Jcxp's blog

广东红帽杯re部分writeup

Word count: 969Reading time: 4 min
2019/11/11 Share

reverse

观察sub_7FF712C21AB0这个函数的实现过程,刘大神说是xtea算法,我对比了一下实现方法,发现有一些差异的地方

从这里看到一个特征,然后百度到了一篇文章

这里面有xxtea的算法,似乎对上了,在调试的时候,发现这个函数的key是取输入的前四个字符,所以大胆猜测是flag
最下面是字符串比较,以及v18v19的算法


提取最终字符串,脚本很容易还原出最初的内容

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
# -*- coding: UTF-8 -*-
from xtea import *
#v20=[0x1a,0x32,0xd4,0xd1,0x38,0x8b,0xe7,0x93,0x16,0x49,0xa8,0xcc,0xc3,0x2,0x47,0x7a,0xcf,0x65,0x68,0xd0,0x7c,0xf3,0xf0,0x8d]
v20=[0xCE,0xBC,0x40,0x6b,0x7c,0x3a,0x95,0xc0,0xef,0x9b,0x20,0x20,0x91,0xf7,0x2,0x35,0x23,0x18,0x2,0xc8,0xe7,0x56,0x56,0xfa]
v19=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

v19[0]=v20[0]
v19[1]=v20[1]
v19[2]=v20[2]

for i in range(24):
if (i/3):
tmp=v20[i]
for j in range(i/3):
tmp^=v20[j]
v19[i]=tmp


v18=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
v18[0] = v19[1]
v18[3] = v19[2]
v18[1] = v19[3]
v18[6] = v19[4]
v18[4] = v19[5]
v18[7] = v19[6]
v18[5] = v19[7]
v18[10] = v19[8]
v18[8] = v19[9]
v18[11] = v19[10]
v18[9] = v19[11]
v18[14] = v19[12]
v18[12] = v19[13]
v18[15] = v19[14]
v18[13] = v19[15]
v18[18] = v19[16]
v18[16] = v19[17]
v18[19] = v19[18]
v18[17] = v19[19]
v18[22] = v19[20]
v18[20] = v19[21]
v18[23] = v19[22]
v18[21] = v19[23]
v18[2] =v19[0]

print v[18]

然后使用xxtea解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: UTF-8 -*-
import xxtea
import binascii
text = binascii.a2b_hex('bca5ce40f4b2b2e7a9129d12ae10c85b3dd7061ddc70f8dc')
print text
key = "flag"
'''
encrypt_data = xxtea.encrypt(text, key)
print encrypt_data.encode('hex')
decrypt_data = xxtea.decrypt(encrypt_data, key)
print(text == decrypt_data);
'''
decrypt_data = xxtea.decrypt(text, key)
print decrypt_data
#flag{CXX_and_++tea}

easyRE

这道题应该是签到题吧,看到字符串中有很长的一段经过很多次base64编码的一段代码:返回了一个链接:
https://bbs.pediy.com/thread-254172.htm
在这个链接里我们可以看到一种思路

也就是诱导攻击者去认为他觉得正确的地方,这道题比较人性化的地方是,你在算出第一个值的时候,他提示你:

1
Info:The first four chars are `flag`

而且可能流程并不在我们算的地方,那么我们可以看到sub_400D35这个函数中有一些处理

很明显是一个数组的比较,第一个字符和第四个字符,分别和f g进行异或,而这个数组的长度刚好是4,所以稍微偏了一点脑洞

1
2
3
4
5
6
7
8
9
10
11
12
#v5=[0x85,0xaa,0x12,0xf5]

v5=[0x26,0x59,0x41,0x31]

p=[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]
flag=''
for i in range(len(p)):
flag+=chr(p[i]^v5[i%4])


print flag
#flag{Act1ve_Defen5e_Test}

childRE

首先是输入31个字符串

在调试时发现v6正常状态下怎么都不会是62

修改程序流程之后,很容易算出来outputString的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: UTF-8 -*-
from z3 import *

v13216='''1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;'ASDFGHJKL:"ZXCVBNM<>?zxcvbnm,'''
v13368="55565653255552225565565555243466334653663544426565555525555222"
v13432='(_@4620!08!6_0*0442!@186%%0@3=66!!974*3234=&0^3&1@=&0908!6_0*&'

#name = [BitVec('u%d'%i,8) for i in range(62)]

#s=Solver()
flag=''
for i in range(62):
b=v13216.index(v13432[i])
c=v13216.index(v13368[i])
flag+=(chr(c*23+b))

print flag

竟然返回了这样一个字符串

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

某大神提示是C++的修饰名,遂百度了一下C++的修饰名规则

这里直接在vs新建一个工程

写入如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// b.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"



class R0Pxx{
private : char * __thiscall My_Aut0_PWN(unsigned char * a)
{return (char *)a;}
public : void test()
{
unsigned char * a;
this->My_Aut0_PWN(a);
}
};

int _tmain(int argc, _TCHAR* argv[])
{
R0Pxx a = R0Pxx();
a.test();
return 0;
}

然后编译后,使用ida打开,成功获得了一个修饰名

flag为?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z的md5值

calc

Snake

CATALOG
  1. 1. reverse
  2. 2. easyRE
  3. 3. childRE
  4. 4. calc
  5. 5. Snake