Vulnerability #1 lies within Authd, which is part of an open source framework that handles authorization, authentication and privileged process spawning. While looking through the source code, a funny function group of code was noticed that copies the security entitlements. This code just copies the entitles without doing a signature check!
This means that arbitrary entitlements can be created and sent to Authd to give those permissions away. Although this entitlements should be used all the time, several Apple specific frameworks ignore them and just require a password.
There are a list of privileges that the author found to be usable without the password check from other frameworks. The important one (that actually worked) was system.install.* rights. This only allows for Apple signed packages to be installed at arbitrary locations :( So, we will need another bug.
Several Apple signed packages exist online that are sort of weird! Eventually, after scouring the internet, a package was found that had a command injection as parameter 3 of a bash script, which could allow us to escalate up to a root.
Now, on to the final vulnerability... SIP (System Integrity Protection) is used to ensure that only Apple signed binaries are run and do not alter important parts of the Kernel, such as the OS. The kextutil is what is used to load Kernel extensions.
When
kextutil loads a kernel extension it does the following:
- Copies the kernel extension to a non-modifiable directory, which is SIP protected.
- Verifies the signature of the extension.
- Reopens the extension to load and start it.
So what's the issue here?
There are TWO points here where the file is opened: it is opened to verify and opened to run! So, there is a classic time of check-time of use (TOCTOU) bug here! If the file is altered after the signature check, then a non-verified file will be ran! Because we have root permissions from the first two vulnerabilities, we can alter the file prior to it loading :)
But this is not deterministic, is it? We are training to win a race here. Well, there is an awesome trick that the author used to always win the race! The kextutil function has a built-in interactive mode for loading kernel drivers. While loading the driver with the interactive mode, the signature is verified. Now, all you have to do is alter the driver to be whatever we want, load it in the interactive shell and we have kernel code execution! This interactive nature makes it trivial to hit the window for altering the file.
Privilege escalation in OS's does not always have to be memory corruption! Sometimes, it is just poorly written logic in multiple places that allows for this to happen.