Wednesday, October 17, 2018


After a bit of a hiatus I hope to start blogging more regularly, or at least to get caught up on posting about various topics I have spoken on at recent conferences.  For those who missed it I spoke on script based malware including so-called "fileless" intrusions, and taught a related training at BSides-Pittsburgh in June.  Last week, I co-presented a talk at DerbyCon about hacking maritime SCADA.  I will be working on some posts related to those talks, both technical deep-dives, and sharing some of my experiences with "soft-skill" topics like presenting at conferences, writing CFP responses, talking to reporters, and coordinating ethical disclosure of vulnerabilities.

Friday, April 20, 2018

Part Three: Triage With Osquery and Obtaining Indicators

In this post, I’ll go more in-depth about how I used osquery to find the indicators in part two, and how to use the same technique for threat hunting on macOS.

Osquery Logs

There are two styles of results logs in osquery, snapshots and differential logs.  Snapshots are exactly what the name suggests, results of queries executed at a single point in time.  Differential logs only add a row when results of a query change.  As a simple example, I have created an osquery.conf file with scheduled queries for listening_ports and launchd tables.  Applying these configs gives us a differential log.

The first set of entries from launchd are the baseline.  This log can be saved or discarded.  For our purposes we just need the subsequent changes, which will list any new property lists added to the launchd paths.  We could get the same information without using osquery by running "launchctl list" and writing a script to parse it, but osquery is a convenient tool to use for this purpose.

The next step is to take a snapshot on my virtual machine, and then run the trojan PDF from part one. After the Mach-O binary executes, we see the decoy document appear.

Checking our osqueryd.results.log again, we can see we have a new row in our log.  Reading through the results we can see that indeed the malware has added a property list to our launch directory for persistence.  We can also see the paths we need to locate the property list, which will in turn yield the path to the persistent executable, as we saw in part two.

This is an extremely simple example of dynamic analysis.  The technique could be automated further with scripting to create our own custom "sandbox". With it we could quickly find low-hanging fruit indicators from our macOS malware sample, or from suspected phishing email attachment.  Additional tables can be added to monitor other potential persistence mechanisms like crontab, or even more stealthy methods like @xorrior's emond based persistence.

I am still exploring the capabilities of osquery for ways to detect other malicious behavior and indicators.  For example, I've been exploring the best way to capture network information using only osquery tables.  I experimented with the listening_ports table and found that it does indeed log processes listening on a port.  I am able to see, for instance the mDNSResponder service listening as expected on UDP port 5353.  Unfortunately, listening_ports does not address reverse-shells or other backdoor and C2 mechanisms.  

Another interesting table I have experimented with is file_events, and it seems to have some cool possibilities. One use case would be to create a substitute for Windows Security Event ID 4663, and use it for something like @neu5ron's canary files.  I'll keep exploring, and keep blogging about what I find. 

Monday, April 16, 2018

Part Two: Writing the Rules

Query Rules

As I said in part one, I began by checking the osx-attacks pack for existing rules.  While there were no rules to detect the newest APT32 associated variants, I used the pack as a template for writing my own.  Packs have only a few necessary elements.  The first element in the osx-attacks pack is a platform key that specifies the value for macOS ("darwin").  The next element, "queries", quite naturally contains the rules we want applied, formatted as a series of SQL queries.

Looking at the first rule, "Wirelurker", we see that it consists of a query selecting all columns from the table "launchd" where the row has a name value that ends in ".plist".  The other keys in the Wirelurker rule are pretty straight forward.  "Interval" specifies in seconds how often to run the query.  The "version" key is the minimum version of osquery compatible with this rule.  The two remaining fields, "value" and "description" are just optional meta-data for informational purposes.

Before going any further, a brief note on the syntax.  The osx attacks pack includes a bash-style backslash to indicate line continuation. Other example configuration files from the Facebook osquery repository include C-style comments (//).  These elements were compatible with the json parser in earlier versions of osquery, but may not be compatible with newer versions. The parser in version 3.1.0, the latest version installed by Brew as of my writing this post, throws errors on these non-compliant elements.  I have confirmed this via experimentation and talking to osquery developers via the Slack channels.

Now let's go back to that table "launchd", and answer "what is a .plist?" and "why are we looking for them?"  For additional information you can always check out my talks from BloomCon 2018 and BSides Columbus 2018.  The short answer is that property lists (.plist) and launchd are the way at least half of macOS malware variants, according to my own completely un-scientific estimate, achieve persistence.

 The more complete answer is that launch daemon (launchd) is the process started by kernel_task (pid 0) on startup (as pid 1) to ensure that other processes that need to run on startup on macOS get run.  Launchd accomplishes this by walking a set of special directories and parsing a set of special xml files, which are the startup "property lists".  These directories and property lists serve much the same function as the Windows' "run" and "run once" registry keys.

Within the .plist file for the APT32 variant shown here, a "RunAtLoad", "true" key-value pair ensures persistence through a shutdown or restart, while "KeepAlive", "true" key-value pair ensures the process is restarted if stopped.  Lastly, the "ProgramArguments", "/Users/thewoz/Library/Containers/" key-value pair gives us the full path of the Mach-O binary "hidd", which is written to disk in the victim's ~/Library/Containers folder and concealed with a "hidden" xattribute, which launchd is required to run on startup.

Using this information, we can create two rules for query pack.  The first will follow our osx-attacks pack template and query the launchd table to detect the presence of "", a good indicator of this variant.  The second rule will query the "file" table for that persistent Mach-O binary.  Results can either be logged locally to the default /var/osquery/log/osqueryd.results.log, or can be aggregated for ingestion by Splunk, LogStash, Fluentd, or other options.  But that will have to wait for a future post.

A final note, after writing my rules I ran them through, just to make sure I don't get any json parser related errors.  I would recommend it as a practice.   Yes, these are pretty static indicators, stick around for part three, where I will discuss more "flexible" queries.   Again, the full query pack can be found on my github repository.

Part Three: Triage With Osquery and Obtaining Indicators

Sunday, April 15, 2018

Writing Query Packs to Detect APT32's macOS Malware Variants: Part One

Recently, I decided to learn how to write my own query packs for osquery.  I’ve been spending a lot of time lately learning about macOS malware and osquery has proven to be a useful tool.  When I saw a report from Trend Micro of a new malware variant targeting macOS, it seemed like a good opportunity for some practice.

In this first part of a two three part post, I will go over some query pack basics and some info about macOS malware variants.  In part two I'll go over details on writing queries. In part three, I’ll go more in-depth about how I used osquery to find the indicators, and how to use the same technique for threat hunting on macOS.  

Query Packs

Osquery can be used in two modes, interactive and as a daemon.  When running as a daemon, lists of rules, supplied as external json files called query packs, can be applied. These query packs are applied by simply adding a file path to the “packs” section of the configuration file, /var/osquery/osquery.conf.

Before I started writing my own pack, I first checked the osx-attacks pack in osquery’s github master branch.  I didn’t find a signature for the new variant, but I figured this query pack would give me a good template to start from.

The Malware

The next step was to decide what signatures to include in my query pack and to find samples of the malware.  The variant reported in early April was attributed by Trend Micro to the activity FireEye dubs  Advanced Persistent Threat (APT) 32 / Ocean Lotus.  

I am usually pretty skeptical about both the value and accuracy of attribution in open-source “threat intelligence”.  Since the goal of this endeavor was simply to learn to build signatures for osquery, I decided to accept the community consensus and focus on putting together an “Ocean Lotus” query pack.

According to a FireEye report:

Since at least 2014, FireEye has observed APT32 associated ttps and malware targeting foreign corporations with a vested interest in Vietnam’s manufacturing, consumer products, and hospitality sectors...In addition to focused targeting of the private sector with ties to Vietnam, APT32 has also targeted foreign governments, as well as Vietnamese dissidents and journalists since at least 2013...

OK, so now that we know a little bit about APT32 activity, what malware is associated with it?  I was able to locate four variants of malware, specifically targeting macOS, publicly attributed to APT32 Ocean Lotus. 

The first variant is a trojan Mach-O binary disguised as a Flash update (SHA-256 12f941f43b5aba416cbccabf71bce2488a7e642b90a3a1cb0e4c75525abb2888).  This file in turn writes another binary, named "corevideosd" to disk (SHA-256 3d974c08c6e376f40118c3c2fa0af87fdb9a6147c877ef0e16adad12ad0ee43a).  For more information on activity related to these samples, refer to the Alien Vault post.

The second variant is a .zip archive containing a trojan Mach-O binary disguised as a Word document. (SHA-256 b33370167853330704945684c50ce0af6eb27838e1e3f88ea457d2c88a223d8b). This variant writes to disk a persistent Mach-O binary, "servicessl" (SHA-256 07154b7a45937f2f5a2cda5b701504b179d0304fc653edb2d0672f54796c35f7).  For more info, see the Unit 42  post.

The third variant was a trojan Mach-O binary, this time disguised as a PDF (SHA-256

Lastly, we have the most recent variant, a malicious Word document (SHA-2562bb855dc5d845eb5f2466d7186f150c172da737bfd9c7f6bc1804e0b8d20f22a) which drops the malicious Mach-O "spellagentd" (SHA-256 673ee7a57ba3c5a2384aeb17a66058e59f0a4d0cddc4f01fe32f369f6a845c8f). A detailed analysis was posted by Trend Micro.

Luckily, Patrick Wardle has posted samples of most of these variants on his Objective-See blog. For the remaining sample, a hat-tip goes to @acalarch for helping me out.

The query pack can be found on Github, I hope you'll stick around for Part Two.

Part Two, Writing the Rules