Leveraging Apple’s Game Engine to Detect Threats

Leveraging Apple’s Game Engine to Detect Threats

To detect new Mac malware, a behavior-based approach is needed. This talk will discuss our open-source monitoring framework which passively collects system events, and will then detail our rule-based system that leverages Apple’s game engine to quickly and efficiently apply rules against these collected events. End result? A comprehensive, extensible detection, response and threat hunting platform.


patrick wardle

March 05, 2019


  1. #RSAC SESSION ID: HTA-T08 What’s Your Game Plan? 

    Apple’s Game Engine to Detect Threats Co-Founder, Digita Security Patrick Wardle
  2. #RSAC WHOIS @patrickwardle + JOSH STEIN JON MALM } research

    (free!) tools
  3. #RSAC Outline Threats (malware & bugs) Monitoring 
 ("MonitorKit") Detection

  4. (Recent) Mac Malware Threats

  5. #RSAC The Reality Macs are no more resistant to malware,

    than their (modern) Windows counterparts. 93% 7% "ok, then why not more mac malware!?" 7.1% of personal computer market (Q2 2018, Gartner) ...what makes the most money?
  6. #RSAC Macs vs. Malware "Mac-specific malware increased by 270% in

    2017 compared with 2016, and four new Mac threats were detected in the first two months of 2018" -Malwarebytes 2017/2018 malware/adware continues to proliferate
  7. #RSAC OSX.FruitFly (2017) spying on victims (children) for over a

    decade $ cat fpsaud #!/usr/bin/perl use strict;use warnings;use IO::Socket;use IPC::Open2;my$l;sub G{die if!defined syswrite$l,$_[0]}sub J{my($U, $A)=('','');while($_[0]>length$U){die if!sysread$l,$A,$_[0]-...... "For more than 13 years, Phillip Durachinsky allegedly infected with malware the computers of 1000s of Americans and stole their most personal data and communications" -Assistant Attorney General backdoor (obfuscated perl)
  8. #RSAC OSX.MaMi (2018) a dns hijacker…ported from Windows? installs (root)

    certificate modifies DNS server settings Mac port of 'Win32.DNSUnlocker'? 'same' malicious DNS servers identical certificate thumbprint
  9. #RSAC OSX.AppleJeus (2018) lazarus group's (n. korea) first macOS implant

    updater (malicious) + Celas Trade Pro, from "Celas Limited" fake company!
  10. #RSAC OSX.WindShift (2018) file exfiltration implant , with a unique

    infection vector yan { [self yoop:@"BouCfWujdfbAUfCos/iIOg=="]; [self yoop:@"Bk0WPpt0IFFT30CP6ci9jg=="]; [self yoop:@"RYfzGQY52uA9SnTjDWCugw=="]; [self yoop:@"XCrcQ4M8lnb1sJJo7zuLmQ=="]; … Read: "Analyzing WindShift's Implant: OSX.WindTail (part 1 & 2)" -digitasecurity.com encrypted file extensions persistence doc, docx, xls, xlsx, ppt, pdf, db, txt, rtf, pptx infection }
  11. #RSAC OSX.CreativeUpdate (2018) cryptominer distributed via 'macupdate.com' not mozilla! $

    cat ~/Library/LaunchAgents/MacOS.plist <key>ProgramArguments</key> <array> <string>sh</string> <string>-c</string> <string> ~/Library/mdworker/mdworker 
 -user walker18@protonmail.ch -xmr </string> </array> ... persistent cryptominer (xmr) macupdate.com security alert ...previously at RSA
  12. #RSAC The Mac Malware of 2018 digitasecurity.com/ blog/2019/01/01/malware2018/ infection vector

    persistence mechanism capabilities / payload samples (for download) a comprehensive report on infection, persistence, and capabilities
  13. (Recent) Mac Vulnerabilities Threats

  14. #RSAC The Reality Macs are just as susceptible to vulnerabilities

    as their (modern) Windows counterparts ...if not more so! market rates for 0days (2019) wise words from @thegrugq <
  15. #RSAC CVE-2017-7149: Password Exposure for encrypted volumes: hint == password!?

    (@martiano_) [SKHelperClient addChildVolumeToAPFSContainer: ...password: passwordHint: ...] //save password if(password != nil) [infoDictionary setObject:password forKey:@"kSKAPFSDiskPasswordOption"]; //save password hint if(passwordHint != nil) [infoDictionary setObject:password forKey:@"kSKAPFSDiskPasswordHintOption"]; password value stored in 'hint' key create encrypted AFPS volume set (any) password hint later:'Show Hint' 
 ...reveals password! cut & paste fail? }
  16. #RSAC CVE-2017-13872: #iamroot click twice, get root...no really! 0day on

    Apple's forums!? proof of concept //verify int match = kODErrorCredentialsInvalid; if(kODErrorSuccess != od_verify_crypt_password(accountHash, providedPassword, &match, ...){ //error goto bail; } //ok happy! // allow authentication/login 'match' variable never checked never checked!
  17. #RSAC CVE-2018-4407: pure remote ring-0!? heap-overflow in (kernel) packet handling

    (@kevin_backhouse) "Kernel RCE caused by buffer overflow in Apple's ICMP packet handling code (CVE-2018-4407)" -https://lgtm.com/blog/ } remote ring-0 no-user interaction
  18. #RSAC CVE-2019-6223: #FacePalm audio/video streamed before the call is confirmed

    streamed, before call is answered :( 0day on Twitter …in the New York Times patch (callservicesd)
  19. #RSAC 0day: 'KeySteal' dump all things from the keychain (@linushenze)

    private keys passwords dump the macOS keychain
  20. #RSAC The Mac App Store ...unfortunately, not safe either! "The

    safest place to download apps for your Mac is the Mac App Store. Apple reviews each app before it’s accepted" "Adware Doctor" #4 @privacyis1st -apple.com "Adware Doctor" to .CN?
  21. an open-source macOS monitoring framework Monitoring (MonitorKit)

  22. #RSAC An Overview MonitorKit process file monitor all things (events)

    download screen capture usb synthetic-click keylogging webcam/mic login standardized events
  23. #RSAC Process Monitoring via OpenBSM auditing "[applications can] tap into

    the audit stream...the kernel provides a character device: /dev/auditpipe" -j. levin connect to: 
 /dev/auditpipe set 'events' of interest: AUDIT_CLASS_EXEC
 AUDIT_CLASS_PROCESS read & tokenize header body trailer struct tokenstr { u_char id; 
 u_char *data; size_t len; union {} tt; } } au_header au_subject au_path_t au_execarg_t
  24. #RSAC Process Monitoring via OpenBSM auditing //events of interest (process

    events!) let mask: u_int = AuditConstants.AUDIT_CLASS_PROCESS | AuditConstants.AUDIT_CLASS_EXEC //but only start/stop events let filter: [UInt16] = [ UInt16(AUE_EXEC), UInt16(AUE_EXIT), UInt16(AUE_FORK), UInt16(AUE_EXECVE), UInt16(AUE_POSIX_SPAWN) ] //init monitor // tokenize and print if let monitor = try? BSMMonitor(mask, recordFilter: filter) { monitor.start { (record: BSMRecord) in for token in record.tokens { print("Token \(token.tokenString()):\n \(token.stringValue())") } } } raw OpenBSM process monitoring //start process monitor // monitor for process start/end events if let monitor = try? ProcessMonitor() { monitor.start { (event: ProcessEvent) in 
 if event.type == .CREATE { print("Process with pid \(event.pid) created") } else if event.type == .EXIT { print("Process with pid \(event.pid) exited") } } } abstracts OpenBSM: reading, tokenization, etc... ProcessMonitor fully abstracts OpenBSM 'ProcessEvent': create 'ProcessEvent': exit
  25. #RSAC File Monitoring via FSEvents connect to: /dev/fsevents set 'events'

    of interest: FSE_CREATE_FILE
 FSE_DELETE read & tokenize events file create file delete etc... let monitor = FileMonitorFSE() public static let filter = [ FSEventTypes.CREATE_FILE.rawValue, FSEventTypes.DELETE.rawValue, ... ] monitor.start(eventFilterInclude: filter) { event in print("\(event.pid) \(event.type.string) \ (event.path)") } Apple's FSEvents API: no pid for the file i/o event :( FileMonitor abstracts fsevents internals
  26. #RSAC Download Monitoring via Spotlight Notifications "NSMetadataQueryDidUpdate" Spotlight //register for

    NSMetadataQueryDidUpdate // item of interest: NSMetadataItemWhereFromsKey public class DownloadMonitor: BaseSpotlightMonitor<DownloadEvent> { public init() { super.init(predicate: NSPredicate(format: "%K like ‘*'", NSMetadataItemWhereFromsKey), forNotification: NSNotification.Name.NSMetadataQueryDidUpdate) } } new file downloaded DownloadMonitor //init/start monitoring DownloadMonitor().start() { event in print("Downloaded File \(event.path)") }
  27. #RSAC Keylogger Monitoring via Core Graphics Event Notifications "kCGNotifyEventTapAdded" //register

    for kCGNotifyEventTapAdded public class EventTapsMonitor: NSObject { public func start(eventHandler: @escaping EventTapsHandler) {
 //register for notification notify_register_dispatch(kCGNotifyEventTapAdded, &self.notifyToken, DispatchQueue.global()) { [weak self] event in
 //report any new taps! for newTap in newTaps.keys where nil == strongSelf.previousTaps[newTap] { if let tap = newTaps[newTap] { eventHandler(EventTapsEvent(tap: tap)) } } … EventTapsMonitor new event tap (keylogger) //init/start monitoring EventTapsMonitor().start() { event in print("new keyboard event tap \(event.source)") }
  28. #RSAC Synthetic Click Monitoring via a (passive) Core Graphics event

    tap allow access keychain? "synthetic click" ...in the news source pid "state"
 (0x1 if synthetic)
  29. #RSAC Cam/Mic Monitoring via AVFoundation notification(s) OSX.Crisis OSX.Eleanor OSX.Mokes OSX.FruitFly

    public class AudioVideoMonitor: NSObject { public func start(eventHandler: @escaping AudioVideoHandler) { var property = CMIOObjectPropertyAddress( mSelector: kAudioDevicePropertyDeviceIsRunningSomewhere, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster) CMIOObjectAddPropertyListener(camID, &property, camCallback, Unmanaged.passUnretained(self).toOpaque()) AudioVideoMonitor.start() { event in print("NEW A/V EVENT") print("type: ", event.type) print("name: ", event.name) print("state: ", event.state) } $ ./monitorAV NEW A/V EVENT type: mic name: Built-in Microphone state: 1 (On) NEW A/V EVENT type: cam name: FaceTime HD Camera state: 1 (On) AudioVideoMonitor }
  30. #RSAC MonitorKit monitor all things iokit notifications openbsm monitoring fs

    events core graphic events spotlight notifications core graphic taps av foundation notifications MonitorKit standardized events 100% user-mode open-source
  31. ...by leveraging apple's game logic engine Detection (GamePlan)

  32. #RSAC So far... mac threats monitor all things [MonitorKit] }

    malware exploits detect (all?) things efficiently:
 many events, complex rules contextually: structured output, w/ history flexibly: modify/add detections w/o code
  33. #RSAC Game (Logic) Engine sensor(s) modeled events state actuators logic

    controller (Σ logic blocks) src:docs.blender.org play! pieces of the puzzle
  34. #RSAC Game (Logic) Engine: (re)Applied cache MonitorKit analytics actions (alert,

    log, etc) missing piece
  35. #RSAC Apple's "GameplayKit" State Machines Components Randomization Strategists Goals, Behaviors

    Pathfinding Rule Systems Rule Systems 
 (GKRuleSystem): "allows a list of [logic blocks], together with context for evaluating them and interpreting results, for use in constructing data-driven logic or fuzzy logic systems" Apple's Game Engine Framework "separates game design from executable code" ...this "Rule System" is really a logic controller (applicable to analytics)!? "GameplayKit"
  36. #RSAC GKRuleSystem Class pac-man's ghosts, as an example define &

    load ghost logic (re)evaluate game logic respond to output of engine evaluation //init logic system let sys = SimpleLogicSystem() sys.update(powerPellet: true)
 //later sys.update(powerPellet: false) "run, Forest, run!" "lets go hunting" (abridged) ghost logic "chase" mode: ...hunt pacman "frightened" mode: ...run!
  37. #RSAC GKRuleSystem Class "allows a list of [logic blocks], together

    with context for evaluating them and interpreting results, for use in constructing data-driven logic or fuzzy logic systems" "allows a list of [logic blocks]" rules, (or in Apple parlance: NSPredicates) "context for evaluating them and interpreting results" "for use in constructing data-driven logic...systems" regex, etc.
  38. #RSAC "Game Plans" defining predicates (rules) across the Mitre ATT&CK

    Framework Initial Access Execution Persistence Privilege Escalation Defense Evasion Credential Access Discovery Lateral Movement Collection Exfiltration Command & Control LuLu KnockKnock BlockBlock ReiKey }
  39. #RSAC $event.isNewDirectory == 1 AND ( $event.path MATCHES[cd] "/System/Library/Extensions/[^/]*" OR

    $event.path MATCHES[cd] "/Library/Extensions/[^/]*" ) -> Persist, Kext Developing "Game Plans" detecting methods of persistence Objective-See's BlockBlock ... -> Persist, Kext ... -> Persist, Launch ... -> Persist, EventMonitor ... -> Persist, AppLoginItem ... -> Persist, LoginItem ... -> Persist, CronJob ... -> Persist, StartupItem ... -> Persist, LoginHook ... -> Persist, SpotlightImporter ... -> Persist, SecurityAgentPlugin ... -> Persist, DYLDInsert(App) ... & "Launch" -> Persist, DYLDInsert(LaunchD) malware persistence techniques Kext Persistence Logic block: NSPredicate over data model file events (MonitorKit) labeled (by logic block)
  40. #RSAC Chaining Logic Blocks ...for more accurate and actionable detection

    label: persisted "how am I supposed to know I should click 'block'" logic block: 
 code signing logic block: 
 persist && 
 (!Apple && !AppStore) alert! + label: 
 signing info
  41. #RSAC Advanced Behavioral Detections towards generic ransomware detection file modification

 (i.e. in /Users/*) process is non-Apple file contents encrypted multiple encrypted files ransomware detection algorithm (objective-see.com/blog/blog_0x0F.html) } $event.isModified == TRUE AND $event.path MATCHES[cd] "/Users/*" AND !$event.process.labels.contains("AppleSigned", "AppStore") AND $event.contents.encrypted == TRUE untrusted encryption $event.labels.contains("UntrustedEncrypt") AND @SUBQUERY(cache, $e, $e.date > (X sec ago) AND $e.process.pid == $event.process.pid).@count > 3 -> Ransomware multiple encryption previous tag/label ransomware
  42. #RSAC $event.isNew == 1 AND $event.file.onRemovableMedia == 0 AND $event.path

    MATCHES[cd] \"/Volumes/.*\" Profiles/Rule "Flavors" an example: detect malicious insiders Goal: detect "insider threat" USB writes $event.path == "/usr/bin/sudo" 'sudo' usage screen captures after-hours activity suspicious insider } alert !
  43. #RSAC Detect (All?) Things hail the power of the predicate!

    ($event.isModified == 1 OR $event.isNew == 1) AND 
 ($event.path BEGINSWITH[cd] '/System/' OR $event.path BEGINSWITH[cd] '/usr/' OR $event.path BEGINSWITH[cd] '/bin/' OR $event.path BEGINSWITH[cd] '/sbin/') AND NOT ($event.path BEGINSWITH[cd] '/usr/local/') AND event.file.isExecutable AND
 $event.file.signingInfo.signerType != Apple $event.type == file.delete AND $event.process.path == $event.path self-deletion
 (malware) $event.type == file.create AND $event.path MATCHES[cd] "/Users/.*/ Library/Logs/DiagnosticReports/*" crash reports (anti-exploitation) SIP bypasses (anti-exploitation)
  44. #RSAC Threat Hunting collect, hunt, mitigate ...repeat stream events }

    deploy (new) rule hunt!
  45. #RSAC GamePlan ...detect all things? alerts

  46. #RSAC GamePlan create, edit, manage analytics (rules) analytic (rules) interface

    edit analytic
  47. #RSAC GamePlan real-time audit/compliance insights CIS Security Benchmark

  48. ...mac malware / exploits! GamePlan vs.

  49. #RSAC Known Mac Malware rules (predicates) to detect known threats

    OSX.iWorm "LaunchD" IN $tags AND $context.Name.value == "com.javaw.plist" OSX.Eleanor "LaunchD" IN $tags AND $context.Name.value in { "com.getdropbox.dropbox.timegrabber.plist", "com.getdropbox.dropbox.usercontent.plist"}
  50. #RSAC OSX.FruitFly building a better trap (install time) ($event.path MATCHES[cd]

    "/Library/LaunchAgents/.*.plist" OR $event.path MATCHES[cd] "/Users/.*/Library/LaunchAgents/.*.plist") AND $event.isNewFile == 1 !$event.file.contentsAsDict.ProgramArguments[0].signingInfo("AppleSigned") launch agent persistence $ cat ~/Library/LaunchAgents/ com.client.client.plist ...
 <plist version="1.0"> <dict> <key>ProgramArguments</key> <array> <string> ~/.client </string> </array> ... "LaunchD" IN $tags AND $event.file.contentsAsDict.ProgramArguments[0]. lastPathComponent.startsWith(".") launch item persistence not signed by apple 'hidden' binary alert !
  51. #RSAC OSX.FruitFly building a better trap (runtime time) $event.process.path.lastPathComponent.startsWith(".") $event.process.path.startsWith("/tmp")

    $event.process.labels.contains("Unsigned") + webcam synthetic clicks + + ...other generic detection predicates!? hidden process dropper payload in /tmp unsigned process +
  52. #RSAC OSX.WindShift detecting initial exploitation vector $ cat Final_Presentation.app/Contents/Info.plist <plist

    version="1.0"> <dict> ... <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>openurl2622007</string> </array> </dict> </array> $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 dir app with custom URL handler
  53. #RSAC OSX.MaMi (2018) detecting dns hijacking (and self-deletion) hijacked DNS

    settings modified DNS alert self-deletion alert alert !
  54. #RSAC *.Adware ...our favorite generic detector! $event.process.path.contains("Adobe") OR $event.process.path.contains("Flash") contains

    "Adobe" or "Flash" !($event.process.sigtype == Dev AND $event.process.signer != "Adobe Systems, Inc.") ...but is not signed by Adobe alert !
  55. Conclusions

  56. #RSAC Apply! Yes, Macs are hackable and rather susceptible to

    malware... Peruse the MonitorKit source code [ to be posted shortly on GitHub ] Deploy a product such as GamePlan to detect: mac exploitation malicious insiders mac malware (known & unknown) }
  57. #RSAC Finale @patrickwardle Digita Security cybersecurity solutions for the mac

    enterprise CleanMyMac X Guardian Mobile Firewall On a personal note: Mahalo to the: "Friends of Objective-See"
  58. #RSAC One more thing... Announcing OBTS 2.0: the world's only

    mac security conference June 1-2 Monaco ObjectiveByTheSea.com Free