De1CTF 2019 (一)

Last updated on January 27, 2024 am

Cplusplus,RE_sign

Cplusplus

总体分析

程序的输入和关键比较函数都比较明显,直接看关键的函数

截屏2024-01-14 00.21.49

在这个函数里面里面,出现了三次sub_140005a90这个函数,这个函数经过一点🤏时间的调试后,发现就是字符串转16进制,并且限定输入只能是数字而不能是字符。

截屏2024-01-14 00.22.22

这里用了三次这个函数,也就是把输入转了三次,猜测到这里就是把flag分成三段,类似这样111_111_111,这里下划线就是分隔符。

分隔符

然后再接着看这个sub_140006910,直接对着F5的代码调试的时候总会有奇奇怪怪的事情,应该IDA没有很好识别,所以转去看汇编,值得注意的是这里有两个挺关键的比较函数,位与21行和23行。

截屏2024-01-14 00.25.55

将断点下在这里,动态调试会得到这样的汇编

截屏2024-01-14 00.31.26

这里的al就是之前提及的分隔符,[rsi+18h]就是这个分隔符,如果不在这里加分隔符那么上面的loc_14000599c就会直接退出。查看[rsi+18]就可以得到这个分隔符,下面的汇编也是如此。总之现在得到了两个分隔符分别是@和#,那么输入的形式就是111@111#111

第一部分

经过第一个格式check后,进入第二个内容check,也就是检查每个部分的flag是否正确。

先看第一部分flag的检查

截屏2024-01-14 00.35.43

这里的v45就是第一部分flag的16进制,即输入78那么v45=4E,就是78=0x4e。这个函数会首先限制输入小于0x6f,然后走一个十分复杂的算法,看其他WP说这是梅森旋转算法,不懂。但可以找到一个很关键的比较语句

截屏2024-01-14 00.39.34

不管中间算法怎样复杂,这里肯定是不能exit的,而且输入范围也比较小,那么就可以考虑爆破。这里爆破的基本思路就是不断改变输入的值,然后通过if语句。

爆破可以考虑以下两种手段,

  1. 直接dump源码
  2. 从源程序patch

这里用patch源程序方式。

先在IDA中找到对应位置

这里是与0x6f比较

截屏2024-01-14 00.42.49

x64dbg打开,注意这里rbx寄存器存放的就是第一部分flag值的内存地址

截屏2024-01-14 00.46.05

这里是if判断语句

截屏2024-01-14 00.43.29

x64dbg打开,rbx寄存器仍没有发生变化。

截屏2024-01-14 00.48.39

那么就可以通过rbx寄存器爆破flag,具体patch如下

截屏2024-01-14 00.51.13 截屏2024-01-14 00.51.39

其余部分不变,然后在140002b07下一条语句处下断点然后运行,程序断下后再查看rbx寄存器内存对应值即可。最终也就是爆破得到第一部分flag为78

第二部分

这里的flag就比较简单了,就是数组的简单索引

截屏2024-01-14 00.55.38

得到第二部分是20637

第三部分

这部分只有一条语句,不过IDA识别有问题,直接看汇编就好

截屏2024-01-14 00.56.22

这里[rbp+0x0E0h+var_58]就是0x22h,只是之前那个梅森算法的输出,[rbp+0x0E0h+var_58+4]是第三部分flag。

截屏2024-01-14 00.57.09

所以这里很明确

flag_3 % 0x22 =0xc

flag_3 / 0x22 = 3

那么flag_3 = 3 * 0x22 + 0xc = 114

所以flag就是78@20637#114

RE_sign

主程序逻辑比较明显

大意就是输入flag,然后经过sub_401233进行加密,中间进行一些运算然后去到33行的if判读语句进行判断。经过简单调试可以发现,sub_401233高度疑似是一个变表的base64操作,中间21行至31行不会对输入进行操作。

现在就需要跟进sub_401233进行分析。

sub_401233函数很长,很多if、while等语句,逐一分析不太现实。程序中存在原base64的字符串表,并且在这个函数中有所引用,可以基本推测变表是基于原表进行变化。

往下审计过程中会发现有一个特殊的判断语句if (i > 63),而base的表正是64为长度,推测这里可能是生成变表,于是打个断点,看看会得到什么

在if处下断点,在Hex View中可以发现新的特殊的字符串

然后打断点跳出循环

点击v221变量去它的地址处,找附近有没有可能的base64字符串

找到类似的字符串0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/,经过验证,这个就是变表后的base64表。

继续往后分析进入到于flag比较的地方,这里面也挺多操作,但是可以从后往前看。

首先很显然不能进入else里面,否则会返回0值,而要返回1则需要v34==49,推测是比较成功的密文字符数量,继续往前倒推可以看到71行的if判断语句,这里这是涉及到break操作,而想要进入到这个if语句判断,前面还有一个if需要满足

这里的v5是经过变表base64后的字符串,其长度需要为48,那么原始字符串就需要是33~36个字节。

进入sub_402160查看

这里又用到了原始的base64表,并且还用到了加密了的base64输入,猜测这里是返回加密的字符在原表中的索引,经过调试发现确实如此,而原始判断左边v19则是密文。

至此加密逻辑就已经很清晰了,首先进行变表的base64加密,变表为0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/,再把加密字符在原base64表中的索引作为最后的密文,那么解密就很简单了,

先得到加密的base64密文

1
2
3
4
5
6
7
enc = [8, 59, 1, 32, 7, 52, 9, 31, 24, 36, 19, 3, 16, 56, 9, 27, 8, 52, 19, 2, 8, 34, 18, 3, 5, 6, 18, 3, 15, 34, 18, 23, 8, 1, 41, 34, 6, 36, 50, 36, 15, 31, 43, 36, 3, 21, 65, 65]

table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='

for i in enc:
print(table[i-1],end='')
# H6AfGzIeXjSCP3IaHzSBHhRCEFRCOhRWHAohFjxjOeqjCU==

再base64解密即可

de1ctf{E_L4nguag3_1s_K3KeK3_N4Ji4}


De1CTF 2019 (一)
http://example.com/2024/01/14/De1CTF 2019/
Author
yring
Posted on
January 14, 2024
Licensed under