2019RedHat部分Reverse writeup

周末打了一下红帽杯,Reverse比较简单,解了XX、easyRE以及childRE,简略写了 下writeup

XX

程序首先校验前四个字符是否在”qwertyuiopasdfghjklzxcvbnm1234567890”这个字符集

1
v17 = xxtea((__int64)Code, v3, (unsigned __int8 *)&v30, &Size);

之后进行xxtea加密,密钥为前四个字符,明文为输入的19个字符+0x00000013,密文为6*32bits,24个字符

接下来是一个一一映射的关系,改变密文顺序,最后是一个比较简单的异或算法,结果与常量进行比较

1
2
3
4
5
6
*(_QWORD *)&v30 = 0xC0953A7C6B40BCCEi64;
v25 = v20 - (_BYTE *)&v30;
*((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
v26 = 0i64;
v31 = 0xC8021823;
v32 = 0xFA5656E7;

直接还原出xxtea密文,爆破密钥,复杂度为36**4

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <stdbool.h>
#include <stdio.h>
#define MX \
((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))
bool btea(unsigned int* v, int n, unsigned int* k) {
unsigned int z = v[n - 1], y = v[0], sum = 0, e, DELTA = 0x9e3779b9;
unsigned int p, q;
if (n > 1) {
return 0;
} else if (n < -1) {
n = -n;
q = 6 + 52 / n;
sum = q * DELTA;
while (sum != 0) {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
z = v[p - 1], y = v[p] -= MX;
z = v[n - 1];
y = v[0] -= MX;
sum -= DELTA;
}
return 0;
}
return 1;
}

int main(int argc, char const* argv[]) {
__uint8_t res[24] = {0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0,
0xEF, 0x9B, 0x20, 0x20, 0x91, 0xF7, 0x02, 0x35,
0x23, 0x18, 0x02, 0xC8, 0xE7, 0x56, 0x56, 0xFA};

for (size_t i = 23; i > 0; i--) {
for (size_t j = 0; j < i / 3; j++) {
res[i] ^= res[j];
}
}
for (size_t i = 0; i < 24; i++) {
printf("%x ", res[i]);
}

__uint8_t bteares[24] = {0};
bteares[2] = *res;
*bteares = res[1];
bteares[3] = res[2];
bteares[1] = res[3];
bteares[6] = res[4];
bteares[4] = res[5];
bteares[7] = res[6];
bteares[5] = res[7];
bteares[10] = res[8];
bteares[8] = res[9];
bteares[11] = res[10];
bteares[9] = res[11];
bteares[14] = res[12];
bteares[12] = res[13];
bteares[15] = res[14];
bteares[13] = res[15];
bteares[18] = res[16];
bteares[16] = res[17];
bteares[19] = res[18];
bteares[17] = res[19];
bteares[22] = res[20];
bteares[20] = res[21];
bteares[23] = res[22];
bteares[21] = res[23];
__uint32_t vres[6] = {0};
__uint32_t tmp[6] = {0};
for (size_t i = 0; i < 24; i += 4) {
vres[i / 4] = bteares[i] + (((__uint32_t)bteares[i + 1]) << 8) +
(((__uint32_t)bteares[i + 2]) << 16) +
(((__uint32_t)bteares[i + 3]) << 24);
tmp[i / 4] = vres[i / 4];
}
int index = 0;
unsigned int key[4] = {0, 0, 0, 0};
__uint8_t vvv[36] = {0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6f,
0x70, 0x61, 0x73, 0x64, 0x66, 0x67, 0x68, 0x6a, 0x6b,
0x6c, 0x7a, 0x78, 0x63, 0x76, 0x62, 0x6e, 0x6d, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30};
for (size_t i = 0; i < 36; i++) {
for (size_t j = 0; j < 36; j++) {
for (size_t k = 0; k < 36; k++) {
for (size_t z = 0; z < 36; z++) {
key[0] = vvv[i] + (((__uint32_t)vvv[j]) << 8) +
(((__uint32_t)vvv[k]) << 16) + (((__uint32_t)vvv[z]) << 24);
for (size_t ii = 0; ii < 6; ii++) {
vres[ii] = tmp[ii];
}
btea(vres, -6, key);
if (vres[0] == key[0]) {
puts("");
printf("%x%x", vres[0], vres[1]);
printf("%x%x", vres[2], vres[3]);
printf("%x%x\n", vres[4], vres[5]);
for (size_t ii = 0; ii < 6; ii++) {
for (size_t jj = 0; jj < 4; jj++) {
printf("%c", ((vres[ii] >> (jj * 8)) & 0xff));
}
}
}
}
}
}
}
return 0;
}

flag{CXX_and_++tea}

easyRE

main函数解出了一个提示还有彩蛋

1
2
3
4
5
6
7
8
9
10
11
➜  hmb ./easyRE

Info:The first four chars are `flag`

continue!

https://bbs.pediy.com/thread-254172.htm

You found me!!!

bye bye~

根据提示最后发现了

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
unsigned __int64 sub_400D35()
{
unsigned __int64 result; // rax
unsigned int v1; // [rsp+Ch] [rbp-24h]
int i; // [rsp+10h] [rbp-20h]
int j; // [rsp+14h] [rbp-1Ch]
unsigned int v4; // [rsp+24h] [rbp-Ch]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]

v5 = __readfsqword(0x28u);
v1 = sub_43FD20(0LL) - qword_6CEE38;
for ( i = 0; i <= 1233; ++i )
{
sub_40F790(v1);
sub_40FE60();
sub_40FE60();
v1 = (unsigned __int64)sub_40FE60() ^ 0x98765432;
}
v4 = v1;
if ( ((unsigned __int8)v1 ^ byte_6CC0A0[0]) == 102 && (HIBYTE(v4) ^ (unsigned __int8)byte_6CC0A3) == 103 )
{
for ( j = 0; j <= 24; ++j )
sub_410E90((unsigned __int8)(byte_6CC0A0[j] ^ *((_BYTE *)&v4 + j % 4)));
}
result = __readfsqword(0x28u) ^ v5;
if ( result )
sub_444020();
return result;
}

尝试解一下

1
2
3
4
5
6
byte_6CC0A0 = [0x40,0x35,0x20,0x56,0x5d,0x18,0x22,0x45,0x17,0x2f,0x24,0x6e,0x62,0x3c,0x27,0x54,0x48,0x6c,0x24,0x6e,0x72,0x3c,0x32,0x45,0x5b]
v4 = [byte_6CC0A0[0]^ord('f'),byte_6CC0A0[1]^ord('l'),byte_6CC0A0[2]^ord('a'),byte_6CC0A0[3]^ord('g')]
flag = ''
for i in range(len(byte_6CC0A0)):
flag+=chr(byte_6CC0A0[i] ^v4[i%4])
print (flag)

flag{Act1ve_Defen5e_Test}

childRE

前面是一个一一映射关系,改变输入字符串顺序,先不管

之后对输入字符串反修饰C++ 符号名

1
UnDecorateSymbolName(v5, outputString, 0x100u, 0);

限定输入长度为31,输出长度为62,之后是一个简单的比较算法

1
2
3
4
5
6
7
8
9
10
11
12
do
{
v14 = outputString[v13];
v15 = v14 % 23;
if ( a1234567890Qwer[v15] != *(_BYTE *)(v13 + 5368722552i64) )
_exit(v12);
if ( a1234567890Qwer[v14 / 23] != *(_BYTE *)(v13 + 5368722488i64) )
_exit(v12 * v12);
++v12;
++v13;
}
while ( v12 < 0x3E );

先还原出c++函数名

1
2
3
4
5
6
7
8
9
src ='1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;\x27ASDFGHJKL:"ZXCVBNM<>?zxcvbnm,./'
s1= '55565653255552225565565555243466334653663544426565555525555222'
s2='(_@4620!08!6_0*0442!@186%%0@3=66!!974*3234=&0^3&1@=&0908!6_0*&'
l = []
for i in range(62):
a = src.find(s1[i])
b = src.find(s2[i])
l.append(a*23+b)
print(''.join(map(chr,l)))

得到原函数名

private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)

根据c++规范手撸修饰后的符号,得到

?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z

前面说过有一个一一映射的关系,懒得逆了,输入

1234567890abcdefghijklmnopqrstu

得到输出

fg8hi94jk0lma52nobpqc6rsdtue731

直接将结果映射回去得到真正的输入,md5得到flag

1
2
3
4
5
6
7
8
9
10
s1 = 'fg8hi94jk0lma52nobpqc6rsdtue731'
s2 = '1234567890abcdefghijklmnopqrstu'
res = '?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'

l = ['0' for _ in range(31)]
for i in range(31):
a = s1[i]
l[s2.find(a)] = res[i]
input = ''.join(l)
print("flag{%s}"%md5(input).hexdigest())

flag{63b148e750fed3a33419168ac58083f5}

Calc

这道题是赛后才搞出来的,cpp、stl太恶心(还是太菜了

主要都是动态调试调出来的,程序逻辑大概就是输入三个整数然后计算

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
v24 = (char *)x[0];
v25 = (x[1] - x[0]) >> 2;
v26 = z[0];
v27 = (z[1] - z[0]) >> 2;
v28 = (char *)y[0];
if ( v25 == v27 )
{
v30 = v25 - 1;
if ( (int)v25 - 1 < 0 )
goto LABEL_47;
v31 = v30;
v32 = (char *)z[0] + 4 * v30;
while ( *(_DWORD *)((char *)v32 + x[0] - z[0]) == *v32 )
{
--v30;
--v32;
if ( --v31 < 0 )
goto LABEL_47;
}
v29 = *((_DWORD *)x[0] + v30) < *((_DWORD *)z[0] + v30);
}
else
{
v29 = v25 < v27;
}
if ( !v29 )
goto LABEL_47;
v35 = (y[1] - y[0]) >> 2;
if ( v35 != v25 )
{
v36 = v35 < v25;
goto LABEL_62;
}
v37 = v35 - 1;
if ( (int)v35 - 1 < 0 )
{
LABEL_47:
v33 = -1;
goto LABEL_48;
}
v38 = v37;
v39 = (char *)x[0] + 4 * v37;
while ( *(_DWORD *)((char *)v39 + y[0] - x[0]) == *v39 )
{
--v37;
--v39;
if ( --v38 < 0 )
goto LABEL_47;
}
v36 = *((_DWORD *)y[0] + v37) < *((_DWORD *)x[0] + v37);

上面这一段是校验 输入的三个整数 x、y、z 中 x<z && y<x

接下来就是 加、减、乘、幂运算了,连蒙带猜理清了一些逻辑关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v40 = mul(&v146, v135, x);                    // v40 = 3*x
v41 = mul(&v143, v40, x); // v41 = 3*x*x
v42 = mul(&v140, v41, y); // v42 = 3*x*x*y
v43 = pow(&v137, y, v133); // v43 = y*y
v44 = mul(&v161, v131, x); // v44 = 3*x
v45 = mul(&v150, v44, v43); // v45 = 3*x*y*y
………………
v54 = add(Memory, v124, y); // v54 = x+y
v55 = pow(&v149, v54, v129); // v55 = (x+y)**3
v154 = v55;
v56 = mov(&v163, v45);
v57 = sub(v55, v56); // v57 = (x+y)**3 - 3*x*y*y
………………
v60 = sub(v122, v59); // v60 = (x+y)**3 - 3*x*y*y - 3*x*x*y

这一部分计算了 (x+y)*3 - 3xyy - 3xx*y

下面还有一部分计算了 (z+4)3 - 12*(z2) - z*48 - 22

最终校验两部分是否相等

化简可以得到一个丢番图方程

x3+y3-z**3 == 42

参考https://en.wikipedia.org/wiki/Sums_of_three_cubes

得到结果

1
2
3
x == 80435758145817515
y == 12602123297335631
z == 80538738812075974

flag{MD5(“804357581458175151260212329733563180538738812075974”).tolower()}

get flag flag{951e27be2b2f10b7fa22a6dc8f4682bd}

0%