|
| 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. |
0 commit comments