buuctf reverse CrackRTF
emmmmm,很长时间没有更新过了,今天更一篇。
IDA打开,进入main函数,分析代码
1 int main_0() 2 { 3 DWORD v0; // eax 4 DWORD v1; // eax 5 char String; // [esp+4Ch] [ebp-310h] 6 int v4; // [esp+150h] [ebp-20Ch] 7 char String1; // [esp+154h] [ebp-208h] 8 BYTE pbData; // [esp+258h] [ebp-104h] 9 10 memset(&pbData, 0, 260u); // 将&pbData的前260长度设置为0 11 memset(&String1, 0, 260u); // 将&String1的前260长度设置为0 12 v4 = 0; 13 printf("pls input the first passwd(1): "); 14 scanf("%s", &pbData); // 将输入的字符串传递给pbData 15 if ( strlen(&pbData) != 6 ) // pbData的长度要等于6 16 { 17 printf("Must be 6 characters!\n"); // 如果pbData的长度不为6则错误 18 ExitProcess(0); 19 } 20 v4 = atoi(&pbData); // 将pbData转换成整数然后给v4 21 if ( v4 < 100000 ) // v4要大于等于100000 22 ExitProcess(0); 23 strcat(&pbData, "@DBApp"); // 把"@DBApp"拼接到pbData后 24 v0 = strlen(&pbData); // v0等于pbData的长度 25 sub_40100A(&pbData, v0, &String1); 26 if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )// 不比较大小写,判断string1是否等于…… 27 { 28 printf("continue...\n\n"); 29 printf("pls input the first passwd(2): "); 30 memset(&String, 0, 260u); 31 scanf("%s", &String); // 输入字符串到string地址 32 if ( strlen(&String) != 6 ) // 输入的字符串长度要为6 33 { 34 printf("Must be 6 characters!\n"); 35 ExitProcess(0); 36 } 37 strcat(&String, &pbData); // 将pbData处存储的内容拼接到String后 38 memset(&String1, 0, 0x104u); // 给string1清零 39 v1 = strlen(&String); // 让v1等于string的长度 40 sub_401019(&String, v1, &String1); // 与sub_40100A函数作用相同 41 if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )// string1处存储的内容要相等 42 { 43 if ( !sub_40100F(&String) ) 44 { 45 printf("Error!!\n"); 46 ExitProcess(0); 47 } 48 printf("bye ~~\n"); 49 } 50 } 51 return 0; 52 }
可以看到,需要我们输入两次密码,而且每次输入密码都必须是6位数
否则退出,并且有两次判断~~
先看第一次,第一次要求我们输入6位数,然后连接上@DBApp,
通过一个sub_40100A函数进行加密,然后与6E32D0943418C2C33385BC35A1470250DD8923A9
进行匹配
如果一样则继续往下走~~,否则退出~
进入sub_40100A函数
这利用到了一个windows加密的加密库函数~
一般第二个参数是加密的方式,但是这里看上去不是很明显,,,,
不过还是可以猜一下的,,,,,
经过发现6E32D0943418C2C33385BC35A1470250DD8923A9
是40位的加密后的字符串
很有可能是shal加密,先来爆破试一试~
1 import hashlib 2 3 flag = "@DBApp" 4 5 for i in range(100000,999999): 6 s = str(i)+flag 7 x = hashlib.sha1(s.encode()) 8 cnt = x.hexdigest() 9 if "6e32d0943418c2c" in cnt: 10 print(cnt) 11 print(str(i)+flag)
密码为123321@DBApp
运行exe,输入检查正确~
接下来走第二次输入~
第二次输入同理,不过他把123321@DBApp加在了第二次密码的后面,并且进行加密~
返回main函数
由于第二次输入的六位字符串不知道是啥,不能爆破
if里面还有一个函数~
进入到这个比较中的sub_40100F函数看看
看到内容如下,应该是从一个AAA的东西里面取出数据,
然后将从AAA中取出的数据和我们传入的参数——也就是输入的第二次密码连接后的字符串
传入一个sub_401005函数
最后生成一个dbapp.rtf文件,看到这想起了题目的RTF~
这个函数应该有东西~
进入sub_401005函数查看一下,
就是将我们从AAA取出的值和第二次密码连接后的字符串进行异或嘛:
从大佬的博客中知道用ResourceHacker获取AAA中的值
与密码异或,密码长度是6,所以读取的长度是6 05 7D 41 15 26 01
异或的结果保存到dbapp.rtf中,所以要读取他里面的内容,并与前六位异或,就可以得到原先的值
.rtf开头都是{\rtf1\ansi
取前六位……写脚本进行异或
1 s = "{\\rtf1" 2 3 a = [0x05,0x7D,0x41,0x15,0x26,0x01] 4 5 flag = "" 6 for i in range(0,len(s)): 7 x = ord(s[i]) ^ a[i] 8 flag += chr(x) 9 print(flag)
得到第二次密码:~!3a@0
最后在本地查找dbapp.rtf文件,最后得到flag~
flag:flag{N0_M0re_Free_Bugs}