InCTF-2021

Reverse~(本来说后面来把做当时做了题的wp更新下,拖太久了,那就算了,暂且就这两个题😂

find_plut0

开始我使用z3来解,掉进坑里了。

这里手动把程序中的连续的数据定义为数组,然后转换一下类型,方便直接复制到z3中使用。

image-20210816122348022

但是跑不出结果,,。

接着使用了最基本的angr模板来跑一下,结果秒出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import angr, claripy, sys

def is_success(state):
std_out = state.posix.dumps(1)
if b'\nYeey you found him !!!!' in std_out:
return True
else:
return False

def is_false(state):
std_out = state.posix.dumps(1)
if b'Lol , he won' in std_out:
return True
else:
return False

proj = angr.Project('./chall')
init_state = proj.factory.entry_state()
sim = proj.factory.simgr(init_state)
sim.explore(find = is_success, avoid = is_false)

for i in range(3):
print(sim.found[0].posix.dumps(i))
1
2
3
4
WARNING | 2021-08-16 12:12:05,063 | cle.loader | The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.
b'`\\ET0a\xfd\x8e\x8b3\x01\x02!7\x03\x02\xc9\xe3\x01\x02\x12\x1ftr\x027\xff\xd1\x02\xe1\x00\x00\x00\x02\x02\x00\x02\x02\x00\x02\x00\x00\x00\x02\x02\x00\x02\x00\x02\x00\x02\x00\x02\x02\x02\x02\x02\x8a\x89\x02'
b"Hello there , i lost my dog pluto :(\nHelp me call him out please !!\n\n ................\n |w00ff w00ff!! |\n '''''V'''''''' \n \n .~````~. \n .,/ \\,. \n ( | (0 0) | )\n ( | ____ | )\n (_/| \\__/ |\\_)\n \\__/\\__/\n '-..-' \n\n\nYeey you found him !!!!\n Grab your reward from nc!\n"
b''

这个有很多不可通过键盘输入的字符,所以使用pwntools来远程sendline一下。

1
2
3
4
5
6
7
8
from pwn import *

#p = remote('34.94.181.140', 4205)
p = process('./chall')
ans = b'`\\ET0a\xfd\x8e\x8b3\x01\x02!7\x03\x02\xc9\xe3\x01\x02\x12\x1ftr\x027\xff\xd1\x02\xe1'
p.recvuntil('him out please !!')
p.sendline(ans)
p.interactive()

然后是找使用z3得不到正确结果的原因。

看了一下运算过程,首先发现了一个/运算:它在python3和C语言中有点区别,python3中会保留运算小数,C中直接取整。这里改为>>1就保持一致了。

image-20210816122710296

再次跑了一下,得到仍然不是正确结果。

调试看运算过程,从汇编层面发现了问题所在,是因为计算的数据类型不当。

程序定义的输入为char类型数组,然后计算的时候也都是以char数组数类型来算的,,ida就把我从汇编层面看到的很多的当运算的数要大于127才会对计算有影响的运算在伪代码中都直接省去了(也可以说这里是ida优化太好了

但对于本题,正确的输入恰好不全是可打印字符,范围可以是(1~255),这也是程序要给nc来连接远程的原因,方便我们输入数据。

正是由于正确输入范围在1~255,所以运算过程直接看伪代码就肯定不对了,z3也得不到正确结果。

下面举几个汇编层面看到的要数据大于127才会对计算结果有影响的汇编指令:

eg1:

伪代码:

image-20210816124859158

汇编代码:红框部分在伪代码中并没有体现,因为当计算的数为char范围的话,这个对最终结果也确实没有影响的。

image-20210816124658017

eg2:

伪代码:

image-20210816134137679

汇编代码:这可以看到伪代码中没有展示出来这里只取最低字节来移位。然后这里比较奇怪,我测试这里sar edx,cl移动的都是1位,但cl的值也不为1呀。而且按照正常cl值来移动的话又显然不对,这个地方还是比较迷糊。

image-20210816134223056

eg3:

伪代码:

image-20210816124907598

汇编代码:这里注意这个movsx指令(带符号扩展传送指令),它先会用al的符号位来填充eax的高24位。也就是说当我们要计算的数是大于127的话,这里结果经过传送指令后就变成了对应的负数。这个其实在运算后用&0xff取低字节后对结果不会有影响,因为一个数转化为对应的负数后他们的二进制位是没有变的。如-1*6与255*6他们计算后的低字节都是相同的。虽然这个例子不影响最后的结果,但值得注意一下。

image-20210816125219175

最后,感觉本题的出题人的本意也是为了对我上面所提到的考察一下,本意上是要我们用angr要解。

main_replica

rust语言逆向,他和go一样都是无虚拟机的高级语言。

首先可以从标志字符串main.rs识别出来这是rust程序,字符串窗口也能看到很多标志字符串:

image-20210818144457208

在做了这个题写wp的时候,乘着这是一个个rust题,我去搭建了一下rust的开发环境。一是为了方便自己编写玩一下rust程序;二是为了使用rust-reversing-helper这个项目来恢复rust程序中的符号。rust-reversing-helper

搭建整个环境到最后符号签名的应用遇到坑肯定还是有的,这个以后来专门开一个文章记录下。

本想wp中提一下用了这个恢复签名的效果,,结果很不理想。

然后回到我做这个题的时候。

根据elf文件的特征,找到main函数,因为程序代码量还是有点大,这就要着重去找关键代码。

很快定位到关键比较:

image-20210818195211548

其实加密就是打乱输入的顺序,然后与密文比较。

调试一遍,得到映射关系就好:

1
2
3
4
5
6
7
8
base = '0123456789abcdefghijklmno'
enc = '0kedtZ6fYO3aX4lPNMSgQbRwh'
tmp = 'onlh98g76kfe54mjdc32iba10'
flag = ''

for i in base:
flag += enc[tmp.index(i)]
print(flag)
-------------本文结束感谢您的阅读-------------