-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
1 parent
246f1a2
commit 8dbe3d2
Showing
6 changed files
with
263 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |