Post

Basic MacOS Static Malware Analysis

Information and Techniques for Static Analysis of MacOS Malware and Persistence Mechanisms

Basic MacOS Static Malware Analysis

This doc has been heavily informed by the Objective by the Sea MacOS conference. I highly suggest you check out these links:

Objective See Foundation
Objective by the Sea Security Conference
The Art of Mac Malware Vol.1 (read for free online!)
The Art of Mac Malware Vol.2 (read for free online!)
Objective See Foundation Discord

Special thanks to for helping with this documentation.

Introduction

Before we dive into the exciting details, I would like to take a moment to discuss the present threat landscape for MacOS, as there are significant distinctions from the Windows threat landscape that we are more accustomed to.

In general, most of the malware you encounter on MacOS will consist of adware and info stealers. This is likely related to the heightened difficulty in running malicious code on the MacOS platform, along with the fact that MacOS threat actors are typically useless scrubs who lack creativity.

The purpose of adware is fairly obvious. Display ads or hijack clicks to generate revenue for threat actors. Adware is generally categorized as low but does come with persistence mechanisms on disk.

Stealers are much more severe in priority and will usually come in as high or crit, but generally do not drop persistence on disk as they have but one goal, steal creds, cookies, tokens, keychains, etc, then exfil and dip out. (“dip out” is philly for “leave”)

One quick note is that stealers are generally unimpressive and are most if not all running the same stolen Amos code under the hood, however, there has been some activity that shows us stealers may be expanding their capabilities to include remote control, but this is still incredibly rare. (But should be noted as a possible evolution of threat actor techniques.)

So let’s get into it, nerds.


General Info

Infection Vectors

Understanding common infection vectors is just as important as understanding the malware’s activity once on disk.

  • We have observed this on Windows. Sponsored advertisements for otherwise genuine software being offered as a trojanized variant on a deceptive yet credible website.
    • Advanced IP Scanner
    • RoyalTSX
    • WhatsApp
    • etc

Pirated Software

  • Pirated software is, to us, a fairly obvious way to catch an infection.
    • Keygens packed with malware.
    • Trojanized versions of the legitimate software.
    • Generally speaking, the method of providing the software for free will be packed with malware, whatever that method may be.

Fake Company Websites or Communications

  • Website, emails, or other communications offering books, documents, new tools, etc. to the target user end in phishing, trojanized tools, or malicious documents.

Word / Excel Macros

  • malicious_file.doc
    • Word or excel docs that come packed with malicious macros

Custom URL schemes

  • custom url schemes allow a threat actor to define a custom url path on disk to point url hooks like zoom:// to their own malicious path. These are usually packed into a .app package and fairly easy to find.
  • Removal (one method):
    • Quit chrome
    • Open ~/Library/Application Support/Google/Chrome/Default/Preferences
    • Search for the protocol_handler entry
    • Find the offending app/url and remove it
      • <https://evil.bad>":{"zoom":true}

Supply Chain Attacks

  • Targets the organization or software itself, instead of end user.
  • Can hit one target (zoom) and affect 758930275 end users.
  • Costs like 20 gold but gives like 400 victory points
  • See 3CX, NPM, etc

Etc.


Payload Types

AdInjectors

  • AppleScript (osascript) Injector
    • Loads ads into browser, usually with JS
    • Usually persists in the browser

CryptoMiners

  • Usually Monero
    • shocking -__-
  • Drops persistence

Remote Shells (interactive)

  • Example: OSX.Dummy
  • May drop persistence

Remote Execute

  • Example: OSX.Komplex
    • OSX.Komplex
    • Russian backdoor to execute binaries on system
  • May drop persistence

Collection / Exfil

  • Collects, zips, then yeets files (usually)
  • Easily observable process with Process Monitor
  • Can be financial in nature (extortion)

Ransomware

  • Encrypts files on disk
  • Financial in nature

Etc.

Great end-of-year-2023 report by Patrick Wardle: The Mac Malware of 2023


Persistence

My other blog on this subject: Mac the Ripper - Persistence

Persistence Types

  • Login Items
    • If you see usage of LSSharedFileList in malicious code, this API is most likely being used to create launch items.
  • LaunchDaemons
    • Requires root privs to create, executes as root
  • LaunchAgents
    • Root not required to write, does not execute as root
  • Cron Jobs
  • Login and Logout Hooks
  • Kernel Extensions (Kexts)
  • Browser Extensions
  • etc, see above documents for an in depth look at persistence.

Malware Examples:

Tools to Check Persistence:


PIDs (Special mention because they’re annoying on Mac)

The Mac operating system not only uses PIDs and parent PIDs like windows and linux systems, but there are a few more you may not be so familiar with. You can find these detailed below.

PID: This is your run of the mill process ID. Keep in mind, Launchd will always have a PID of 1. This is an issue you will see detailed below.

PPID: This is the Parent PID. It works exactly as you would expect.

PGID: This one is fun. This is the Process Group ID. This one is a lot easier to explain with an example. Let’s say you have a command with several pipes, like so: cmd.exe echo textfile.txt | grep something | sort | uniq. In this example each base command cmd.exe, grep, sort, and uniq will all have their own PIDs and you will have to climb the process tree to see the whole command. However, if we search for the PGID of any of these commands, we can find the rest of the pieces and put together the full command line. An example of how some of these may show in you log source:

Command Line:cmd.exe echo textfile.txt
PID:5520
PPID:5519
PGID:5518
  
Command Line:grep something
PID:5521
PPID:5520
PGID:5518
  
Command Line:sort
PID:5522
PPID:5521
PGID:5518
  
Command Line:uniq
PID:5523
PPID:5522
PGID:5518

Note how they all have the same PGID.

responsible_PID: This is another fun one. Explaining exactly what happens here may be a little difficult but I’ll give it my best shot. Lets pretend we have this process tree:

launchd > process 1 > process 2 > process 3 > process 4

Next let’s pretend process 2 was forked, and the original tree was killed. This would created a forked process 5 with a parentPID of launchd not process 2 since process 2 has been killed and our new process 5 is orphaned. The Mac operating system will identify an orphaned process and assign launchd to be its new adoptive parent. (aww so sweet).

image

That is not very good for our investigation as it completely nullifies our visibility of Process 1. In comes the responsible_PID. Even if a process is forked and the parent tree is killed, the responsible_pid will give us the PID information for the original parent tree, retaining our ability to properly investigate.

Here’s some beautiful art to help illustrate:

image


Static Analysis Techniques

Identifying File Type

We cannot always trust the file extension, determining the actual file type is easily step 1 of static analysis.

We can use the file command to determine the file type. (however, this can give you some weak info sometimes.)

image

A better tool is WhatsYourSign (Referred to beyond this point as WYS) which provides more clear file type info, as well as signing and notarization info.

image

image


Analyzing Common File Types

.dmg disk images

  • Needs to have .dmg file extension.
    • .dmg disk images cannot launch without the .dmg extension so these will usually always be distributed with this extension.
  • Might not be signed. a lot of legitimate disk images don’t get signed because reasons
  • May also be “legitimately” signed AND notarized by Apple proper, this does not imply legitimacy.
  • file command may fail here, WYS helps, see image:

image

  • Mount disk image for analysis purposes
    • hdiutil attach [file.dmg]
      • mounts to /volumes/ and can be cd’d into for pokin' and proddin'.

image

.pkg packages

  • pkgutil --expand file.pkg path/to/expand
    • This will export the package contents to the chosen path for you to poke around.
  • will usually have the .pkg extension
  • file may struggle, use WYS for more consistent results.
  • double clicking a .pkg file will execute it along with any pre/post install scripts embedded with it

image

  • Package Scripts
    • executed when a .pkg is launched
    • can be used to pack legitimate software with malicious scripts
    • can be viewed in SuspiciousPackage by going to the preinstall or postinstall tab.

image This postinstall script installs a cryptominer with Launchdaemon persistence

Python Scripts

  • .py or .pyc file extension
  • generally human readable
  • with base64, decode with cyberchef (or if exec exists at the end of the script, replace with print to receive output easily.)

image Repacing this exec with print would give you human readable output for the script

  • Simply decoding base64 blocks within scripts can sometimes give you quick wins. In this case we get a URL as well as a persistence name and location.

image

image Decoded pythin featuring a base64 block

image Decoded b64 block for a vaguely human readable output and an IOC

Application Bundles

  • .app file extension
    • Easily viewed with right click > view contents
      • directories, files, and subdirectories
    • info.plist file is interesting
      • points to apps binary
      • build envitonment
      • oldest supported os version
      • if the info.plist contents begin with bplist it has been compressed, you can uncompress wkth:
        • defaults read info.plist
        • plutil -convert xml11

For example, if we have the below compressed Info.plist, we can read it with defaults read info.plist

1
2
3
4
> file badness.app/Contents/Info.plist Info.plist: Apple binary property list
> cat badness.app/Contents/Info.plist
bplist00<DE>^A^B^C^D^E^F^G^H^K^L^M^N^O^P^Q^R^S^T^W^V^Y^ZESC^\^]^S_^P^ZCFBundleShortVers
ionString_^P^RCFBundleIdentifier_^p^] CFBundleInfoDictionaryVersion_^P^OCFBundleVersion ^p^RCFBundleExecutable_^p^VNSAppTransportSecurity_^P^PNS PrincipalClass [LSUIElement]...

Decompressed:

1
2
3
4
5
6
7
8
9
10
> defaults read badness.app/Contents/Info.plist
{
CFBundleDevelopmentRegion = en;
CFBundleExecutable = DropBox;
CFBundleIconFile = "AppIcon.icns"; 
CFBundleIdentifier = "inc.dropbox.com"; 
CFBundleInfoDictionaryVersion = "6.0"; 
CFBundleName = DropBox;
...
}

Conclusion

It’s no mistake that MacOS is growing in popularity for enterprise applicztions and eventually people who have only ever used windows and linux will have to investigate their first incident on a MacOS system. This blog only scratches the surface, and serves as more of a personal reference for myself than a formal blog, but I hope you find some of the information helpful.

Cheers, nerds! ^_^

This post is licensed under CC BY 4.0 by the author.