• [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然后就进行比较

    1. int __cdecl main(int argc, const char **argv, const char **envp)
    2. {
    3. ...
    4. std::operator<<<std::char_traits<char>>(
    5. &std::cout,
    6. (unsigned int)"Enter the dragon's secret: ",
    7. "Enter the dragon's secret: ");
    8. fgets(s, 257, stdin);
    9. std::allocator<char>::allocator(v8);
    10. std::string::string(v9, s, v8);
    11. std::allocator<char>::~allocator(v8);
    12. std::string::string((std::string *)v7, (const std::string *)v9);
    13. started = start_quest((std::string *)v7);
    14. std::string::~string((std::string *)v7);
    15. if ( started == 4919 )
    16. {
    17. std::string::string((std::string *)v6, (const std::string *)v9);
    18. reward_strength(v6);
    19. std::string::~string((std::string *)v6);
    20. }
    21. ...
    22. }

    在start_duest中有一大堆数据

    1. __int64 __fastcall start_quest(std::string *a1)
    2. {
    3. ......
    4. v10 = a1;
    5. if ( y26 >= 10 && ((((_BYTE)x25 - 1) * (_BYTE)x25) & 1) != 0 ) #恒为0无条件不跳转
    6. goto LABEL_13;
    7. while ( 1 )
    8. {
    9. v9 = &v2[-2];
    10. v8 = &v2[-2];
    11. v7 = (int *)&v2[-2];
    12. v6 = (std::string *)&v2[-2];
    13. std::vector<int>::push_back(&hero, &secret_100); //数据
    14. std::vector<int>::push_back(&hero, &secret_214);
    15. std::vector<int>::push_back(&hero, &secret_266);
    16. std::vector<int>::push_back(&hero, &secret_369);
    17. ......

    很明显这跟flag有关,先看数据

    1. .data:000000000061013C 64 secret_100 db 64h ; d ; DATA XREF: start_quest(std::string)+5E↑o
    2. .data:000000000061013C ; start_quest(std::string)+8CD↑o
    3. .data:000000000061013D 00 db 0
    4. .data:000000000061013E 00 db 0
    5. .data:000000000061013F 00 db 0
    6. .data:0000000000610140 public secret_214
    7. .data:0000000000610140 D6 secret_214 db 0D6h ; DATA XREF: start_quest(std::string)+AF↑o
    8. .data:0000000000610140 ; start_quest(std::string)+8E6↑o
    9. .data:0000000000610141 00 db 0
    10. .data:0000000000610142 00 db 0
    11. .data:0000000000610143 00 db 0
    12. .data:0000000000610144 public secret_266
    13. .data:0000000000610144 0A secret_266 db 0Ah ; DATA XREF: start_quest(std::string)+C8↑o
    14. .data:0000000000610144 ; start_quest(std::string)+8FF↑o
    15. .data:0000000000610145 01 db 1
    16. .data:0000000000610146 00 db 0
    17. .data:0000000000610147 00 db 0
    18. .data:0000000000610148 public secret_369
    19. .data:0000000000610148 71 secret_369 db 71h ; q ; DATA XREF: start_quest(std::string)+E1↑o
    20. .data:0000000000610148 ; start_quest(std::string)+918↑o
    21. .data:0000000000610149 01 db 1
    22. .data:000000000061014A 00 db 0
    23. .data:000000000061014B 00 db 0
    24. .data:000000000061014C public secret_417
    25. .data:000000000061014C A1 secret_417 db 0A1h ; DATA XREF: start_quest(std::string)+FA↑o
    26. .data:000000000061014C ; start_quest(std::string)+931↑o
    27. .data:000000000061014D 01 db 1
    28. .data:000000000061014E 00 db 0
    29. .data:000000000061014F 00 db 0
    30. .data:0000000000610150 public secret_527
    31. .data:0000000000610150 0F secret_527 db 0Fh ; DATA XREF: start_quest(std::string)+113↑o
    32. .data:0000000000610150 ; start_quest(std::string)+94A↑o
    33. .data:0000000000610151 02 db 2
    34. .data:0000000000610152 00 db 0
    35. .data:0000000000610153 00 db 0

    这些数据是64,d6,10a,171明显超过ascii的范围,并且是递增的,后边的算法也看不明白,试试后边减前边得到64,114,52这些都能转成ascii码,试着转一下

    1. 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]
    2. print(bytes([a[i]- a[i-1] for i in range(1, len(a))]))
    3. #dr4g0n_or_p4tric1an_it5_LLVM
    4. #flag{dr4g0n_or_p4tric1an_it5_LLVM}

    确实得到的就是flag,有一定懵的成分。

    118_[De1CTF2019]cplusplus

    这个整不出来,看了下WP也不大明白,对照代码一点点注释。

    1. int __cdecl main(int argc, const char **argv, const char **envp)
    2. {
    3. ...
    4. sub_140004DD0(std::cin, v52); // 读入
    5. v4 = v52;
    6. if ( v54 >= 0x10 )
    7. v4 = (void **)v52[0];
    8. v5 = (void **)((char *)v4 + v53);
    9. v20[0] = 9024;
    10. *(_QWORD *)v23 = &v22;
    11. v23[8] = byte_14000C7D7;
    12. v31 = *(__m128d *)v23;
    13. v32 = &unk_14000C7ED;
    14. v33 = &v31;
    15. *(_QWORD *)v23 = (char *)&v21 + 2;
    16. v34 = *(__m128d *)v23;
    17. v29[0] = (__int64)&unk_14000C7ED;
    18. v29[1] = (__int64)&v34;
    19. *(_QWORD *)v23 = &v21;
    20. v23[8] = byte_14000C7D7;
    21. v27[0] = (__int64)&unk_14000C7ED;
    22. v27[1] = (__int64)&v35;
    23. v28[0] = (__int64)v27;
    24. v28[1] = (__int64)v20;
    25. v30[0] = (__int64)v28;
    26. v30[1] = (__int64)v29;
    27. v36 = v30;
    28. v37 = (__int64)v20 + 1;
    29. v48 = (__int64)v4 + v53;
    30. *((_QWORD *)&v24 + 1) = *(_QWORD *)&v31.m128d_f64[0];
    31. *(__m128d *)&v46[8] = v34;
    32. *(_OWORD *)&v23[8] = *(_OWORD *)v23;
    33. v35 = *(__m128d *)&v23[8];
    34. v38 = *(_OWORD *)v23; // 数据结构 d1 @ d2 # d3
    35. v39 = *(_OWORD *)&_mm_unpackhi_pd(v35, v35);
    36. v40 = '@';
    37. v41 = *(_OWORD *)v46;
    38. v42 = *(_OWORD *)&_mm_unpackhi_pd(v34, v34);
    39. v43 = '#';
    40. v44 = v24;
    41. v45 = *(_OWORD *)&_mm_unpackhi_pd(v31, v31);
    42. v47 = v4;
    43. *(_QWORD *)&v24 = &v47;
    44. *((_QWORD *)&v24 + 1) = &v48;
    45. v25 = &unk_14000C808;
    46. v26 = &unk_14000C808;
    47. *(_QWORD *)v23 = &v38;
    48. if ( sub_140005910((__int64 *)v23, (__int64)&v21, (__int64 **)&v24) || v47 != v5 )// 判断结构 d1@d2#d3
    49. _exit(0);
    50. LODWORD(v47) = v21;
    51. WORD2(v47) = v22;
    52. sub_1400029B0(&v47); // d1 = 78
    53. sub_1400046A0(Block);
    54. if ( v50 != 5 )
    55. goto LABEL_40;
    56. v6 = time64(0i64);
    57. if ( v6 - v3 > 3 )
    58. goto LABEL_40;
    59. v7 = Block;
    60. if ( v51 >= 0x10 )
    61. v7 = (void **)Block[0];
    62. if ( aEqdtw91a0qwryu[*(char *)v7 - 48] != 68 )// d2 = 20637
    63. goto LABEL_39;
    64. v8 = Block;
    65. if ( v51 >= 0x10 )
    66. v8 = (void **)Block[0];
    67. if ( aEqdtw91a0qwryu[*((char *)v8 + 1) - 48] != 101 )
    68. goto LABEL_39;
    69. v9 = Block;
    70. if ( v51 >= 0x10 )
    71. v9 = (void **)Block[0];
    72. if ( aEqdtw91a0qwryu[*((char *)v9 + 2) - 48] != 49 )
    73. goto LABEL_39;
    74. v10 = Block;
    75. if ( v51 >= 0x10 )
    76. v10 = (void **)Block[0];
    77. if ( aEqdtw91a0qwryu[*((char *)v10 + 3) - 48] != 116 )
    78. goto LABEL_39;
    79. v11 = Block;
    80. if ( v51 >= 0x10 )
    81. v11 = (void **)Block[0];
    82. if ( aEqdtw91a0qwryu[*((char *)v11 + 4) - 48] != 97 )
    83. {
    84. LABEL_39:
    85. Sleep(5u);
    86. _exit(0);
    87. }
    88. if ( (int)(time64(0i64) - v6) > 2 )
    89. LABEL_40:
    90. _exit(0);
    91. 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
    92. {
    93. sub_1400041F0(std::cout, "You failed...again");
    94. _exit(0);
    95. }
    96. v12 = sub_1400041F0(std::cout, "Your flag is:");
    97. std::ostream::operator<<(v12, sub_1400043C0);
    98. v13 = sub_1400041F0(std::cout, "de1ctf{");
    99. v14 = v52;
    100. if ( v54 >= 0x10 )
    101. v14 = (void **)v52[0];
    102. v15 = sub_140004FC0(v13, v14, v53);
    103. v16 = sub_1400041F0(v15, "}");
    104. std::ostream::operator<<(v16, sub_1400043C0);
    105. if ( v51 >= 0x10 )
    106. {
    107. v17 = Block[0];
    108. if ( v51 + 1 >= 0x1000 )
    109. {
    110. v17 = (void *)*((_QWORD *)Block[0] - 1);
    111. if ( (unsigned __int64)(Block[0] - v17 - 8) > 0x1F )
    112. invalid_parameter_noinfo_noreturn();
    113. }
    114. j_j_free(v17);
    115. }
    116. v50 = 0i64;
    117. v51 = 15i64;
    118. LOBYTE(Block[0]) = 0;
    119. if ( v54 >= 0x10 )
    120. {
    121. v18 = v52[0];
    122. if ( v54 + 1 >= 0x1000 )
    123. {
    124. v18 = (void *)*((_QWORD *)v52[0] - 1);
    125. if ( (unsigned __int64)(v52[0] - v18 - 8) > 0x1F )
    126. invalid_parameter_noinfo_noreturn();
    127. }
    128. j_j_free(v18);
    129. }
    130. return 0;
    131. }

    在输入后,找两个定位符@#然后逐个段时判断,d2容易点一比较就行,其它两个都是动调,没啥好想的,运行到那就出现了。结果就是这样

    1. #123@456#789
    2. #d1 = 78
    3. #d2 = 20637
    4. #d3 = 114
    5. #flag{78@20637#114}

    119_[CFI-CTF 2018]Automated Reversing

    附件里有970个小文件,还随机送了生成程序和解密程序solution.py  当时一楞,还给了解密程序。直接运行不就得了。不过可能那是python2写的,我这3有点小问题,于是小小改动一点。输出一大堆东西,在里边就有flag

    到了1分以后难的是真难,但也有不少简单的一塌糊涂

    1. flag = b''
    2. for i in range(970):
    3. path = "binaries/binary{}".format(i)
    4. with open(path, "rb") as f:
    5. binary = f.read()
    6. operator = binary[0xca]
    7. key = binary[0xcb]
    8. check = binary[0xce]
    9. if operator == 0xc2: # add
    10. flag += bytes([(0x100+ check - key) & 0xff])
    11. elif operator == 0xea: # sub
    12. flag += bytes([(check + key) & 0xff])
    13. else:
    14. flag += bytes([check ^ key])
    15. print(flag)
    16. #改python3 chr改为bytes
    17. #flag{1s_th1s_4_pr0g_ch4ll_0r_4_r3ve3se_ch4ll?}
    18. '''
    19. b'\nLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula dolor. Aenean massa. Cum sociis nato
    20. que penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu,
    21. pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
    22. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tin
    23. cidunt. Cras dapibus. The flag is CFI{1s_th1s_4_pr0g_ch4ll_0r_4_r3ve3se_ch4ll?}. Aenean vulputate eleifend tellus. Aenea
    24. n leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. I stole this idea directly from Defcon Quals 2016. Phase
    25. llus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur
    26. ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semp
    27. er libero, si'
    28. '''

    120_[RCTF2019]babyre1

    这个题实在作不出来,就看了WP,发现原题有个提示就是给了md5值,呵呵。

    hint md5('rctf{'+input+'}').digest.hex() == '5f8243a662cf71bf31d2b2602638dc1d'

    题目在main里进行了几个操作

    1. __int64 __fastcall main(int a1, char **a2, char **a3)
    2. {
    3. ...
    4. memset(v11, 0, 0x100uLL);
    5. __printf_chk(1LL, "Input right flag you can got 'Bingo!' :");
    6. __isoc99_scanf("%31s", v11);
    7. v3 = &v11[strlen(v11)];
    8. if ( (unsigned __int64)(v3 - v11) > 0x10 )
    9. {
    10. puts("input is too long!");
    11. }
    12. else if ( v3 - v11 == 16 )
    13. {
    14. v4 = sub_C00((unsigned __int64)v11, 16, (char **)&ptr);// 16进制转数字
    15. if ( v4
    16. && (v5 = sub_1180(ptr, v4, (__int64)&unk_202010, 16, &v9), (v6 = v5) != 0LL)// tea
    17. && v9 > 0
    18. && (unsigned __int16)((__int64 (__fastcall *)(char *))sub_13D0)(v5) == 27106 )// crc校验
    19. {
    20. for ( i = 0LL; v9 > (int)i; ++i )
    21. v6[i] ^= 0x17u;
    22. puts(v6);
    23. if ( ptr )
    24. free(ptr);
    25. free(v6);
    26. }
    27. else
    28. {
    29. puts("input flag is wrong!");
    30. }
    31. }
    32. else
    33. {
    34. puts("input is too short!");
    35. }
    36. return 0LL;
    37. }

    一开始就是说会输出Bingo,然后是16进制转换和tea加密(用findcrypt能搜出一堆来,看上去是标准加密)

     然后是个自制的crc校验,其实这里一直也没逆出来,也就不逆了,从前边两项和md5值入手就行了。

    tea解密后与0x17异或是Bingo但还少2字符,也就是这个需要爆破,tea的key在202010已经给出。

    也就是将Bingo爆破两位与0x17异或后用tea加密,再求md5进行比较

    1. #hint md5('rctf{'+input+'}').digest.hex() == '5f8243a662cf71bf31d2b2602638dc1d' buu未给出
    2. import xxtea
    3. import hashlib
    4. key = [0xc7,0xe0,0xc7,0xe0,0xd7,0xd3,0xf1,0xc6,0xd3,0xc6,0xd3,0xc6,0xce,0xd2,0xd0,0xc4]
    5. text = [v^0x17 for v in b'Bingo!\0\0']
    6. for i in range(0x100):
    7. for j in range(0x100):
    8. text[6] = i
    9. text[7] = j
    10. c = xxtea.encrypt(bytes(text), bytes(key), padding=False ).hex()
    11. flag = 'rctf{'+c+'}'
    12. #print(flag)
    13. if hashlib.md5(flag.encode()).digest().hex() == '5f8243a662cf71bf31d2b2602638dc1d':
    14. print('OK:',flag)
    15. exit()
    16. #rctf{05e8a376e4e0446e}
    17. #flag{05e8a376e4e0446e}

  • 相关阅读:
    Spring AOP 的使用
    zookeeper学习记录
    增强大型语言模型(LLM)可访问性:深入探究在单块AMD GPU上通过QLoRA微调Llama 2的过程
    电脑重装系统后如何删除微软商店下载记录
    CS 611 Legends: Monsters and Heroes
    20 行代码!带你快速构建基础文本搜索引擎 ⛵
    【架构师(第十二篇)】脚手架之命令行交互工具 inquirer.js 使用方法
    操作系统学习笔记_1 计算机系统的运行和结构
    新加坡大带宽服务器托管优势
    编译原理实验一:源程序的预处理及词法分析程序的设计与实现(python)
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/125438505