2019 RCTF
赛后复现, 学习学习!
嗯, 主办方很喜欢XXTEA呀0.0
babyre1
题目:babyre1
运行:
Input right flag you can got 'Bingo!' :ssssss |
IDA打开, 找到主函数:
分析得:输入密文, 长度为16, 范围0-9, a-z
之后用xxtea解密, 后进行CRC16_CCITT校验, 结果应该等于0x69E2。而后对解密后的前N位异或0x17, 根据提示, 最终应该得到Bingo!。
而xxtea解密中:
v11 = (unsigned __int8)v8[v6 - 1]; |
根据解密的最后一个字节的大小N, 把明文倒数第N位用”\0”截断。
那么最后一个字节的大小就应该为2, 即最终应该为“Bingo!xx\x02”
, xx未知, 而Bingo!
应异或0x17.
可以通过提示:MD5(rctf{your answer}) == 5f8243a662cf71bf31d2b2602638dc1d
爆破出来。
而我这里是靠猜的, 也不难猜, \x02很像加密时的padding, 所以猜测XXTEA解密后的明文应该为“Bingo!\x02\x02”
(其中Bingo!应为异或0x17后的结果)
则解密脚本如下(XXTEA代码网上抄的0.0):
|
得到flag:
rctf{05e8a376e4e0446e}
babyre2
题目:babyre2
程序逻辑:
输入8-16位长account, 8-16位长password, 不超过0x400长度的data, data范围:
(buf[i] <= '/' || buf[i] > '9') && (buf[i] <= '`' || buf[i] > 'f') && (buf[i] <= '@' || buf[i] > 'F') ) |
后以account作为key, 加密一组常量。
v12 = XXtea_1((__int64)&account, (__int64)&v6); |
0xF8u, 0xD4u, 0xD5u, 0xDCu, 0xC9u, 0xDAu, 0xCFu, 0xCEu, 0xD7u, 0xDAu, 0xCFu, 0xD2u, 0xD4u, 0xD5u, 0xC8u, 0x9Au, 0xB1u |
password的每一位减去十位和个位, 减去的结果作为下标从data取数据, 得到data2.
for ( i = 0; i < v10; ++i ) |
用data2异或0xCC作为key密之前的密文。
for ( j = 0; j < a2; ++j ) |
于是直接构造account:’1’*16, data’fd’*256, password任意16位即可
脚本:
from pwn import * |
p.s.这题还有时间限制, 调试的时候就很喜欢Time Out!0.0….
DontEatMe
题目:DontEatMe
运行程序:
LiHua is trapped on an isolated island. One day, he caught a fish. |
根据输出找到主函数, 一开始有ZwSetInformationThread反调试:
v70 = GetModuleHandleA("Ntdll"); |
直接跳过就可以了, 伪随机数生成以一串key, 接下来应该是那个函数应该是Blowfish
srand(0xDEADBEEF); |
特征为:
.rdata:000B3118 dword_B3118 dd 243F6A88h ; DATA XREF: Blowfish+12↑o |
接下来这里, 无论输什么, 运算后v8 = 8。所以else里面那一大串都可以不用看hhh
if ( v8 / 16 <= 0 ) |
接下来大一串, 就为了生成一个迷宫
a68 = *(_QWORD *)"DontEatM"; |
大概长这样:
1111111111111111 |
根据maze
和解密后的输入进行check
v103 = *v92; |
直接DFS算出明文:
maze = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] |
得到:ddddwwwaaawwwddd
最终解密脚本如下:
from Crypto.Cipher import Blowfish |
得flag:
RCTF{db824ef8605c5235b4bbacfa2ff8e087}
crack
题目:crack
第一部分
根据字符串, 找到主要函数:
v4 = v3; |
这一句限制了输入必须为0 or 1:
if ( v15 != '0' && v15 != '1' ) |
调试运行过程中, 可知v13 = 0x200:
v13 = v4[58]; // 0x200 if ( v12 >= v13 ) // 0x200 * 0x200 |
这一部分的逻辑很像之前做过的Bugku里面的
因为静态找不到mountain, 所以只能在动态调试过程中将mountain dump出来, 脚本如下:
import ida_bytes |
得到:
10256753 |
动态规划求解:
import numpy |
求得512位输入:
00000000010101000000000111100111111110100111100101001000101010010011101100111101011111111111111111001110111011011000000101110111001111100100011000000000000110001111110100000000001101110111010101011111000101110000011000111001110000000000000000000000011001000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011100011111110000100111000000000000000000000000000000010000000000000001000001100000000000000101000000000100000010000000000000000010000000000000000000000 |
第二部分
接着分析这个函数:
v18(v4, &v30, v19); |
在动态调试过程中可以将汇编代码转成一个函数进行静态分析:
int __stdcall sub_3B46020(_DWORD *a1, int a2, int a3) |
大概是个VM, 调试过程中将操作码dump出来, 嗯, 复制粘贴
之后分析VM过程, 写个脚本将过程大致还原一下:
code = '000000010101100100000000000000110000010000010110100000000011000000000000000000001100110000000000110000000000000000000000101000000000000000000000000000000000110000000000010000000000000000000000101000000000111000000000000000000000110000011000110000111000010010110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000000000011000000000000000000000110000011000111000110100110000000000011000000000000000000000101000100000111000000000000000000000011000100000100000000000000000000000110100110000000000111000000000000000000000101000000000000000000000000000000000100110100000011000000000000000000000011000100000111000000000000000000000101100100000111111000100001011110000011010100000011011000011000000000000010110100000011000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000110100000000000000000000011000111000100010110000000000110100000000000000000000101000100000001100000000000000000000011000111000100010110000000000001100000000000000000000101000100000101100000000000000000000011000111000100010110000000000101100000000000000000000101000000000111000000000000000000000100000000000000000000000000000101000100000101100000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000111000000000000000000000011000111000101010100000011011111001000000000000010110100000011000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000111000000000000000000000011000111000110100110000000000000010000000000000000000101000100000111000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000011100000000000000000000011000111000100100110000000000100010000000000000000000101000100000000010000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000100010000000000000000000011000111000100010110000000000001000000000000000000000101000100000111000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000011100000000000000000000011000111000010100100000111000000000000000000000011000100000100000000000000000000000110100110000000000111000000000000000000000101000000000000001110010000000000000100110100000110100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000000000000000000000000000010100100000001100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000100000000000000000000000010100100000101100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000010000000000000000000000010100100000011100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000110000000000000000000000010100' |
得到:
mov r0, 0x26a |
接下来就只能靠猜的了0.0
由于又这几句:
mov r1, 0x7 |
猜测这里是check, 也就是说有另外一个数(暂时不知道这个数怎么算出来的), 这个数*7 == 0xf423f, 也就是0x22e09。又因为整一个逻辑下来只有一句shl r0, r1
, 所以猜测有另外一个二进制数跟在前512的输入之后, 而这个二进制数应该为100010111000001001(==0x22e09)而且输入应该是大端序, 也就是100100000111010001, 即整个第二部分逻辑大概是
input = "100100000111010001" |
所以整个输入为前512位输出接上100100000111010001:
00000000010101000000000111100111111110100111100101001000101010010011101100111101011111111111111111001110111011011000000101110111001111100100011000000000000110001111110100000000001101110111010101011111000101110000011000111001110000000000000000000000011001000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011100011111110000100111000000000000000000000000000000010000000000000001000001100000000000000101000000000100000010000000000000000010000000000000000000000100100000111010001 |
得到flag:13yR01sw3iy1l1n9