[buuctf.reverse] 117-120

目录

117_[XMAN2018排位赛]Dragon Quest

118_[De1CTF2019]cplusplus

119_[CFI-CTF 2018]Automated Reversing

120_[RCTF2019]babyre1


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}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值