Note: The attack procedure built in this post will not work for every macOS operating system or in every scenario. There are many factors that can block scripts from running at boot time, and you should always test against your target operating system.
The MITRE ATT&CK framework is a universally accepted knowledge-base of tactics, techniques and procedures designed to organize and display how adversaries attack real-world assets. Blue teams use ATT&CK to better understand the multitude of new (and old) attacks and map those to their internal tools and systems. Red teams can use ATT&CK as a sort of playbook, using specific “plays” (combinations of TTPs) to try and test their systems, which can be easily communicated to the rest of the security team.
Digging into some terminology:
- A tactic is what an attacker hopes to achieve.
- A technique is how an attacker plans to achieve or execute the tactic.
- A procedure is a specific implementation of the technique.
Sound confusing? Let’s walk through an example:
An attacker may execute a Collection tactic to steal data from a computer, picking the Clipboard Data (T1115) technique and executing the Get-Clipboard PowerShell cmdlet as the procedure to complete the action.
ATT&CK helps defenders in a variety of ways:
- It offers a common language to discuss tactics, techniques and procedures.
- It provides a dynamic kill-chain for blue team members to detect and respond.
- It supplies resources related to threat groups and the behaviors they use in the wild.
For those on the offensive side, the ATT&CK matrix offers another quite remarkable benefit: it acts a classification system to design your attacks into distinct kill-chains.
Offensive operators, including those in cyber operations and red teams alike, spend their time crafting exploits, coding implants and researching ways to conduct post-compromise activities without getting caught. In a constant game of cat-and-mouse, an offensive operator needs to remain one step ahead at all times and, therefore, must build (and rebuild) procedures constantly.
In this post, we’ll walk through how an offensive operator uses ATT&CK. We will start with a goal, something to accomplish, and then set out to define it as a tactic, select the best-fitting technique and finally pivot into building a single procedure to use in a live attack.
Step 0: The ATTACK Scenario
I am an offensive operator. Previously, I wrote an excellent Python-based implant that easily drops onto target systems and allows me Remote Code Execution (RCE). When my agent, let’s call it “Boomer,” is installed, it beacons back to my command-and-control (C2) server where I can send it instructions. I now need to devise a new instruction (procedure) to ensure Boomer stays on the infected computer – specifically when the computer reboots.
When a computer reboots, any non-system services and processes will shut down and not reopen when the computer starts back up. This will stop implants like Boomer in their tracks – unless action is taken to ensure they reboot when the computer does.
As a Python agent, I’ve coded Boomer to execute Python code as attacks using the Python 3 interpreter installed by default on my target operating system, macOS.
Some attackers will send instructions directly to the shell interpreter through utilities such as Bash or ZSH, but defenders have improved their detection’s for these over the years. So I’ll need to write my procedure in the Python programming language so it can execute through the interpreter on the infected machine.
Boomer accepts a Python expression – even a large one – and pipes it through the built-in exec() function, which interprets and executes dynamic Python code.
It looks like this:
Step 1: Selecting the tactic
With Boomer deployed remotely and waiting for an instruction, I first have to select my tactic.
With my goal in hand – which is to maintain my foothold on the infected computer – I head to attack.mitre.org to see if any tactics align.
Looking at the Enterprise tactics, I see Reconnaissance, Resource Development, Initial Access, Execution, Persistence…there it is. Persistence sounds exactly like what I’m trying to do!
Clicking into the tactic, I verify my hunch by reading MITRE’s description:
The adversary is trying to maintain their foothold. Persistence consists of techniques that adversaries use to keep access to systems across restarts, changed credentials, and other interruptions that could cut off their access. Techniques used for persistence include any access, action, or configuration changes that let them maintain their foothold on systems, such as replacing or hijacking legitimate code or adding startup code.
Perfect. This is the one. Time to pick a technique.
Step 2: Selecting the technique
Scrolling down the page on the Persistence tactic (https://attack.mitre.org/tactics/TA0003/), I see a variety of rows with a T* prefix. These are the technique identifiers underneath the tactic.
Two in particular catch my eye: T1547 (Boot or Logon Autostart Execution) and T1037 (Boot or Logon Initialization Scripts).
T1547 is described as:
Adversaries may configure system settings to automatically execute a program during system boot or logon to maintain persistence or gain higher-level privileges on compromised systems. Operating systems may have mechanisms for automatically running a program on system boot or account logon. These mechanisms may include automatically executing programs that are placed in specially designated directories or are referenced by repositories that store configuration information, such as the Windows Registry. An adversary may achieve the same goal by modifying or extending features of the kernel.
And T1037 is:
Adversaries may use scripts automatically executed at boot or logon initialization to establish persistence. Initialization scripts can be used to perform administrative functions, which may often execute other programs or send information to an internal logging server. These scripts can vary based on the operating system and whether applied locally or remotely.
Hm. Either could work for me, as they are both designed to relaunch an arbitrary program (like Boomer) after a computer boots up. Because Boomer is a Python script, I figure I can probably hook into the script technique a little easier, so I decide on T1037.
Under this technique, I see a series of sub-techniques, or categories, as denoted with the .000 syntax. Now, while all of these sub-techniques should be considered, my eye is drawn to .002: Logon Script (Mac) because it specifically mentions the operating system Boomer is currently running on.
Scanning the description of T1037.002, I read:
Adversaries may use macOS logon scripts automatically executed at logon initialization to establish persistence. macOS allows logon scripts (known as login hooks) to be executed whenever a specific user logs into a system. A login hook tells Mac OS X to execute a certain script when a user logs in, but unlike Startup Items, a login hook executes as the elevated root user.
Perfect. This will do just fine.
Step 3: Researching the options
At this point, I’ve identified the Persistence tactic and technique T1037.002 as my preferred behavior to execute. For any technique, there could be dozens – if not thousands – of variations. This is what makes being a defender so difficult. As the offensive operator, to be successful, I only need to select one variation the defense is blind to, whereas defenders need to catch all of my attacks to beat me.
Picking a variation means hitting the internet for some research.
Let’s start on the ATT&CK website itself. Clicking into the technique itself (https://attack.mitre.org/techniques/T1037/002/), I can see the defense is being trained to detect procedures under this technique in this way:
Monitor logon scripts for unusual access by abnormal users or at abnormal times. Look for files added or modified by unusual accounts outside of normal administration duties. Monitor running process for actions that could be indicative of abnormal programs or executables running upon logon.
Ok, good to know.
Heading to every hacker’s best friend, Google, I type the following:
“macos logon script python”
This leads me to a Stackoverflow post (https://stackoverflow.com/questions/29338066/run-python-script-at-os-x-startup) recommending I create a PLIST file and place it in one of the following locations:
A PLIST file is simply a properties file on macOS computers for specific applications.
This has 12 upvotes and seems to be a well supported answer, so I bookmark the page and move on to the next step: writing the code.
Step 4: Writing the code
Based on my research in the previous step, I need to do two things to build my attack:
- Write a PLIST property file which starts Boomer.
- Place the property file on the correct location on disk.
In my research, it says to put my new PLIST property file in one of three locations on disk. I suppose I can find an example PLIST file there to work off of, so I navigate on my own laptop to those locations and open a few PLIST files.
I find a small example that seems promising: com.jetbrains.toolbox.plist.
Opening this, I see:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "<http://www.apple.com/DTDs/PropertyList-1.0.dtd>"> <plist version="1.0"> <dict> <key>Label</key> <string>com.jetbrains.toolbox</string> <key>ProgramArguments</key> <array> <string>/Applications/JetBrains Toolbox.app/Contents/MacOS/jetbrains-toolbox</string> <string>--minimize</string> </array> <key>KeepAlive</key> <true/> </dict> </plist>%
It looks like the Label should equal the name of my PLIST file and the Program arguments should be the path to the Python interpreter and script location. I adjust the values to the following, which match my own computer.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "<http://www.apple.com/DTDs/PropertyList-1.0.dtd>"> <plist version="1.0"> <dict> <key>Label</key> <string>my.boomer</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/python3</string> <string>/Users/privateducky/Downloads/boomer.py</string> </array> <key>KeepAlive</key> <true/> </dict> </plist>
Next, I stage the PLIST file on my laptop’s /Users/privateducky/Library/LaunchAgents directory in order to test it out.
I ensure the paths defined in the PLIST are correct. Then, instead of infecting my laptop with a Boomer agent, I drop an ad-hoc Python script called boomer.py into my laptop’s Downloads directory to test with:
import time while True: print('boomer here') time.sleep(30)
Rebooting my laptop, I run a process check to see if my ad-hoc Boomer process is active:
Step 5: Launching the attack
With a working procedure in hand, I’m ready to send it to my live Boomer agent running on the infected remote computer.
Since I’m planning on using Python’s built-in exec() function, I need to ensure my instruction is a valid Python string.
It looks a little messy, but this one-liner should do the trick (assuming the username of the active user is barry and Boomer is located in the Downloads directory of the remote machine):
With the command ready, I send the procedure (instruction) to Boomer and sit back comfortably, knowing every time the infected machine is rebooted, Boomer will kick back on.
In this post, we learned how to take a goal and convert it into an executable procedure classified by MITRE ATT&CK.
From here, we can continue building procedures to construct an end-to-end mission, or we can save our procedure into an indexed database so we can repeat it in the future. In the latter case, there are several popular online repositories built toward standardizing attack procedures in a repeatable way. There is the Atomic Red Team (https://github.com/redcanaryco/atomic-red-team) project as well as the Community repository (https://github.com/preludeorg/community), both of which index procedures in YML format for reuse in future missions.
About the Author: David Hunt is the CTO of Prelude Research Inc. There, he leads a team supporting a cutting-edge autonomous red team platform. Prior to this work, David built CALDERA, an open-source adversary emulation framework, while working as a Principal Cyber Security Engineer for MITRE. David has spent 15 years working as a security consultant for the U.S. Government, along with full-time roles at major cyber security firms, such as FireEye.
Editor’s Note: The opinions expressed in this guest author article are solely those of the contributor, and do not necessarily reflect those of Tripwire, Inc.