Skip to content

Commit 26934cb

Browse files
author
Nico Waisman
authored
Merge pull request #19 from kevinbackhouse/Apport_pid_recycling_CVE-2019-15790
Add new exploit, based on Apport PID recycling vulnerability
2 parents e4c3093 + 011fab2 commit 26934cb

29 files changed

Lines changed: 35168 additions & 65 deletions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
gencrashreport
22
killwhoopsie1
3+
killwhoopsie2
4+
segv
5+
whoopsie_exploit
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
all: gencrashreport killwhoopsie1
1+
all: gencrashreport killwhoopsie1 killwhoopsie2 segv whoopsie_exploit
22

33
gencrashreport: gencrashreport.cpp utils.cpp
44
g++ -Wall -O2 gencrashreport.cpp utils.cpp -o gencrashreport
55

66
killwhoopsie1: killwhoopsie1.cpp utils.cpp
77
g++ -Wall -O2 killwhoopsie1.cpp utils.cpp -o killwhoopsie1
88

9+
killwhoopsie2: killwhoopsie2.cpp utils.cpp
10+
g++ -Wall -O2 killwhoopsie2.cpp utils.cpp -o killwhoopsie2
11+
12+
segv: segv.c
13+
gcc -Wall -O2 segv.c -o segv
14+
15+
whoopsie_exploit: whoopsie_exploit.cpp restart_whoopsie.cpp load_crash_report.cpp encoding.c utils.cpp
16+
g++ -Wall -O2 whoopsie_exploit.cpp restart_whoopsie.cpp load_crash_report.cpp encoding.c utils.cpp -o whoopsie_exploit
17+
918
clean:
10-
rm -f gencrashreport killwhoopsie1
19+
rm -f gencrashreport killwhoopsie1 killwhoopsie2 segv whoopsie_exploit
Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,11 @@
1-
# Ubuntu Apport TOCTOU (CVE-2019-7307) and whoopsie heap buffer overflow (CVE-2019-11476)
1+
# Vulnerabilities in Ubuntu's apport and whoopsie components (CVE-2019-7307, CVE-2019-11476, CVE-2019-11481, CVE-2019-11484, CVE-2019-15790)
22

3-
This directory contains proof-of-concept exploits for vulnerabilities in Ubuntu's crash reporting system:
3+
This directory contains proof-of-concept exploits for five vulnerabilities in the [apport](https://launchpad.net/ubuntu/+source/apport) and [whoopsie](https://launchpad.net/ubuntu/+source/whoopsie) components of [Ubuntu](https://ubuntu.com/)'s crash reporting system:
44

5-
* [CVE-2019-7307](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7307) is a time-of-check to time-of-use (TOCTOU) vulnerability in Apport, which enables an unprivileged local user to trick Apport into including the contents of an arbitrary file in a crash report. The full bug report is public on [bugs.launchpad.net](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1830858).
6-
* [CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476) is a denial of service vulnerability. An integer overflow when reading large crash dumps (> 4GB) leads to a heap buffer overflow. I do not believe it is possible to exploit this heap buffer overflow to achieve code execution, so I have classified this bug as a denial of service. The full bug report is public on [bugs.launchpad.net](https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830863).
5+
* [CVE-2019-7307](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7307) is a time-of-check to time-of-use (TOCTOU) vulnerability in apport, which enables an unprivileged local user to trick apport into including the contents of an arbitrary file in a crash report. See [README_CVE-2019-7307](README_CVE-2019-7307.md).
6+
* [CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476) is a local denial of service vulnerability in whoopsie. An integer overflow when reading large crash reports (> 4GB) leads to a heap buffer overflow. I do not believe it is possible to exploit this heap buffer overflow to achieve code execution, so I have classified this bug as a denial of service. See [README_CVE-2019-11476](README_CVE-2019-11476.md).
7+
* [CVE-2019-11481](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11481) is a local denial of service vulnerability in apport. If `~/.config/apport/settings` is a symlink, then apport will read the target file, even if it requires root privileges to read. Apport usually errors out immediately after reading the file, though, so I do not believe it is possible to exploit this vulnerability in an interesting way. See [README_CVE-2019-11481](README_CVE-2019-11481.md).
8+
* [CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484) is a local privilege escalation vulnerability in whoopsie. An integer overflow when reading large crash reports (> 2GB) leads to a heap buffer overflow. I have written a simple PoC for this (see [README_CVE-2019-11484](README_CVE-2019-11484.md)), which just causes whoopsie to crash with a segmentation fault, and also a more sophisicated one which gains code execution as the whoopsie user by chaining CVE-2019-11484 with CVE-2019-15790 (see [README_CVE-2019-15790](README_CVE-2019-15790.md)).
9+
* [CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790) is an information disclosure vulnerability in apport. PID recycling enables an unprivileged user to generate and read a crash report for a privileged process. See [README_CVE-2019-15790](README_CVE-2019-15790.md).
710

8-
## Instructions
9-
10-
I usually try to provide a `Dockerfile` so that my PoCs are safely reproducible on a patched system. Unfortunately, Apport is specifically designed to behave differently inside a container, so I am not able to do so this time. Instead, if you would like to test the exploit, then you will need to revert the bug fix in your Apport installation. You can do that as follows:
11-
12-
```
13-
git clone https://git.launchpad.net/ubuntu/+source/apport
14-
cd apport
15-
git checkout applied/2.20.9-0ubuntu7.6
16-
sudo cp apport/report.py /usr/lib/python3/dist-packages/apport/report.py
17-
```
18-
19-
When you are done, don't forget to fix your installation:
20-
21-
```
22-
sudo apt-get install --reinstall python3-apport
23-
```
24-
25-
Build the PoC for Apport CVE-2019-7307 like this:
26-
27-
```
28-
make
29-
```
30-
31-
And run it like this:
32-
33-
```
34-
./gencrashreport /etc/shadow
35-
```
36-
37-
This will create a file named `/var/crash/_usr_share_apport_apport.0.crash`, which is owned by `root`, but also readable by `whoopsie`. For a full exploit chain, we would therefore also need a second exploit that enables us to read files as whoopsie. But since we don't have that yet, we need to change the permissions of the crash report:
38-
39-
```
40-
sudo chmod 666 /var/crash/_usr_share_apport_apport.0.crash
41-
```
42-
43-
At this point, you can unpack the crash report and see that the contents of `/etc/shadow` are embedded in the `CoreDump` file:
44-
45-
```
46-
mkdir report
47-
apport-unpack /var/crash/_usr_share_apport_apport.0.crash report
48-
cd report
49-
```
50-
51-
Note: `apport-unpack` is a bit flaky and usually crashes with an error message like this: `['ProcEnviron', 'UserGroups'] has no binary content`. But it works well enough to extract the core dump from the report. Now use your favorite text editor to open `CoreDump` and search for the contents of `/etc/password`. Searching for the string "root:" usually works.
11+
A lot of code is shared between the 5 PoCs, so I have put them all in this directory rather than creating a separate sub-directory for each PoC. But each PoC has its own README file, with instructions on how to build and run it.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Integer overflow in parse_report (whoopsie CVE-2019-11476)
2+
3+
[CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476)
4+
is a local denial of service vulnerability in
5+
[whoopsie](https://launchpad.net/ubuntu/+source/whoopsie).
6+
An integer overflow when reading large crash dumps (> 4GB) leads to a heap buffer overflow.
7+
I do not believe it is possible to exploit this heap buffer overflow to achieve code execution,
8+
so I have classified this bug as a denial of service.
9+
The full bug report is public on `bugs.launchpad.net`:
10+
[bug 1830863](https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830863).
11+
12+
## Instructions
13+
14+
Note: these reproduction steps will only work with a vulnerable version of whoopsie.
15+
See [CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476)
16+
for a list of vulnerable versions.
17+
18+
Build the PoC as follows:
19+
20+
```bash
21+
make
22+
```
23+
24+
And run it like this:
25+
26+
```bash
27+
./killwhoopsie1
28+
```
29+
30+
The PoC works by creating a file named `/var/crash/killwhoopsie.crash`,
31+
just over 4GB in size. It then creates a file named
32+
`/var/crash/killwhoopsie.upload`, which prompts whoopsie to start
33+
processing the .crash file. Be aware that whoopsie will keep restarting
34+
and crash repeatedly until you remove the files from `/var/crash`:
35+
36+
```bash
37+
rm /var/crash/killwhoopsie.*
38+
```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Symlink traversal in apport (CVE-2019-11481)
2+
3+
[CVE-2019-11481](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11481)
4+
is a local denial of service vulnerability in
5+
[apport](https://launchpad.net/ubuntu/+source/apport).
6+
If `~/.config/apport/settings` is a symlink,
7+
then apport will read the target file,
8+
even if it requires root privileges to read.
9+
Apport usually errors out immediately after reading the file, though,
10+
so I do not believe it is possible to exploit this vulnerability in an interesting way.
11+
The full bug report is public on `bugs.launchpad.net`:
12+
[bug 1830862](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1830862).
13+
14+
## Instructions
15+
16+
Please be aware that these instructions are likely to make your
17+
computer completely unresponsive for several minutes.
18+
19+
```bash
20+
make
21+
mkdir -p ~/.config/apport
22+
ln -s /dev/zero ~/.config/apport/settings
23+
./segv
24+
```
25+
26+
After running the exploit, don't forget to remove the malicious symlink:
27+
28+
```bash
29+
rm ~/.config/apport/settings
30+
```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Integer overflow in bson_ensure_space (whoopsie CVE-2019-11484)
2+
3+
[CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484)
4+
is an integer overflow in [whoopsie](https://launchpad.net/ubuntu/+source/whoopsie).
5+
The integer overflow is triggered by a large crash report (> 2GB) and leads to
6+
a subsequent heap buffer overflow.
7+
This file contains instructions for running the simple version of the proof-of-concept exploit,
8+
which just causes whoopsie to crash with a segmentation fault.
9+
A more sophisticated PoC, which can get a shell as the whoopsie user, is described in
10+
[README_CVE-2019-15790](README_CVE-2019-15790.md).
11+
The full bug report is public on `bugs.launchpad.net`:
12+
[bug 1830865](https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830865).
13+
14+
## Instructions
15+
16+
Note: these reproduction steps will only work with a vulnerable version of whoopsie.
17+
See [CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484)
18+
for a list of vulnerable versions.
19+
20+
Build the PoC as follows:
21+
22+
```bash
23+
make
24+
```
25+
26+
And run it like this:
27+
28+
```bash
29+
./killwhoopsie2
30+
```
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# PID recycling enables an unprivileged user to generate and read a crash report for a privileged process (apport CVE-2019-15790)
2+
3+
[CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790)
4+
is an information disclosure vulnerability in [apport](https://launchpad.net/ubuntu/+source/apport).
5+
PID recycling enables an unprivileged user to trick apport into
6+
generating a crash report containing the `/proc/[pids]/maps` belonging
7+
to a (newly started) privileged process.
8+
The vulnerabilty can be used to be obtain the ASLR offsets of any process,
9+
provided that we are able to control the startup time of the process.
10+
The PoC described here uses the
11+
vulnerability to obtain the ALSR offsets of the
12+
[whoopsie](https://launchpad.net/ubuntu/+source/whoopsie)
13+
process.
14+
The motivation for this is to complete the exploit chain described in
15+
[README_CVE-2019-7307](README_CVE-2019-7307.md):
16+
by exploiting
17+
[CVE-2019-7307](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7307),
18+
we can include the contents of an arbitrary file in a crash report,
19+
but that crash report is only readable by root or the whoopsie user.
20+
So to complete the exploit chain, we need to get code execution as the whoopsie user.
21+
22+
The PoC described here works by chaining the PID recycling vulnerability
23+
([CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790))
24+
with a heap buffer overflow vulnerability in whoopsie
25+
(see [README_CVE-2019-11484](README_CVE-2019-11484.md))
26+
to get a shell as the whoopsie user.
27+
The full bug report for CVE-2019-15790 is public on `bugs.launchpad.net`:
28+
[bug 1839795](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1839795).
29+
I have also recorded a
30+
[video](https://youtu.be/pbVtW3aTt7k)
31+
of the exploit in action.
32+
33+
## Instructions
34+
35+
Note: these reproduction steps will only work with a vulnerable versions of apport and whoopsie.
36+
See
37+
[CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790)
38+
for a list of vulnerable versions of apport and
39+
[CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484)
40+
for the vulnerable versions of whoopsie.
41+
42+
Build the PoC as follows:
43+
44+
```bash
45+
make
46+
```
47+
48+
And run it like this:
49+
50+
```bash
51+
./whoopsie_exploit 10
52+
```
53+
54+
You may need to tweak the command line argument,
55+
which is used to guess which PID whoopsie will get after it restarts.
56+
If the exploit consistently guesses too low then you may need to increase this number and vice versa.
57+
The logging messages printed by the exploit will give you more information about what's happening.
58+
59+
## Explanatory notes
60+
61+
The exploit takes several minutes to run.
62+
It's slow for several reasons:
63+
64+
1. The exploit needs to guess which PID whoopsie will get when it restarts. It takes about 3 tries on average to guess correctly.
65+
2. The exploit will only work if the base address of the mmap-ed region can be encoded as a UTF8 string. The base address is partially randomized due to [ASLR](https://en.wikipedia.org/wiki/Address_space_layout_randomization) and there is only a 32.6% chance that it will pass the UTF8 test, so we need to keep retrying until we get a suitable address.
66+
3. The behavior of whoopsie is affected by file events in `/var/crash`. Because apport creates files in `/var/crash`, I discovered that my exploit for apport was causing the whoopsie exploit to fail. I was able to solve the problem by slowing the apport exploit down, but that involved adding an extra 20 second delay.
67+
4. Once we have a suitable address, we have to trigger the heap overflow 5 times to overwrite the heap with a smaller number of fake gslice magazine chunks. The heap overflow takes just under 15 seconds each time, because it has to process 2GB of data.
68+
69+
The exploit is also somewhat unreliable.
70+
These are the main causes of unreliability that I am aware of:
71+
72+
1. Sometimes, the hashtable that is created in [parse_report](https://git.launchpad.net/ubuntu/+source/whoopsie/tree/src/whoopsie.c?id=import/0.2.62ubuntu1#n397) is allocated in the memory region that is corrupted by the heap buffer overflow. When this happens, the exploit causes whoopsie to crash immediately. (It's possible that corrupting the hashtable could be an alternative angle of attack for exploitation, but it happens relatively infrequently so I did not explore that option.)
73+
2. The offset of the magazine chunk that we need to corrupt seems to depend on the environment. For reasons that I never got to the bottom of, the offset is consistently `0x6f40` when I am in the office and `0x7040` when I am at home (same laptop, different locations). So if the exploit isn't working for you, then you might need to modify the value of [`magazine_offset`](whoopsie_exploit.cpp#L292) in `whoopsie_exploit.cpp`. For comparison, I have also included some sample memory dumps of the relevant memory region in the [memory_dumps](memory_dumps) sub-directory. (In the dumps named "home" the block is at offset `0x7040` and in the dumps named "work" the block is at offset `0x6f40`.)
74+
3. Sometimes [apport-gtk](https://launchpad.net/ubuntu/bionic/+package/apport-gtk) starts reading the 2GB crash report at an inconvenient moment and ruins the timing of the exploit. This is because [update-notifier](https://launchpad.net/ubuntu/bionic/+package/update-notifier) checks `/var/crash` [every 3 minutes](https://git.launchpad.net/ubuntu/+source/update-notifier/tree/src/update-notifier.c?h=ubuntu/bionic-updates#n444) and launches `apport-gtk` if there are any new files.
75+
4. The [final step](whoopsie_exploit.cpp:#L627) of the exploit relies on timing because it needs to trigger some events while whoopsie is in the middle of a 2GB [`memcpy`](https://git.launchpad.net/ubuntu/+source/whoopsie/tree/src/whoopsie.c?id=import/0.2.62ubuntu1#n507). The exploit is able to create a reasonably accurate [estimate](whoopsie_exploit.cpp#L687) of how long this will take by measuring how long the earlier exploit steps took, so I think this part of the exploit is fairly reliable but I don't know for sure.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# TOCTOU in _get_ignore_dom (apport CVE-2019-7307)
2+
3+
[CVE-2019-7307](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7307)
4+
is a time-of-check to time-of-use (TOCTOU) vulnerability in
5+
[apport](https://launchpad.net/ubuntu/+source/apport),
6+
which enables an unprivileged local user to trick apport into
7+
including the contents of an arbitrary file in a crash report.
8+
The full bug report is public on `bugs.launchpad.net`:
9+
[bug 1830858](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1830858).
10+
11+
## Instructions
12+
13+
I usually try to provide a `Dockerfile` so that my PoCs are safely reproducible on a patched system.
14+
Unfortunately, apport is specifically designed to behave differently inside a container,
15+
so I am not able to do so this time.
16+
Instead, if you would like to test the exploit,
17+
then you will need to revert the bug fix in your apport installation.
18+
You can do that as follows:
19+
20+
```bash
21+
git clone https://git.launchpad.net/ubuntu/+source/apport
22+
cd apport
23+
git checkout applied/2.20.9-0ubuntu7.6
24+
sudo cp apport/report.py /usr/lib/python3/dist-packages/apport/report.py
25+
```
26+
27+
When you are done, don't forget to fix your installation:
28+
29+
```bash
30+
sudo apt-get install --reinstall python3-apport
31+
```
32+
33+
Build the PoC for apport CVE-2019-7307 like this:
34+
35+
```bash
36+
make
37+
```
38+
39+
And run it like this:
40+
41+
```bash
42+
./gencrashreport /etc/shadow
43+
```
44+
45+
This will create a file named `/var/crash/_usr_share_apport_apport.0.crash`,
46+
which is owned by `root`, but also readable by `whoopsie`.
47+
For a full exploit chain, we therefore also need a second exploit that enables us to read files as whoopsie.
48+
I didn't have such an exploit when CVE-2019-7307 was disclosed on 2019-07-09, but I do now:
49+
see [README_CVE-2019-15790](README_CVE-2019-15790.md).
50+
But to keep these instructions self-contained,
51+
it is simplest to just change the permissions of the crash report:
52+
53+
```bash
54+
sudo chmod 666 /var/crash/_usr_share_apport_apport.0.crash
55+
```
56+
57+
At this point, you can unpack the crash report and see that the contents of `/etc/shadow` are embedded in the `CoreDump` file:
58+
59+
```bash
60+
mkdir report
61+
apport-unpack /var/crash/_usr_share_apport_apport.0.crash report
62+
cd report
63+
```
64+
65+
Note: `apport-unpack` is a bit flaky and usually crashes with an error message like this: `['ProcEnviron', 'UserGroups'] has no binary content`. But it works well enough to extract the core dump from the report. Now use your favorite text editor to open `CoreDump` and search for the contents of `/etc/password`. Searching for the string "root:" usually works.

0 commit comments

Comments
 (0)