Skip to content

Commit

Permalink
Documentation: Foundations (#443)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #443

* Add foundational feature documentation
* Revamp the README.md and Link it to Foundational Documentation
* Suggest looking at the rendered markdown in the Github pull request to review

Reviewed By: cedowens

Differential Revision: D51495585

fbshipit-source-id: 70b3e31ddeeea101f158663c80d9dc9047a32897
  • Loading branch information
d3sch41n authored and facebook-github-bot committed Nov 21, 2023
1 parent 246f1a2 commit 8dbe3d2
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 17 deletions.
42 changes: 26 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,26 @@
[![License](https://img.shields.io/github/license/facebookincubator/TTPForge?label=License&style=flat&color=blue&logo=github)](https://github.com/facebookincubator/TTPForge/blob/main/LICENSE)
[![Tests](https://github.com/facebookincubator/TTPForge/actions/workflows/tests.yaml/badge.svg)](https://github.com/facebookincubator/TTPForge/actions/workflows/tests.yaml)
[![🚨 Semgrep Analysis](https://github.com/facebookincubator/TTPForge/actions/workflows/semgrep.yaml/badge.svg)](https://github.com/facebookincubator/TTPForge/actions/workflows/semgrep.yaml)
[![🚨 CodeQL Analysis](https://github.com/facebookincubator/TTPForge/actions/workflows/codeql-analysis.yaml/badge.svg)](https://github.com/facebookincubator/TTPForge/actions/workflows/codeql-analysis.yaml)
[![🚨 Nancy 3p Vulnerability Scan](https://github.com/facebookincubator/TTPForge/actions/workflows/nancy.yaml/badge.svg)](https://github.com/facebookincubator/TTPForge/actions/workflows/nancy.yaml)
[![Coverage Status](https://coveralls.io/repos/github/facebookincubator/TTPForge/badge.svg)](https://coveralls.io/github/facebookincubator/TTPForge)

This repo hosts the TTPForge tool created by Meta's Purple Team.
It is intended to provide an interface to execute TTPs across various
targets and mediums.
TTPForge is a cyber attack simulation platform. This project promotes a Purple
Team approach to cybersecurity with the following goals:

- To help blue teams accurately measure their detection and response
capabilities through high-fidelity simulations of real attacker activity.
- To help red teams improve the ROI/actionability of their findings by packaging
their attacks as automated, repeatable simulations.

TTPForge allows you to automate attacker tactics, techniques, and procedures
(TTPs) using a powerful but easy-to-use YAML format. Check out the links below
to learn more!

---

## Table of Contents

- [Getting Started - User](#getting-started-as-a-user)
- [Installation](#installation)
- [Documentation](docs/foundations/README.md)
- [Getting Started - Developer](docs/dev/README.md)
- [Go Package Documentation](https://pkg.go.dev/github.com/facebookincubator/ttpforge@main)
- [Using the TTPForge Dev Container](docs/container.md)
Expand All @@ -24,7 +31,7 @@ targets and mediums.

---

## Getting started as a user
## Installation

1. Get latest TTPForge release:

Expand Down Expand Up @@ -55,20 +62,24 @@ targets and mediums.
1. Initialize TTPForge configuration

This command will place a configuration file at the default location
`~/.ttpforge/config.yaml` and download the
[ForgeArmory](https://github.com/facebookincubator/ForgeArmory)
TTPs repository:
`~/.ttpforge/config.yaml` and configure the `examples` and `forgearmory` TTP
repositories:

```bash
ttpforge init
```

1. List available TTP repositories (should show `forgearmory`)
1. List available TTP repositories (should show `examples` and `forgearmory`)

```bash
ttpforge list repos
```

The `examples` repository contains the TTPForge examples found in this
repository. The
[ForgeArmory](https://github.com/facebookincubator/ForgeArmory) repository
contains our arsenal of attacker TTPs powered by TTPForge.

1. List available TTPs that you can run:

```bash
Expand All @@ -78,14 +89,13 @@ targets and mediums.
1. Examine an example TTP:

```bash
ttpforge show ttp forgearmory//examples/args/define-args.yaml
ttpforge show ttp examples//args/basic.yaml
```

1. Run the specified example:

```bash
ttpforge run \
forgearmory//examples/args/define-args.yaml \
--arg a_message="hello" \
--arg a_number=1337
ttpforge run examples//args/basic.yaml \
--arg str_to_print=hello \
--arg run_second_step=true
```
4 changes: 4 additions & 0 deletions cmd/default-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
---
repos:
- name: examples
path: repos/examples
git:
url: https://github.com/facebookincubator/TTPForge
- name: forgearmory
path: repos/forgearmory
git:
Expand Down
9 changes: 9 additions & 0 deletions docs/foundations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# TTPForge Foundations

Learn about the key features of TTPForge, including:

- [Automating Attacker Actions with TTPForge](actions.md)
- [Customizing TTPs with Command-Line Arguments](args.md)
- [Ensuring Reliable TTP Cleanup](cleanup.md)

More sections coming soon!
2 changes: 1 addition & 1 deletion docs/foundations/actions.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# TTPForge Attacker Action Portfolio
# TTPForge Attacker Action Types

TTPForge supports the following types of actions:

Expand Down
115 changes: 115 additions & 0 deletions docs/foundations/args.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Customizing Your TTPs with Command-Line Arguments

**Note**: to run the examples in this section, make sure you have the `examples`
repository installed with `ttpforge list repos` and if not run:

```bash
ttpforge install repo https://github.com/facebookincubator/TTPForge --name examples
```

## Basics of Command-Line Arguments

TTPForge allows users to control TTP execution through its support for
command-line arguments - check out the TTP below to see how it works:

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/args/basic.yaml#L1-L33

You can run this TTP and provide values for all relevant arguments as follows:

```bash
ttpforge run examples//args/basic.yaml \
--arg str_to_print=hello \
--arg run_second_step=true
```

Try out the following exercises to increase your understanding of how arguments
work in TTPForge:

- Remove `--arg str_to_print="..."` - the TTP will now refuse to run because the
user is required to specify a value for that argument since it has no
`default` value specified.
- Explicitly set `int_arg` with `--arg int_arg=5` - the `default` value will be
overridden.
- Try to pass values with invalid types, such as `--arg int_arg=foo` or
`--arg run_second_step=bar`. TTPForge validates argument types and should
throw an error for both of these cases. Note that `string` type arguments (the
default) will pretty much accept anything.
- Disable the second step by removing the `--arg run_second_step=true` line.

Focus in particular on the last item above, concerning `run_second_step=true`.
TTPForge TTP files are processed using Golang's
[text/template](https://pkg.go.dev/text/template) package to expand all argument
values prior to execution. We can use advanced templating features, such as the
[if-else-end](https://pkg.go.dev/text/template#hdr-Actions) shown above, to
precisely control execution based on argument values.

## Argument Types

TTPForge supports the following argument types (which you can specify with the
`type:` field as shown in the example above):

- `string` (this is the default if no `type` is specified)
- `int`
- `bool`
- `path` (a very important one - see below)

## The `path` Argument Type

If your TTP will accept arguments that refer to file paths on disk, you should
**almost always** use `type: path` when declaring those arguments, as shown in
the example below (just focus on the `args:` section for now, though you can
check out the [edit_file documentation](actions/edit_file.md) if you are
curious):

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/actions/edit_file/append_delete.yaml#L1-L35

You must use `type: path` because when you execute `ttpforge run [ttp]`,
**TTPForge changes its working directory to the folder containing the TTP.**
This means that relative paths such as `foo/bar` won't retain their original
meaning by default - however, when you declare your argument using `type: path`,
TTPForge knows to expand its value to an absolute path prior to changing
directories, ensuring that everything will work as intended.

## Predefined Choices for Argument Values

Sometimes only certain specific values make sense for a given argument. TTPForge
lets you restrict the allowed values for an argument using the `choices:`
keyword, as shown below

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/args/choices.yaml#L1-L29

You can run the above TTP as follows:

```bash
ttpforge run examples//args/choices.yaml \
--arg arg_with_choices=C
```

Notice the following key aspects of the `choices` feature:

- TTPForge will reject your arguments if you specify an invalid choice such as
`arg_with_choices=D`.
- If you use `choices` and `default` together, the `default` value must be one
of the valid choices.

## Validating Arguments with Regular Expressions

In order to require user-provided argument values to match a particular regular
expression (which is useful for ensuring that you don't get strange errors
halfway through a TTP due to user error) you can use the `regexp:` syntax
demonstrated below:

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/args/regexp.yaml#L1-L20

You can use any regular expression allowed by the Golang regular expression
[syntax](https://pkg.go.dev/regexp), although if you use YAML metacharacters
such as `:` you are advised to put quotes around your regexp to ensure that your
TTP YAML remains valid.

You can run the above TTP as follows:

```bash
ttpforge run examples//args/regexp.yaml \
--arg must_contain_ab=xabyabz \
--arg must_start_with_1_end_with_7=1337
```
108 changes: 108 additions & 0 deletions docs/foundations/cleanup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Reliable Post-Execution Cleanup of TTP Actions

**Note**: to run the examples in this section, make sure you have the `examples`
repository installed with `ttpforge list repos` and if not run:

```bash
ttpforge install repo https://github.com/facebookincubator/TTPForge --name examples
```

## Goals

TTPs will often include destructive (or at the very least, messy) actions, such
as:

- Editing System Files (such as `/etc/sudoers` or `/root/.ssh/authorized_keys`)
- Killing/Disabling Critical System Services (especially endpoint security
solutions such as MDE)
- Launching Cloud Resources (EC2 Instances/Docker Containers/Kubernetes Pods)

Failure to clean up properly after such activity will at the very least
inconvenience the user, and at worst may actually create severe new security
vulnerabilities in the target system.

Interpreter scripts usually lack standardized, platform-independent, and
reliable methods for cleaning up attacker activity. In particular, it is
especially difficult to ensure that these clean up processes are resilient to
runtime errors. For example, when writing TTPs in bash, one would need to make
very careful use of the
[trap](https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html) feature.

TTPForge's native support for cleanup actions provides users with a reliable
solution to these problems.

## Cleanup Basics

Every step in a TTPForge TTP can be associated with a cleanup action. That
cleanup action can be any valid TTPForge [action type](actions.md). Here's an
example TTP with several steps that have associated cleanup actions:

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/cleanup/basic.yaml#L1-L24

You can run this example with the command:
`ttpforge run examples//cleanup/basic.yaml` - based on the output, notice the
following key aspects about how cleanup actions work:

1. Every time a step completes successfully, its cleanup action is added to the
cleanup queue.
1. Not every step defines a cleanup action, and that's just fine. No cleanup
action will be added to the queue upon completion of those steps.
1. Once the TTP completes (or a step fails), the actions in the cleanup queue
are executed in reverse (last-in, first-out) order.

Pay particular attention to point (3) - TTPForge executes cleanup actions in
reverse order because it is quite common for later steps to depend on earlier
ones. For instance, one would definitely want the steps of the following
scenario cleaned up in reverse order:

1. Attacker adds self to `/etc/sudoers`
1. Attacker loads a malicious kernel module for persistence.

If we cleaned up step (1) first, we would then lose the privileges required to
cleanup (2).

## Delaying or Disabling Cleanup

Sometimes, one may wish to execute a given TTP and then to leave the target
system in a "dirty" state for further analysis. For these purposes, TTPForge
provides two useful command line flags for the `ttpforge run` command:

- `--cleanup-delay-seconds` - delay cleanup execution for the specified integer
number of seconds
- `--no-cleanup` - do not run any cleanup actions; instead, simply exit when the
last step completes.

## Default Cleanup Actions

Certain action types, such as [create_file](actions/create_file.md) have a
default cleanup action that can be invoked by specifying `cleanup: default` in
their YAML configuration. In the case of `create_file`, the default cleanup
action removes the created file. Check out the example below, which you can run
with `ttpforge run examples//cleanup/default.yaml`:

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/cleanup/default.yaml#L1-L12

## Handling Failures Gracefully

Whenever a step fails, the cleanup process will begin from the last successful
step (the step immediately preceeding the failure). The example below (which you
can run with `ttpforge run examples//cleanup/failure.yaml`) shows how cleanup
actions gracefully handle the failure of a step:

https://github.com/facebookincubator/TTPForge/blob/246f1a2b6b57714a56c5ac3f321399d49243a4eb/example-ttps/cleanup/failure.yaml#L1-L27

Note that **we don't clean up the failed step itself**, because that is usually
not desired behavior. Consider the following example situations:

- The step failed to create file due to a permissions issue. The cleanup action
to delete the file would also fail because the file was never created in the
first place.
- The step failed to setup a cloud resource due to a capacity constraint. The
cleanup action to remove the resource would also fail because no resource was
ever provisioned in the first place.

If a cleanup action fails, all remaining cleanup actions in the queue are
abandoned and not run. In this situation, it's likely that something is
fundamentally wrong with the TTP/test system and we want to prompt the user to
investigate rather than pushing forward and perhaps deleting something that we
shouldn't.

0 comments on commit 8dbe3d2

Please sign in to comment.