目录
119_[CFI-CTF 2018]Automated Reversing
117_[XMAN2018排位赛]Dragon Quest
用IDA打开后发现main先输入再调用start_quest然后就进行比较
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
std::operator<<<std::char_traits<char>>(
&std::cout,
(unsigned int)"Enter the dragon's secret: ",
"Enter the dragon's secret: ");
fgets(s, 257, stdin);
std::allocator<char>::allocator(v8);
std::string::string(v9, s, v8);
std::allocator<char>::~allocator(v8);
std::string::string((std::string *)v7, (const std::string *)v9);
started = start_quest((std::string *)v7);
std::string::~string((std::string *)v7);
if ( started == 4919 )
{
std::string::string((std::string *)v6, (const std::string *)v9);
reward_strength(v6);
std::string::~string((std::string *)v6);
}
...
}
在start_duest中有一大堆数据
__int64 __fastcall start_quest(std::string *a1)
{
......
v10 = a1;
if ( y26 >= 10 && ((((_BYTE)x25 - 1) * (_BYTE)x25) & 1) != 0 ) #恒为0无条件不跳转
goto LABEL_13;
while ( 1 )
{
v9 = &v2[-2];
v8 = &v2[-2];
v7 = (int *)&v2[-2];
v6 = (std::string *)&v2[-2];
std::vector<int>::push_back(&hero, &secret_100); //数据
std::vector<int>::push_back(&hero, &secret_214);
std::vector<int>::push_back(&hero, &secret_266);
std::vector<int>::push_back(&hero, &secret_369);
......
很明显这跟flag有关,先看数据
.data:000000000061013C 64 secret_100 db 64h ; d ; DATA XREF: start_quest(std::string)+5E↑o
.data:000000000061013C ; start_quest(std::string)+8CD↑o
.data:000000000061013D 00 db 0
.data:000000000061013E 00 db 0
.data:000000000061013F 00 db 0
.data:0000000000610140 public secret_214
.data:0000000000610140 D6 secret_214 db 0D6h ; DATA XREF: start_quest(std::string)+AF↑o
.data:0000000000610140 ; start_quest(std::string)+8E6↑o
.data:0000000000610141 00 db 0
.data:0000000000610142 00 db 0
.data:0000000000610143 00 db 0
.data:0000000000610144 public secret_266
.data:0000000000610144 0A secret_266 db 0Ah ; DATA XREF: start_quest(std::string)+C8↑o
.data:0000000000610144 ; start_quest(std::string)+8FF↑o
.data:0000000000610145 01 db 1
.data:0000000000610146 00 db 0
.data:0000000000610147 00 db 0
.data:0000000000610148 public secret_369
.data:0000000000610148 71 secret_369 db 71h ; q ; DATA XREF: start_quest(std::string)+E1↑o
.data:0000000000610148 ; start_quest(std::string)+918↑o
.data:0000000000610149 01 db 1
.data:000000000061014A 00 db 0
.data:000000000061014B 00 db 0
.data:000000000061014C public secret_417
.data:000000000061014C A1 secret_417 db 0A1h ; DATA XREF: start_quest(std::string)+FA↑o
.data:000000000061014C ; start_quest(std::string)+931↑o
.data:000000000061014D 01 db 1
.data:000000000061014E 00 db 0
.data:000000000061014F 00 db 0
.data:0000000000610150 public secret_527
.data:0000000000610150 0F secret_527 db 0Fh ; DATA XREF: start_quest(std::string)+113↑o
.data:0000000000610150 ; start_quest(std::string)+94A↑o
.data:0000000000610151 02 db 2
.data:0000000000610152 00 db 0
.data:0000000000610153 00 db 0
这些数据是64,d6,10a,171明显超过ascii的范围,并且是递增的,后边的算法也看不明白,试试后边减前边得到64,114,52这些都能转成ascii码,试着转一下
a = [0,100,214,266,369,417,527,622,733,847,942,1054,1106,1222,1336,1441,1540,1589,1686,1796,1891,1996,2112,2165,2260,2336,2412,2498,2575]
print(bytes([a[i]- a[i-1] for i in range(1, len(a))]))
#dr4g0n_or_p4tric1an_it5_LLVM
#flag{dr4g0n_or_p4tric1an_it5_LLVM}
确实得到的就是flag,有一定懵的成分。
118_[De1CTF2019]cplusplus
这个整不出来,看了下WP也不大明白,对照代码一点点注释。
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
sub_140004DD0(std::cin, v52); // 读入
v4 = v52;
if ( v54 >= 0x10 )
v4 = (void **)v52[0];
v5 = (void **)((char *)v4 + v53);
v20[0] = 9024;
*(_QWORD *)v23 = &v22;
v23[8] = byte_14000C7D7;
v31 = *(__m128d *)v23;
v32 = &unk_14000C7ED;
v33 = &v31;
*(_QWORD *)v23 = (char *)&v21 + 2;
v34 = *(__m128d *)v23;
v29[0] = (__int64)&unk_14000C7ED;
v29[1] = (__int64)&v34;
*(_QWORD *)v23 = &v21;
v23[8] = byte_14000C7D7;
v27[0] = (__int64)&unk_14000C7ED;
v27[1] = (__int64)&v35;
v28[0] = (__int64)v27;
v28[1] = (__int64)v20;
v30[0] = (__int64)v28;
v30[1] = (__int64)v29;
v36 = v30;
v37 = (__int64)v20 + 1;
v48 = (__int64)v4 + v53;
*((_QWORD *)&v24 + 1) = *(_QWORD *)&v31.m128d_f64[0];
*(__m128d *)&v46[8] = v34;
*(_OWORD *)&v23[8] = *(_OWORD *)v23;
v35 = *(__m128d *)&v23[8];
v38 = *(_OWORD *)v23; // 数据结构 d1 @ d2 # d3
v39 = *(_OWORD *)&_mm_unpackhi_pd(v35, v35);
v40 = '@';
v41 = *(_OWORD *)v46;
v42 = *(_OWORD *)&_mm_unpackhi_pd(v34, v34);
v43 = '#';
v44 = v24;
v45 = *(_OWORD *)&_mm_unpackhi_pd(v31, v31);
v47 = v4;
*(_QWORD *)&v24 = &v47;
*((_QWORD *)&v24 + 1) = &v48;
v25 = &unk_14000C808;
v26 = &unk_14000C808;
*(_QWORD *)v23 = &v38;
if ( sub_140005910((__int64 *)v23, (__int64)&v21, (__int64 **)&v24) || v47 != v5 )// 判断结构 d1@d2#d3
_exit(0);
LODWORD(v47) = v21;
WORD2(v47) = v22;
sub_1400029B0(&v47); // d1 = 78
sub_1400046A0(Block);
if ( v50 != 5 )
goto LABEL_40;
v6 = time64(0i64);
if ( v6 - v3 > 3 )
goto LABEL_40;
v7 = Block;
if ( v51 >= 0x10 )
v7 = (void **)Block[0];
if ( aEqdtw91a0qwryu[*(char *)v7 - 48] != 68 )// d2 = 20637
goto LABEL_39;
v8 = Block;
if ( v51 >= 0x10 )
v8 = (void **)Block[0];
if ( aEqdtw91a0qwryu[*((char *)v8 + 1) - 48] != 101 )
goto LABEL_39;
v9 = Block;
if ( v51 >= 0x10 )
v9 = (void **)Block[0];
if ( aEqdtw91a0qwryu[*((char *)v9 + 2) - 48] != 49 )
goto LABEL_39;
v10 = Block;
if ( v51 >= 0x10 )
v10 = (void **)Block[0];
if ( aEqdtw91a0qwryu[*((char *)v10 + 3) - 48] != 116 )
goto LABEL_39;
v11 = Block;
if ( v51 >= 0x10 )
v11 = (void **)Block[0];
if ( aEqdtw91a0qwryu[*((char *)v11 + 4) - 48] != 97 )
{
LABEL_39:
Sleep(5u);
_exit(0);
}
if ( (int)(time64(0i64) - v6) > 2 )
LABEL_40:
_exit(0);
if ( WORD2(v47) % (unsigned int)(unsigned __int16)v47 != 12 && WORD2(v47) / (unsigned int)(unsigned __int16)v47 != 3 )// v47[1] = v47[0]*3+12 d3=114
{
sub_1400041F0(std::cout, "You failed...again");
_exit(0);
}
v12 = sub_1400041F0(std::cout, "Your flag is:");
std::ostream::operator<<(v12, sub_1400043C0);
v13 = sub_1400041F0(std::cout, "de1ctf{");
v14 = v52;
if ( v54 >= 0x10 )
v14 = (void **)v52[0];
v15 = sub_140004FC0(v13, v14, v53);
v16 = sub_1400041F0(v15, "}");
std::ostream::operator<<(v16, sub_1400043C0);
if ( v51 >= 0x10 )
{
v17 = Block[0];
if ( v51 + 1 >= 0x1000 )
{
v17 = (void *)*((_QWORD *)Block[0] - 1);
if ( (unsigned __int64)(Block[0] - v17 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(v17);
}
v50 = 0i64;
v51 = 15i64;
LOBYTE(Block[0]) = 0;
if ( v54 >= 0x10 )
{
v18 = v52[0];
if ( v54 + 1 >= 0x1000 )
{
v18 = (void *)*((_QWORD *)v52[0] - 1);
if ( (unsigned __int64)(v52[0] - v18 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(v18);
}
return 0;
}
在输入后,找两个定位符@#然后逐个段时判断,d2容易点一比较就行,其它两个都是动调,没啥好想的,运行到那就出现了。结果就是这样
#123@456#789
#d1 = 78
#d2 = 20637
#d3 = 114
#flag{78@20637#114}
119_[CFI-CTF 2018]Automated Reversing
附件里有970个小文件,还随机送了生成程序和解密程序solution.py 当时一楞,还给了解密程序。直接运行不就得了。不过可能那是python2写的,我这3有点小问题,于是小小改动一点。输出一大堆东西,在里边就有flag
到了1分以后难的是真难,但也有不少简单的一塌糊涂
flag = b''
for i in range(970):
path = "binaries/binary{}".format(i)
with open(path, "rb") as f:
binary = f.read()
operator = binary[0xca]
key = binary[0xcb]
check = binary[0xce]
if operator == 0xc2: # add
flag += bytes([(0x100+ check - key) & 0xff])
elif operator == 0xea: # sub
flag += bytes([(check + key) & 0xff])
else:
flag += bytes([check ^ key])
print(flag)
#改python3 chr改为bytes
#flag{1s_th1s_4_pr0g_ch4ll_0r_4_r3ve3se_ch4ll?}
'''
b'\nLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula dolor. Aenean massa. Cum sociis nato
que penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu,
pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tin
cidunt. Cras dapibus. The flag is CFI{1s_th1s_4_pr0g_ch4ll_0r_4_r3ve3se_ch4ll?}. Aenean vulputate eleifend tellus. Aenea
n leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. I stole this idea directly from Defcon Quals 2016. Phase
llus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur
ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semp
er libero, si'
'''
120_[RCTF2019]babyre1
这个题实在作不出来,就看了WP,发现原题有个提示就是给了md5值,呵呵。
hint md5('rctf{'+input+'}').digest.hex() == '5f8243a662cf71bf31d2b2602638dc1d'
题目在main里进行了几个操作
__int64 __fastcall main(int a1, char **a2, char **a3)
{
...
memset(v11, 0, 0x100uLL);
__printf_chk(1LL, "Input right flag you can got 'Bingo!' :");
__isoc99_scanf("%31s", v11);
v3 = &v11[strlen(v11)];
if ( (unsigned __int64)(v3 - v11) > 0x10 )
{
puts("input is too long!");
}
else if ( v3 - v11 == 16 )
{
v4 = sub_C00((unsigned __int64)v11, 16, (char **)&ptr);// 16进制转数字
if ( v4
&& (v5 = sub_1180(ptr, v4, (__int64)&unk_202010, 16, &v9), (v6 = v5) != 0LL)// tea
&& v9 > 0
&& (unsigned __int16)((__int64 (__fastcall *)(char *))sub_13D0)(v5) == 27106 )// crc校验
{
for ( i = 0LL; v9 > (int)i; ++i )
v6[i] ^= 0x17u;
puts(v6);
if ( ptr )
free(ptr);
free(v6);
}
else
{
puts("input flag is wrong!");
}
}
else
{
puts("input is too short!");
}
return 0LL;
}
一开始就是说会输出Bingo,然后是16进制转换和tea加密(用findcrypt能搜出一堆来,看上去是标准加密)
然后是个自制的crc校验,其实这里一直也没逆出来,也就不逆了,从前边两项和md5值入手就行了。
tea解密后与0x17异或是Bingo但还少2字符,也就是这个需要爆破,tea的key在202010已经给出。
也就是将Bingo爆破两位与0x17异或后用tea加密,再求md5进行比较
#hint md5('rctf{'+input+'}').digest.hex() == '5f8243a662cf71bf31d2b2602638dc1d' buu未给出
import xxtea
import hashlib
key = [0xc7,0xe0,0xc7,0xe0,0xd7,0xd3,0xf1,0xc6,0xd3,0xc6,0xd3,0xc6,0xce,0xd2,0xd0,0xc4]
text = [v^0x17 for v in b'Bingo!\0\0']
for i in range(0x100):
for j in range(0x100):
text[6] = i
text[7] = j
c = xxtea.encrypt(bytes(text), bytes(key), padding=False ).hex()
flag = 'rctf{'+c+'}'
#print(flag)
if hashlib.md5(flag.encode()).digest().hex() == '5f8243a662cf71bf31d2b2602638dc1d':
print('OK:',flag)
exit()
#rctf{05e8a376e4e0446e}
#flag{05e8a376e4e0446e}