zerofs.ko is a driver module of a custom filesystem. The kernel and the module is compiled by randstruct plugin, which I found in the magic string – vermagic=4.13.0 SMP mod_unload modversionsRANDSTRUCT_PLUGIN_3c73df5cc8285309b74c8a4caaf831205da45096402d3b1a80caab1d7fa1b03a`. run.sh and /init show that the kernel is protected by SMEP, SMAP, KASLR, kptr_restrict and dmesg_restrict.
zerofs.ko
I found the module may be modified from simplefs after the game. By reversing zerofs.ko, I knew the blocksize is 4096 bits. The first block of the image is the superblock. It consists of magic, block_size, inode_count and free_blocks bitmap.
The second block records all of the inodes in an array. ino is inode number, and dno is the block number of the image.
There is a root inode which ino is 1. It indicates the root dictionary. There is a block corresponding to root dictionary to indicates files in the dictionary. It is an array of zerofs_dir_record structure.
Vulnerabilitie
There isn’t any bound or size check in read and write function. If the filesize we set in image is bigger than blocksize(0x1000), there will be an out-of-bound read/write when invoking copy_to_user/copy_from_user.
After mounting the image, I could trigger out-of-bound read by read the file 666. I tried to find CRED struct in leaked memory. Fortunately, I found some by searching the uid. It took me some time to locate CRED struct because of the radomization of structures.
I still didn’t know which CRED is valid and which process the CRED belongs to although I could find some CRED structures. The exploit is not stable, so I run the exploit serval times. After leaking the memory, the exploit will check if it gets root privilege in a loop. If so, it invokes system("sha256sum /root/flag");.
The last step is to write the CRED. I invoked llseek to set offset to the CRED, and invoked write to modify the CRED, setting uid to 0.
There is a qemu-system-x86_64 binary with a launch script, a linux kernel, a initramfs and some dependencies.
We can get an interactive shell by executing launch.sh.
1
2
3
4
5
6
7
8
9
10
11
__ __ _____________ __ __ ___ ____
/ //_// ____/ ____/ | / / / / / | / __ )
/ ,< / __/ / __/ / |/ / / / / /| | / __ |
/ /| |/ /___/ /___/ /| / / /___/ ___ |/ /_/ /
/_/ |_/_____/_____/_/ |_/ /_____/_/ |_/_____/
Welcome to Tencent Keenlab
Tencent login: root
# uname -r
4.8.0-52-generic
#
The custom vulnerable device
luanch.sh shows there are two custom device named vdd.
1
2
$ ./qemu-system-x86_64 -device help 2>&1 | grep VDD
name "VDD", bus PCI, desc "KeenLab virtualized Devices For Testing D"
we can use some commands to find these devices and their io port/memroy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# lspci
00:00.0 Class 0600: 8086:1237
00:01.3 Class 0680: 8086:7113
00:03.0 Class 0200: 8086:100e
00:01.1 Class 0101: 8086:7010
00:02.0 Class 0300: 1234:1111
00:05.0 Class 00ff: 1234:2333
00:01.0 Class 0601: 8086:7000
00:04.0 Class 00ff: 1234:2333
# cat /proc/iomem
...
fe900000-fe9fffff : 0000:00:04.0
fea00000-feafffff : 0000:00:05.0
...
# cat /proc/ioports
...
c000-c0ff : 0000:00:04.0
c100-c1ff : 0000:00:05.0
...
OOBW
In vdd_mmio_write, there is a out-of-bound write vulnerability which copys QEMU heap memory to guset physical memory when we set dma_len larger than sizeof(dam_buf).
First, we allocate a buffer and get it’s physical address. Then we set dma_state->dst to our buffer and set dma_len larger than sizeof(dma_buf). Finally, we trigger phys_mem_write by writel(0, piomem + 32). By searching the output, we can find libc addresses and program addresses then calculate the base address of program/libc.
Becasue the QEMU is launched with --nographic -append 'console=ttyS0', so we can simply invoke system(cmd) to run a command in host machine and the output will show in console.
To invoke system(cmd), We need to:
set opaque->dma_state->phys_mem_read to system
set opaque->dma_buf to cmd
make sure opaque->dma_state->cmd != 0.
In vdd_linear_write, when addr == 0, a buffer will be allocated with size of opaque->dma_len. And the data in opaque->dma_state->src with length of opaque->dma_len will be copied to opaque->buf, then copied to opaque->dma_state->dst
Different people see different me. But I am always myself. 202.112.26.114:12321 Make the output of your program exactly the same as your source code. At least 3 correct to get this flag $python2 –version Python 2.7.6 $python3 –version Python 3.4.0 $gcc –version gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 $ruby –version ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux] $perl –version This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi
Talentyange gives lots of tedious apks and you know how bad he is now. Let’s try some interesting geography knowledge. nc 202.112.26.111 29995 / nc 202.112.28.118 29995
上去以后问你xxx是哪里的,用国家2字母简称表达。 前20轮给国家,21-70给地名,70-75问你河流或者山脉经过的国家。。。 前70用google map的geocoding api 后70轮用google+维基百科手动输入+自动缓存
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
from zio import *
import re
import requests
import json
correct = {
'Palestine, State of' : 'PS',
'Norfolk Island':'NF',
'Alexandria':'EG',
'Antarctica':'AQ',
'Micronesia':'FM',
'Naples':'IT',
'Mount Olympus':'GR',
'Hyde Park':'GB',
'Georgia':'GE',
'Micronesia (Federated States of)':'FM',
'Korea (Republic of)':'KR',
'Holy See':'VA',
'Tanzania, United Republic of':'TZ',
'Macedonia (the former Yugoslav Republic of)':'MK',
Login as guest. Logout as root. libc.so.6 202.112.26.107:10910 202.112.28.116:10910
>
Notice: Ubuntu 14.04.2 LTS The process is protected by a sandbox. So you may not get a shell. The only thing you can do is reading the “flag”. If you want to break the sandbox, turn to task “0ops APP”.
漏洞发现
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH login