BUUCTF-RE-CrackRTF

一、查壳

二、IDA分析

 1 int __cdecl 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, 0x104u);
11   memset(&String1, 0, 0x104u);
12   v4 = 0;
13   printf("pls input the first passwd(1): ");
14   scanf("%s", &pbData);
15   if ( strlen((const char *)&pbData) != 6 )  //first passwd(1) 6个字符
16   {
17     printf("Must be 6 characters!
");
18     ExitProcess(0);
19   }
20   v4 = atoi((const char *)&pbData);  //atoi()将&pbData转换为一个整数
21   if ( v4 < 100000 )   //first passwd大于100000
22     ExitProcess(0);
23   strcat((char *)&pbData, "@DBApp");  //连接@DBApp到&pbData后面
24   v0 = strlen((const char *)&pbData);
25   sub_40100A(&pbData, v0, &String1);  //进入加密函数  下有详细分析
26   if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
27   {
28     printf("continue...

");
29     printf("pls input the first passwd(2): ");
30     memset(&String, 0, 0x104u);
31     scanf("%s", &String);
32     if ( strlen(&String) != 6 )  //6位密码
33     {
34       printf("Must be 6 characters!
");
35       ExitProcess(0);
36     }
37     strcat(&String, (const char *)&pbData);  //拼接在&pbData前面
38     memset(&String1, 0, 0x104u);
39     v1 = strlen(&String);
40     sub_401019((BYTE *)&String, v1, &String1);  //进入加密函数  下有详细分析
41     if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )
42     {
43       if ( !sub_40100F(&String) )//进入该判断函数 下有详解
44       {
45         printf("Error!!
");
46         ExitProcess(0);
47       }
48       printf("bye ~~
");
49     }
50   }
51   return 0;
52 }

第25行 进入加密函数  该函数如下

 1 int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
 2 {
 3   int result; // eax
 4   DWORD i; // [esp+4Ch] [ebp-28h]
 5   CHAR String2; // [esp+50h] [ebp-24h]
 6   BYTE v6[20]; // [esp+54h] [ebp-20h]
 7   DWORD pdwDataLen; // [esp+68h] [ebp-Ch]
 8   HCRYPTHASH phHash; // [esp+6Ch] [ebp-8h]
 9   HCRYPTPROV phProv; // [esp+70h] [ebp-4h]
10 
11   if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
12     return 0;
13   if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )
14   {
15     if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
16     {
17       CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
18       *lpString1 = 0;
19       for ( i = 0; i < pdwDataLen; ++i )
20       {
21         wsprintfA(&String2, "%02X", v6[i]);
22         lstrcatA(lpString1, &String2);
23       }
24       CryptDestroyHash(phHash);
25       CryptReleaseContext(phProv, 0);
26       result = 1;
27     }
28     else
29     {
30       CryptDestroyHash(phHash);
31       CryptReleaseContext(phProv, 0);
32       result = 0;
33     }
34   }
35   else
36   {
37     CryptReleaseContext(phProv, 0);
38     result = 0;
39   }
40   return result;
41 }

通过函数名猜测  这段加密函数进行的是hash加密  通过hash-identifirt识别类型为sha1 

1)通过在线工具查询 解

2)通过python的hashlib包可以进行爆破解密

import hashlib
flag2="@DBApp"
for i in range(100000,999999):
    h2 = hashlib.sha1((str(i)+flag2).encode('utf8'))
    flags = h2.hexdigest()
    if "6e32d0943418c2c33385bc35a1470250dd8923a9" == flags:
            print (str(i)+flag2)
            print (flags)

解出first passwd(1)=123321@DBApp

——————————————————————————————————————————————

第40行进入加密函数 该函数如下

 1 int __cdecl sub_401040(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
 2 {
 3   int result; // eax
 4   DWORD i; // [esp+4Ch] [ebp-24h]
 5   CHAR String2; // [esp+50h] [ebp-20h]
 6   BYTE v6[16]; // [esp+54h] [ebp-1Ch]
 7   DWORD pdwDataLen; // [esp+64h] [ebp-Ch]
 8   HCRYPTHASH phHash; // [esp+68h] [ebp-8h]
 9   HCRYPTPROV phProv; // [esp+6Ch] [ebp-4h]
10 
11   if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
12     return 0;
13   if ( CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash) )
14   {
15     if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
16     {
17       CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
18       *lpString1 = 0;
19       for ( i = 0; i < pdwDataLen; ++i )
20       {
21         wsprintfA(&String2, "%02X", v6[i]);
22         lstrcatA(lpString1, &String2);
23       }
24       CryptDestroyHash(phHash);
25       CryptReleaseContext(phProv, 0);
26       result = 1;
27     }
28     else
29     {
30       CryptDestroyHash(phHash);
31       CryptReleaseContext(phProv, 0);
32       result = 0;
33     }
34   }
35   else
36   {
37     CryptReleaseContext(phProv, 0);
38     result = 0;
39   }
40   return result;
41 }

跟第一部分一样是hash加密  用hash-identifirt识别类型 为 MD5   但是一番尝试解不出  先跳过去接着看

进入判断函数

char __cdecl sub_4014D0(LPCSTR lpString)
{
  LPCVOID lpBuffer; // [esp+50h] [ebp-1Ch]
  DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h]
  DWORD nNumberOfBytesToWrite; // [esp+5Ch] [ebp-10h]
  HGLOBAL hResData; // [esp+60h] [ebp-Ch]
  HRSRC hResInfo; // [esp+64h] [ebp-8h]
  HANDLE hFile; // [esp+68h] [ebp-4h]

  hFile = 0;
  hResData = 0;
  nNumberOfBytesToWrite = 0;
  NumberOfBytesWritten = 0;
  hResInfo = FindResourceA(0, (LPCSTR)0x65, "AAA");//FindResourceA()查找资源
  if ( !hResInfo )
    return 0;
  nNumberOfBytesToWrite = SizeofResource(0, hResInfo);
  hResData = LoadResource(0, hResInfo);
  if ( !hResData )
    return 0;
  lpBuffer = LockResource(hResData);
  sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);//lpBuffer在函数里就是a2
  hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);
  if ( hFile == (HANDLE)-1 )
    return 0;
  if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
    return 0;
  CloseHandle(hFile);
  return 1;
}

通过一系列函数名猜操作  找到一个叫“AAA”的资源  加载"AAA"文件内的内容进入sub_401005函数

之后在sub_401005函数操作后创建“dapp.rtf”

sub_401005函数如下

 1 unsigned int __cdecl sub_401420(LPCSTR lpString, int a2, int a3)
 2 {
 3   unsigned int result; // eax
 4   unsigned int i; // [esp+4Ch] [ebp-Ch]
 5   unsigned int v5; // [esp+54h] [ebp-4h]
 6 
 7   v5 = lstrlenA(lpString);
 8   for ( i = 0; ; ++i )
 9   {
10     result = i;
11     if ( i >= a3 )
12       break;
13     *(_BYTE *)(i + a2) ^= lpString[i % v5];  //进行按位异或
14   }
15   return result;
16 }

a2就是AAA中的数据内容

Resource Hacker工具获取AAA数据内容

我们第二部分的密码是六位数

而后在sub_401005函数的xor操作后创建“dapp.rtf”

所以我们推测RTF文件格式的前六位与AAA文件的前六位异或之后,将会得到我们的密码

 新建RTF文档查看基本文件头

RTF文件的文件头前6位基本是固定的 为 { tf1

 通过脚本将他们异或

key = [0x05,0x7D,0x41,0x15,0x26,0x01]
key1="{\rtf1"
flag = ''
for i in range(0,5):
     x=ord(key1[i])^key[i]
     flag+=chr(x)
print(flag)

解出第二部分为 ~!3a@

还差一位密码  利用脚本爆破

from hashlib import md5

key1="123321@DBApp"
key2 ="~!3a@"
for i in range(33,127):
    h=md5((key2+chr(i)+key1).encode('utf8'))
    flags=h.hexdigest()
    if "27019e688a4e62a649fd99cadaafdb4e" in flags:
        print (key2+chr(i)+key1)
        print (flags)

解出完整密码~!3a@0123321@DBApp

运行程序输入密码 (1)123321   (2)~!3a@0

在该程序的文件夹里会出现一个RTF文件,文件内容即为flag

三、flag

Flag{N0_M0re_Free_Bugs}

文章参考:https://www.b1ndsec.cn/?p=76

                  https://www.52pojie.cn/thread-994588-1-1.html

原文地址:https://www.cnblogs.com/Nickyl07/p/12683254.html