Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
gencrashreport
killwhoopsie1
killwhoopsie2
segv
whoopsie_exploit
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
all: gencrashreport killwhoopsie1
all: gencrashreport killwhoopsie1 killwhoopsie2 segv whoopsie_exploit

gencrashreport: gencrashreport.cpp utils.cpp
g++ -Wall -O2 gencrashreport.cpp utils.cpp -o gencrashreport

killwhoopsie1: killwhoopsie1.cpp utils.cpp
g++ -Wall -O2 killwhoopsie1.cpp utils.cpp -o killwhoopsie1

killwhoopsie2: killwhoopsie2.cpp utils.cpp
g++ -Wall -O2 killwhoopsie2.cpp utils.cpp -o killwhoopsie2

segv: segv.c
gcc -Wall -O2 segv.c -o segv

whoopsie_exploit: whoopsie_exploit.cpp restart_whoopsie.cpp load_crash_report.cpp encoding.c utils.cpp
g++ -Wall -O2 whoopsie_exploit.cpp restart_whoopsie.cpp load_crash_report.cpp encoding.c utils.cpp -o whoopsie_exploit

clean:
rm -f gencrashreport killwhoopsie1
rm -f gencrashreport killwhoopsie1 killwhoopsie2 segv whoopsie_exploit
Original file line number Diff line number Diff line change
@@ -1,51 +1,11 @@
# Ubuntu Apport TOCTOU (CVE-2019-7307) and whoopsie heap buffer overflow (CVE-2019-11476)
# Vulnerabilities in Ubuntu's apport and whoopsie components (CVE-2019-7307, CVE-2019-11476, CVE-2019-11481, CVE-2019-11484, CVE-2019-15790)

This directory contains proof-of-concept exploits for vulnerabilities in Ubuntu's crash reporting system:
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:

* [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).
* [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).
* [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).
* [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).
* [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).
* [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)).
* [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).

## Instructions

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:

```
git clone https://git.launchpad.net/ubuntu/+source/apport
cd apport
git checkout applied/2.20.9-0ubuntu7.6
sudo cp apport/report.py /usr/lib/python3/dist-packages/apport/report.py
```

When you are done, don't forget to fix your installation:

```
sudo apt-get install --reinstall python3-apport
```

Build the PoC for Apport CVE-2019-7307 like this:

```
make
```

And run it like this:

```
./gencrashreport /etc/shadow
```

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:

```
sudo chmod 666 /var/crash/_usr_share_apport_apport.0.crash
```

At this point, you can unpack the crash report and see that the contents of `/etc/shadow` are embedded in the `CoreDump` file:

```
mkdir report
apport-unpack /var/crash/_usr_share_apport_apport.0.crash report
cd report
```

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.
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Integer overflow in parse_report (whoopsie CVE-2019-11476)

[CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476)
is a local denial of service vulnerability in
[whoopsie](https://launchpad.net/ubuntu/+source/whoopsie).
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`:
[bug 1830863](https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830863).

## Instructions

Note: these reproduction steps will only work with a vulnerable version of whoopsie.
See [CVE-2019-11476](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11476)
for a list of vulnerable versions.

Build the PoC as follows:

```bash
make
```

And run it like this:

```bash
./killwhoopsie1
```

The PoC works by creating a file named `/var/crash/killwhoopsie.crash`,
just over 4GB in size. It then creates a file named
`/var/crash/killwhoopsie.upload`, which prompts whoopsie to start
processing the .crash file. Be aware that whoopsie will keep restarting
and crash repeatedly until you remove the files from `/var/crash`:

```bash
rm /var/crash/killwhoopsie.*
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Symlink traversal in apport (CVE-2019-11481)

[CVE-2019-11481](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11481)
is a local denial of service vulnerability in
[apport](https://launchpad.net/ubuntu/+source/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.
The full bug report is public on `bugs.launchpad.net`:
[bug 1830862](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1830862).

## Instructions

Please be aware that these instructions are likely to make your
computer completely unresponsive for several minutes.

```bash
make
mkdir -p ~/.config/apport
ln -s /dev/zero ~/.config/apport/settings
./segv
```

After running the exploit, don't forget to remove the malicious symlink:

```bash
rm ~/.config/apport/settings
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Integer overflow in bson_ensure_space (whoopsie CVE-2019-11484)

[CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484)
is an integer overflow in [whoopsie](https://launchpad.net/ubuntu/+source/whoopsie).
The integer overflow is triggered by a large crash report (> 2GB) and leads to
a subsequent heap buffer overflow.
This file contains instructions for running the simple version of the proof-of-concept exploit,
which just causes whoopsie to crash with a segmentation fault.
A more sophisticated PoC, which can get a shell as the whoopsie user, is described in
[README_CVE-2019-15790](README_CVE-2019-15790.md).
The full bug report is public on `bugs.launchpad.net`:
[bug 1830865](https://bugs.launchpad.net/ubuntu/+source/whoopsie/+bug/1830865).

## Instructions

Note: these reproduction steps will only work with a vulnerable version of whoopsie.
See [CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484)
for a list of vulnerable versions.

Build the PoC as follows:

```bash
make
```

And run it like this:

```bash
./killwhoopsie2
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# PID recycling enables an unprivileged user to generate and read a crash report for a privileged process (apport CVE-2019-15790)

[CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790)
is an information disclosure vulnerability in [apport](https://launchpad.net/ubuntu/+source/apport).
PID recycling enables an unprivileged user to trick apport into
generating a crash report containing the `/proc/[pids]/maps` belonging
to a (newly started) privileged process.
The vulnerabilty can be used to be obtain the ASLR offsets of any process,
provided that we are able to control the startup time of the process.
The PoC described here uses the
vulnerability to obtain the ALSR offsets of the
[whoopsie](https://launchpad.net/ubuntu/+source/whoopsie)
process.
The motivation for this is to complete the exploit chain described in
[README_CVE-2019-7307](README_CVE-2019-7307.md):
by exploiting
[CVE-2019-7307](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7307),
we can include the contents of an arbitrary file in a crash report,
but that crash report is only readable by root or the whoopsie user.
So to complete the exploit chain, we need to get code execution as the whoopsie user.

The PoC described here works by chaining the PID recycling vulnerability
([CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790))
with a heap buffer overflow vulnerability in whoopsie
(see [README_CVE-2019-11484](README_CVE-2019-11484.md))
to get a shell as the whoopsie user.
The full bug report for CVE-2019-15790 is public on `bugs.launchpad.net`:
[bug 1839795](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1839795).
I have also recorded a
[video](https://youtu.be/pbVtW3aTt7k)
of the exploit in action.

## Instructions

Note: these reproduction steps will only work with a vulnerable versions of apport and whoopsie.
See
[CVE-2019-15790](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-15790)
for a list of vulnerable versions of apport and
[CVE-2019-11484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11484)
for the vulnerable versions of whoopsie.

Build the PoC as follows:

```bash
make
```

And run it like this:

```bash
./whoopsie_exploit 10
```

You may need to tweak the command line argument,
which is used to guess which PID whoopsie will get after it restarts.
If the exploit consistently guesses too low then you may need to increase this number and vice versa.
The logging messages printed by the exploit will give you more information about what's happening.

## Explanatory notes

The exploit takes several minutes to run.
It's slow for several reasons:

1. The exploit needs to guess which PID whoopsie will get when it restarts. It takes about 3 tries on average to guess correctly.
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.
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.
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.

The exploit is also somewhat unreliable.
These are the main causes of unreliability that I am aware of:

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.)
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`.)
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.
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# TOCTOU in _get_ignore_dom (apport CVE-2019-7307)

[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](https://launchpad.net/ubuntu/+source/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`:
[bug 1830858](https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1830858).

## Instructions

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:

```bash
git clone https://git.launchpad.net/ubuntu/+source/apport
cd apport
git checkout applied/2.20.9-0ubuntu7.6
sudo cp apport/report.py /usr/lib/python3/dist-packages/apport/report.py
```

When you are done, don't forget to fix your installation:

```bash
sudo apt-get install --reinstall python3-apport
```

Build the PoC for apport CVE-2019-7307 like this:

```bash
make
```

And run it like this:

```bash
./gencrashreport /etc/shadow
```

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 therefore also need a second exploit that enables us to read files as whoopsie.
I didn't have such an exploit when CVE-2019-7307 was disclosed on 2019-07-09, but I do now:
see [README_CVE-2019-15790](README_CVE-2019-15790.md).
But to keep these instructions self-contained,
it is simplest to just change the permissions of the crash report:

```bash
sudo chmod 666 /var/crash/_usr_share_apport_apport.0.crash
```

At this point, you can unpack the crash report and see that the contents of `/etc/shadow` are embedded in the `CoreDump` file:

```bash
mkdir report
apport-unpack /var/crash/_usr_share_apport_apport.0.crash report
cd report
```

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.
Loading