Everything (you need to know) about TTPs

A friendly guide to tactics, techniques, and especially, procedures

For years, defensive security professionals tasked with attributing cyber attacks to specific groups (or countries) toiled with the problem of Indicators of Compromise (IOC). An IOC is an objective “thing” on a computer, such as an IP address, FQDN (Fully Qualified Domain Name), email address, username, MAC address or one of dozens of other tangible properties that can be objectively analyzed.

Why are they a problem?

An attacker can spoof or fake an IOC during an attack, to try and throw off both the defense, as well as those trying to figure out who is behind the attack. For example, an attacker may launch an attack from behind the website of someone else, in order to make the defense attribute the attack to the wrong party.

For decades, defenders grappled with this problem. Many cried out for a behavior-driven approach that would help attribute an adversary based on their immutable behaviors, not IOCs which can be spoofed.

In 2015 the ATT&CK matrix started gaining traction in security communities as the solution: a table outlining all the possible adversarial actions. The matrix provided a common language for intelligence analysts to talk about adversarial behaviors.

The matrix breaks down adversary behaviors into:

  • Tactics: main goal of the attacker

  • Techniques: specific subset of the tactic

  • Procedures: even more specific subset of a technique, usually in the form of a command the adversary can/did execute

Does the ATT&CK matrix solve the attribution problem? No, behaviors can - and still are - spoofed. But, it does provide a common way to talk about behaviors and is another tool in the belt of analysts. Used in combination with indicators of compromise, an analyst can get closer than ever to the moving target that is attribution.

Community repository

Ok, so outside of understanding the acronym Tactics, Techniques and Procedures, what exactly is a TTP?

Generally speaking, a TTP is shorthand for a very specific, and very independent attack which is part of a larger operation.

Operator is powered by a repository called Community. This repo is a free, open-source collection of TTPs in the form of YAML (.yml) files. Community is independent of the Operator desktop application but when started, all of its TTPs are imported directly into the app for immediate use.

TTPs are organized by the ATT&CK tactic they are associated with, through a directory structure:

Here is an example TTP file from collection we can break down:

Each TTP has a unique ID, which is a UUID-4 string. This is random and is used as a way to ensure the TTP is unique. Conventionally, this id is also used as the filename.

Supporting information

A TTP name and description are simply human-readable text to give the reader a better understanding of what the TTP does when executed.

The metadata is intended to hold additional information about the TTP. In the example above, you can see we store the version (currently unused), authors (who wrote it) and the adversary tags to associate the attack with. Tags help organize procedures so you can bucket them based on either adversary profiles or categories of attack (like ransomware).


The ATT&CK tactic and technique information classifies the TTP according to the best fitting matrix information. This is a way to leverage the common language benefit of the ATT&CK framework.


Moving down the file, we get to platforms. These are the most interesting of the properties and supply the true power. Platforms are a list, where you can describe each operating system that the TTP works against.

Operator, by default, supports darwin (MacOS), Windows and linux. If you write custom agents for different operating systems, you can add your own custom platform blocks here to match.


For each platform, you’ll see a list of executors. An executor is the program used to actually run the TTP on the given operating system. On Linux and darwin platforms, sh (bash), pwsh (PowerShell Core) and python are the options. On Windows, python, pwsh, psh (PowerShell) and cmd (command line) are your options.

For each executor, there is a required property (command) and an option property (payload), not shown above.

The command property is the command that you want to execute. If it is multiple lines, make sure you use semicolons, or whatever line separator your executor uses.

A payload indicates that there is a file that should be downloaded before executing the command. Payloads are described using the HTTP location where it can be found.

Inside Operator, payloads are automatically downloaded by our agents before running the associated commands. If writing your own agents, you'll want to consider doing the same.

Understanding variables

As you review procedures stored in Community, you will come across some which contain variables, as denoted by a #{variable} syntax. Variables indicate that the text should be replaced with a real value, either manually or through some automated process, before running the procedure.

One of the most powerful components of TTPs, when loaded into Operator, is how they can be automatically chained together when deployed as an adversary. Operator automatically parses the output of every executed TTP and extracts variables, looking to fill them into additional procedures automatically.

Let's look at another example.

The commands in these examples expect two variables to be available before they can execute:

  • #{file.T1005}

  • #{directory.T1074}.

Variables use shorthand to describe what type of information to fill in. There is the root and the technique. The root is the closest matching IOC. The technique is the ATT&CK technique that should generate the variable.

For example, you can read #{file.T1005} as: a file path which was discovered from running a T1005 procedure.

You can include multiple potential techniques by using the pipe character:

Copy-Item #{file.T1005|T1010|T1012} #{directory.T1074} 

You can read this as, a file path that was discovered from running a T1005, T1010 or T1012 procedure.

Inside Operator, procedures can only execute if all facts are resolved. There are multiple ways this is done, either automatically by parsing the output of executed commands or manually by letting the user enter facts they already know.

Global platform

In addition to the platforms described above, there is a special global platform called “global”. Here is an example TTP from Community using it:

In this TTP, any platform (operating system) with the executor (python) should be capable of executing the command.

There is an alternative command under linux → sh, which shows a different variation of the procedure. Depending on how you decided to execute this TTP, if you are on Linux you may choose either the global or sh executor.

When run inside Operator executor ordering works like this:

  • An agent has a preferred ordered list of available executors

  • When Operator picks out a TTP for it, it looks at the agent's preferred executors and looks first for a matching one under the same platform as the agent.

    • If a match is found, that command is used

    • If a match is not found, Operator checks if the executor exists under global.

Keyword executor

There is a global executor available as well called “keyword”. Keyword does not map to any installed program, like the others you’ve seen. Instead, a keyword is a word or phrase that the agent can use to conduct special commands against.

Why use the keyword executor? You may have special code you want to run in a custom agent which doesn’t run within a shell executor and using a keyword will notify your agent when to execute that code.

This is a highly customizable executor and gives you space to create dynamic attacks using code, not shell commands.

Become a Community contributor

Have a great idea for a procedure? Write it into a TTP file following the format in this post, then submit it as a pull request to the Community repo. You’ll need to fork the Github project to do this. Contributing TTPs back to the community is a great way to become part of the open-source community, as well as a way to get your name inside Operator as a published author.