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}

 

posted @ 2020-11-10 21:14  Sk2rw  阅读(147)  评论(0编辑  收藏  举报