LitCTF复现

世界上最棒的程序员

直接扔进ida,F5反编译后直接看到flag

ez_XOR

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  strcpy(Str2, "E`}J]OrQF[V8zV:hzpV}fVF[t");
v9 = 0;
v10 = 0;
v11 = 0;
v12 = 0;
v13 = 0;
v14 = 0;
v15 = 0;
printf("Enter The Right FLAG:");
scanf("%s", Str1);
XOR(Str1, 3);
if ( !strcmp(Str1, Str2) )
{
printf("U Saved IT!\n");
return 0;
}
else
{
printf("Wrong!Try again!\n");
return main(v4, v5, v6);
}
}

XOR:

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
size_t __cdecl XOR(char *Str, char a2)
{
size_t result; // eax
unsigned int i; // [esp+2Ch] [ebp-Ch]

for ( i = 0; ; ++i )
{
result = strlen(Str);
if ( i >= result )
break;
Str[i] ^= 3 * a2;
}
return result;
}

很简单的异或操作,直接把str2亦或9即可

enbase64

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Source[61]; // [esp+1Fh] [ebp-81Dh] BYREF
char v5[4]; // [esp+5Ch] [ebp-7E0h] BYREF
char Str1[1000]; // [esp+60h] [ebp-7DCh] BYREF
char Str[1012]; // [esp+448h] [ebp-3F4h] BYREF

__main();
memset(Str, 0, 1000);
memset(Str1, 0, sizeof(Str1));
*(_DWORD *)Source = *(_DWORD *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
strcpy(v5, "9+/");
qmemcpy(&Source[1], &aAbcdefghijklmn[-(Source - &Source[1])], 4 * (((Source - &Source[1] + 65) & 0xFFFFFFFC) >> 2));
puts("Please input flag:");
gets(Str);
if ( strlen(Str) == 33 )
{
base64(Source, Str, Str1);
basecheck(Str1);
}
return 0;
}

进入base64

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
signed int __cdecl base64(char *Source, char *Str, char *a3)
{
signed int result; // eax
signed int v4; // [esp+14h] [ebp-14h]
signed int i; // [esp+18h] [ebp-10h]
int v6; // [esp+1Ch] [ebp-Ch]

basechange(Source);
v4 = strlen(Str);
v6 = 0;
for ( i = 0; ; i += 3 )
{
result = i;
if ( i >= v4 )
break;
a3[v6] = Source[Str[i] >> 2];
a3[v6 + 1] = Source[(16 * Str[i]) & 0x30 | (Str[i + 1] >> 4)];
a3[v6 + 2] = Source[(4 * Str[i + 1]) & 0x3C | (Str[i + 2] >> 6)];
a3[v6 + 3] = Source[Str[i + 2] & 0x3F];
v6 += 4;
}
return result;
}

basechange函数是要换表,根据换表步骤换表即可,但是这里我用python写出来的代码换表不成功,c语言就行

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <string.h>
void basechange(char* table)
{
char* result; // eax
char des[65]; // [esp+13h] [ebp-155h] BYREF
int key[65]; // [esp+54h] [ebp-114h] BYREF
int j; // [esp+158h] [ebp-10h]
int i; // [esp+15Ch] [ebp-Ch]

memset(key, 0, sizeof(key));
key[0] = 16;
key[1] = 34;
key[2] = 56;
key[3] = 7;
key[4] = 46;
key[5] = 2;
key[6] = 10;
key[7] = 44;
key[8] = 20;
key[9] = 41;
key[10] = 59;
key[11] = 31;
key[12] = 51;
key[13] = 60;
key[14] = 61;
key[15] = 26;
key[16] = 5;
key[17] = 40;
key[18] = 21;
key[19] = 38;
key[20] = 4;
key[21] = 54;
key[22] = 52;
key[23] = 47;
key[24] = 3;
key[25] = 11;
key[26] = 58;
key[27] = 48;
key[28] = 32;
key[29] = 15;
key[30] = 49;
key[31] = 14;
key[32] = 37;
key[34] = 55;
key[35] = 53;
key[36] = 24;
key[37] = 35;
key[38] = 18;
key[39] = 25;
key[40] = 33;
key[41] = 43;
key[42] = 50;
key[43] = 39;
key[44] = 12;
key[45] = 19;
key[46] = 13;
key[47] = 42;
key[48] = 9;
key[49] = 17;
key[50] = 28;
key[51] = 30;
key[52] = 23;
key[53] = 36;
key[54] = 1;
key[55] = 22;
key[56] = 57;
key[57] = 63;
key[58] = 8;
key[59] = 27;
key[60] = 6;
key[61] = 62;
key[62] = 45;
key[63] = 29;
strcpy(des, table);
for (i = 0; i <= 47; ++i)
{
for (j = 0; j <= 63; ++j)
table[j] = des[key[j]];
strcpy(des, table);
}
}
int main()
{
unsigned char table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
basechange(table);
printf("%s", table);
return 0;
}

换表后,表为:gJ1BRjQie/FIWhEslq7GxbnL26M4+HXUtcpmVTKaydOP38of5v90ZSwrkYzCAuND

直接进入basecheck函数拿到加密的字符串即可解密

snake

pyc文件直接拿去反编,发现缺少magic number,补齐这个文件的magic number,这个文件版本为3.7,magic number为 42 0D 0D 0A,2.7版本:03 F3 0D 0A

3.5和3.6版本:33 0D 0D 0A

补齐之后直接反编

plaintext
1
uncompyle6.exe xxx.pyc > xxx.py

然后直接在代码中找到flag的数据,直接转换为字符即可

For Aiur

先用pyinstxtractor解包

plaintext
1
python pyinstxtractor.py xxx.exe

得到pyc文件,本地的uncomple6没有反编译出,找了个在线网站编译,得到的py文件里唯一有用的信息就是调用了ch包里的check函数,在前面解的包里的PYZ-00.pyz_extracted文件夹中有ch.pyc文件,反编译,

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
enc = [
98, 77, 94, 91, 92, 107, 125, 66, 87, 70, 113, 92, 83, 70, 85, 81,
19, 21, 109, 99, 87, 107, 127, 65, 65, 64, 109, 87, 93, 90, 65,
64, 64, 65, 81, 3, 109, 85, 86, 80, 91, 64, 91, 91, 92, 0, 94,
107, 66, 77, 94, 91, 92, 71]
lis = []

def check(num):
flag = 'LitCTF{'
if num % 2 == 0:
if num % 4 == 0:
if num % 6 == 0:
if num % 8 == 0:
if num % 12 == 0:
if num % 13 == 11:
k = str(num)
for i in range(len(enc)):
flag += chr(ord(k[i % len(k)]) ^ enc[i])
lis.append(ord(k[i % len(k)]) ^ enc[i])
else:
flag += '}'
from cv2 import imread, imshow, namedWindow, WINDOW_NORMAL, FONT_HERSHEY_SIMPLEX, getTickCount, getTickFrequency, putText, LINE_AA, waitKey, getTextSize, resize, moveWindow, IMREAD_UNCHANGED, destroyAllWindows
from numpy import uint8, zeros
img = zeros((200, 20000, 3), uint8)
img.fill(255)
text = flag
font = FONT_HERSHEY_SIMPLEX
pos = (50, 120)
color = (0, 0, 0)
thickness = 2
putText(img, text, pos, font, 1, color, thickness, LINE_AA)
imshow('flag', img)
waitKey(0)
destroyAllWindows()

直接根据代码写脚本即可

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

enc = [
98, 77, 94, 91, 92, 107, 125, 66, 87, 70, 113, 92, 83, 70, 85, 81,
19, 21, 109, 99, 87, 107, 127, 65, 65, 64, 109, 87, 93, 90, 65,
64, 64, 65, 81, 3, 109, 85, 86, 80, 91, 64, 91, 91, 92, 0, 94,
107, 66, 77, 94, 91, 92, 71]
num=0
flag="LitCTF{"
while 1:

if num % 2 == 0:
if num % 4 == 0:
if num % 6 == 0:
if num % 8 == 0:
if num % 12 == 0:
if num % 13 == 11:
k = str(num)
for i in range(len(enc)):
flag += chr(ord(k[i % len(k)]) ^ enc[i])

else:
flag += '}'
break
num=num+1

print(flag)

程序和人能跑一个就行

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v5; // eax
_DWORD *v6; // eax
int v7; // [esp+0h] [ebp-2ACh] BYREF
int v8; // [esp+14h] [ebp-298h]
int *v9; // [esp+18h] [ebp-294h]
int v10; // [esp+1Ch] [ebp-290h] BYREF
int v11; // [esp+20h] [ebp-28Ch]
int (__cdecl *v12)(int, int, int, int, int, int); // [esp+34h] [ebp-278h]
int *v13; // [esp+38h] [ebp-274h]
int *v14; // [esp+3Ch] [ebp-270h]
void *v15; // [esp+40h] [ebp-26Ch]
int *v16; // [esp+44h] [ebp-268h]
char Buf1[27]; // [esp+68h] [ebp-244h] BYREF
char Buf2[256]; // [esp+A0h] [ebp-20Ch] BYREF
char Destination[268]; // [esp+1A0h] [ebp-10Ch] BYREF
int savedregs; // [esp+2ACh] [ebp+0h] BYREF

v9 = &v10;
v12 = sub_4752F0;
v13 = dword_476078;
v14 = &savedregs;
v15 = &loc_475B38;
v16 = &v7;
sub_40A8F0(&v10);
sub_409B80();
v11 = -1;
sub_472810((int)&dword_47DD80, Buf2);
strcpy(Destination, "litctf");
sub_4015A0(Buf2, strlen(Buf2), Destination, 6);
Buf1[0] = -115;
Buf1[1] = 108;
Buf1[2] = -123;
Buf1[3] = 118;
Buf1[4] = 50;
Buf1[5] = 114;
Buf1[6] = -73;
Buf1[7] = 64;
Buf1[8] = -120;
Buf1[9] = 126;
Buf1[10] = -107;
Buf1[11] = -18;
Buf1[12] = -59;
Buf1[13] = -19;
Buf1[14] = 46;
Buf1[15] = 113;
Buf1[16] = 55;
Buf1[17] = -15;
Buf1[18] = 74;
Buf1[19] = -103;
Buf1[20] = 53;
Buf1[21] = 24;
Buf1[22] = -89;
Buf1[23] = -80;
Buf1[24] = 0;
Buf1[25] = -106;
Buf1[26] = -73;
v8 = memcmp(Buf1, Buf2, 0x1Bu);
if ( v8 )
{
v11 = 1;
v5 = sub_471AE0((int)&dword_47DF60, "U are wrong?");
sub_46FBA0(v5);
v6 = (_DWORD *)sub_474310(4);
*v6 = Buf2;
sub_475190(v6, &off_483660, 0);
}
v11 = 1;
v3 = sub_471AE0((int)&dword_47DF60, "U are right?");
sub_46FBA0(v3);
sub_40AA70(v9);
return v8;
}

这是一个RC4加密,这里的Buf1是假的flag,因为无论如何if语句都会执行,去找真的flag的数据,在sub_475190处设下断点,然后运行,F8把这个函数跳过,往后面找,就可以找到真正的flag数据

前面提到了密钥为litctf,直接写出脚本即可

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from Crypto.Cipher import ARC4

val=[0x8D, 0xC6, 0x84,
0x24, 0x84, 0x00, 0x00, 0x00, 0x6C, 0xC6, 0x84, 0x24, 0x85,
0x00, 0x00, 0x00, 0x85, 0xC6, 0x84, 0x24, 0x86, 0x00, 0x00,
0x00, 0x76, 0xC6, 0x84, 0x24, 0x87, 0x00, 0x00, 0x00, 0x32,
0xC6, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84,
0x24, 0x89, 0x00, 0x00, 0x00, 0xB7, 0xC6, 0x84, 0x24, 0x8A,
0x00, 0x00, 0x00, 0x43, 0xC6, 0x84, 0x24, 0x8B, 0x00, 0x00,
0x00, 0x85, 0xC6, 0x84, 0x24, 0x8C, 0x00, 0x00, 0x00, 0x7B,
0xC6, 0x84, 0x24, 0x8D, 0x00, 0x00, 0x00, 0x85, 0xC6, 0x84,
0x24, 0x8E, 0x00, 0x00, 0x00, 0xDE, 0xC6, 0x84, 0x24, 0x8F,
0x00, 0x00, 0x00, 0xC1, 0xC6, 0x84, 0x24, 0x90, 0x00, 0x00,
0x00, 0xFB, 0xC6, 0x84, 0x24, 0x91, 0x00, 0x00, 0x00, 0x2E,
0xC6, 0x84, 0x24, 0x92, 0x00, 0x00, 0x00, 0x64, 0xC6, 0x84,
0x24, 0x93, 0x00, 0x00, 0x00, 0x07, 0xC6, 0x84, 0x24, 0x94,
0x00, 0x00, 0x00, 0xC8, 0xC6, 0x84, 0x24, 0x95, 0x00, 0x00,
0x00, 0x5F, 0xC6, 0x84, 0x24, 0x96, 0x00, 0x00, 0x00, 0x9A,
0xC6, 0x84, 0x24, 0x97, 0x00, 0x00, 0x00, 0x35, 0xC6, 0x84,
0x24, 0x98, 0x00, 0x00, 0x00, 0x18, 0xC6, 0x84, 0x24, 0x99,
0x00, 0x00, 0x00, 0xAD, 0xC6, 0x84, 0x24, 0x9A, 0x00, 0x00,
0x00, 0xB5, 0xC6, 0x84, 0x24, 0x9B, 0x00, 0x00, 0x00, 0x15,
0xC6, 0x84, 0x24, 0x9C, 0x00, 0x00, 0x00, 0x92, 0xC6, 0x84,
0x24, 0x9D, 0x00, 0x00, 0x00, 0xBE, 0xC6, 0x84, 0x24, 0x9E,
0x00, 0x00, 0x00, 0x1B, 0xC6, 0x84, 0x24, 0x9F, 0x00, 0x00,
0x00, 0x88]
vals=[]
for i in range(0,len(val),8):
vals.append(val[i])
vals_b=bytes(vals)
key=b"litctf"
enc=ARC4.new(key)
flag=enc.decrypt(vals_b)
print(flag)

debase64

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[4]; // [esp+10h] [ebp-44h] BYREF
char v5; // [esp+20h] [ebp-34h]
__int16 v6; // [esp+21h] [ebp-33h]
__int16 v7; // [esp+23h] [ebp-31h]
__int16 v8; // [esp+25h] [ebp-2Fh]
__int16 v9; // [esp+27h] [ebp-2Dh]
__int16 v10; // [esp+29h] [ebp-2Bh]
__int16 v11; // [esp+2Bh] [ebp-29h]
__int16 v12; // [esp+2Dh] [ebp-27h]
char v13[20]; // [esp+3Ch] [ebp-18h] BYREF

sub_402290();
puts(&Buffer);
memset(v4, 0, 15);
memset(v13, 0, sizeof(v13));
scanf("%s", v13);
if ( strlen(v13) != 20 )
{
puts(&byte_404053);
return 0;
}
v5 = 70;
v6 = 6381;
v7 = 22166;
v8 = -11618;
v9 = -19854;
v10 = -32589;
v11 = -144;
v12 = 0;
sub_401520(v13, v4);
if ( v5 != LOBYTE(v4[0])
|| v6 != *(_WORD *)((char *)v4 + 1)
|| v7 != *(_WORD *)((char *)v4 + 3)
|| v8 != *(_WORD *)((char *)&v4[1] + 1)
|| v9 != *(_WORD *)((char *)&v4[1] + 3)
|| v10 != *(_WORD *)((char *)&v4[2] + 1)
|| v11 != *(_WORD *)((char *)&v4[2] + 3)
|| v12 != *(_WORD *)((char *)&v4[3] + 1) )
{
puts(&byte_40405E);
return 0;
}
return puts(&byte_404065);
}

进入 sub_401520

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
int __cdecl sub_401520(_BYTE *a1, int a2)
{
_BYTE *v2; // ebp
_BYTE *v3; // ecx
int v4; // ebx
int v5; // eax
int i; // edx
_BYTE *v7; // edx
int j; // ecx
_BYTE *v9; // ecx
int k; // ebx
int v12; // [esp+0h] [ebp-38h]
int v13; // [esp+4h] [ebp-34h]
int v14; // [esp+Ch] [ebp-2Ch]

if ( !*a1 )
return 0;
v2 = a1 + 4;
v3 = a1;
v4 = 0;
v5 = 0;
v13 = 0;
while ( 1 )
{
v14 = -1;
for ( i = 0; i != 64; ++i )
{
while ( byte_404000[i] != *v3 )
{
if ( ++i == 64 )
goto LABEL_7;
}
LOBYTE(v14) = i;
}
LABEL_7:
LOBYTE(i) = 0;
do
{
while ( byte_404000[i] != a1[v4 + 1] )
{
if ( ++i == 64 )
goto LABEL_11;
}
BYTE1(v14) = i++;
}
while ( i != 64 );
LABEL_11:
v7 = &a1[v4 + 2];
for ( j = 0; j != 64; ++j )
{
while ( byte_404000[j] != *v7 )
{
if ( ++j == 64 )
goto LABEL_15;
}
BYTE2(v14) = j;
}
LABEL_15:
v9 = &a1[v4 + 3];
for ( k = 0; k != 64; ++k )
{
while ( byte_404000[k] != *v9 )
{
if ( ++k == 64 )
goto LABEL_19;
}
HIBYTE(v14) = k;
}
LABEL_19:
v12 = v5 + 1;
*(_BYTE *)(a2 + v5) = (4 * HIBYTE(v14)) | (BYTE2(v14) >> 4) & 3;
if ( *v7 == 61 )
return v12;
v12 = v5 + 2;
*(_BYTE *)(a2 + v5 + 1) = (16 * BYTE2(v14)) | (BYTE1(v14) >> 2) & 0xF;
if ( *v9 == 61 )
return v12;
v5 += 3;
v3 = v2;
v2 += 4;
v13 += 4;
v4 = v13;
*(_BYTE *)(a2 + v5 - 1) = (BYTE1(v14) << 6) | v14 & 0x3F;
if ( !*(v2 - 4) )
return v5;
}
}

一个类似base64的算法,将输入的20个字符分为4组每组分别反序做base64运算,这里字符会与v4作比较,直接在sub_401520处设个断点进入就能看到v4的值了

但是拿到的字符会有一位不知道,因为题目给了最后的md5值,直接爆破就好,脚本如下

python
1
2
3
4
5
6
7
8
9
10
11
12
import base64
import hashlib
val=[0x46,0xED,0X18,0X96,0X56,0X9E,0XD2,0X72,0XB2,0XB3,0X80,0X70,0XFF]
val_b=bytes(val)
print(base64.b64encode(val_b))#Ru0Yllae0nKys4Bw/w== --> Y0uReallyKn0wB4s?===

key="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
for i in key:
flag="Y0uReallyKn0wB4s"+i+"==="
if hashlib.md5(flag.encode()).hexdigest()=="5a3ebb487ad0046e52db00570339aace":
print(flag)
break

总结

知道了ARC4加密方式的处理,知道了magic number。