Today, I’m thrilled to release a new open-source project I’ve been working on in the past few weeks: Stratus Red Team, an adversary emulation and purple teaming tool, focused on emulating common attack techniques in cloud environments.
Motivation
A fair deal of my professional experience involves threat detection. I started fresh out of school working on threat detection use cases in a local Managed Detection & Response company focused on endpoint security. When I later moved to a cloud security role in a tech company, I found that detecting malicious activity in the cloud had similar challenges.
One of them was reproducing attackers tactics, techniques and procedures (TTPs) in live environments, to validate that our logging pipelines and detection logic are working end-to-end. Several open-source projects exist for traditional endpoint and on-premise security, such as Atomic Red Team™ or MITRE Caldera. However, none of these tools is cloud-native, built with cloud providers and infrastructure in mind, or has a reasonable number of cloud-focused attack techniques.
Meet Stratus Red Team
Stratus Red Team is a project that started maturing in my mind in early 2021. I was finally able to execute on it thanks to my new position as a cloud security researcher at Datadog, and I’m proud that we are releasing it as 100% free and open-source software!
https://stratus-red-team.cloud/
https://github.com/DataDog/stratus-red-team
You can read the official announcement on the Datadog blog:
https://www.datadoghq.com/blog/cyber-attack-simulation-with-stratus-red-team/
I recommend you start by reading this post, then continue reading here. I won’t cover the basics to avoid content duplication.
What is Stratus Red Team?
Stratus Red Team is a lightweight Go binary you can install easily. It comes packaged with a number of AWS-specific attack techniques. Each attack technique as a documentation page, automatically generated from source code.
Stratus Red Team handles spinning up any infrastructure or configuration needed to execute an attack technique. This is what it calls warming-up an attack technique. Once an attack technique is “warm”, it can be detonated, i.e. executed to emulate the attacker behavior it intends to simulate.
How it Works Under The Hood
Attack Techniques as Code
Under the hood, each attack technique is comprised of:
- a piece of Terraform code, describing the prerequisite infrastructure that Stratus Red Team needs to deploy before detonating the attack technique ;
- a piece of Go code, defining the technique metadata as well as its detonation logic.
Let’s see an example for the attack technique “Stop CloudTrail Trail“. The prerequisite Terraform code defines a CloudTrail Trail logging to an S3 bucket. The attack technique definition includes its name, mapping to MITRE ATT&CK, and the detonation function. Here, the detonation consists in stopping the CloudTrail Trail.
resource "random_string" "suffix" { length = 16 min_lower = 16 special = false } locals { bucket-name = "my-cloudtrail-bucket-${random_string.suffix.result}" } resource "aws_s3_bucket" "cloudtrail" { bucket = local.bucket-name force_destroy = true policy = "..." } resource "aws_cloudtrail" "trail" { name = "my-cloudtrail-trail" s3_bucket_name = aws_s3_bucket.cloudtrail.id } output "cloudtrail_trail_name" { value = aws_cloudtrail.trail.name } output "display" { value = format("CloudTrail trail %s ready", aws_cloudtrail.trail.arn) }
//go:embed main.tf var tf []byte func init() { stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ ID: "aws.defense-evasion.stop-cloudtrail", FriendlyName: "Stop CloudTrail Trail", Platform: stratus.AWS, MitreAttackTactics: []mitreattack.Tactic{mitreattack.DefenseEvasion}, Description: ` Stops a CloudTrail Trail from logging. Simulates an attacker disrupting CloudTrail logging. Warm-up: - Create a CloudTrail Trail. Detonation: - Call cloudtrail:StopLogging to stop CloudTrail logging. `, PrerequisitesTerraformCode: tf, IsIdempotent: true, // cloudtrail:StopLogging is idempotent Detonate: detonate, }) } func detonate(params map[string]string) error { cloudtrailClient := cloudtrail.NewFromConfig(providers.AWS().GetConnection()) trailName := params["cloudtrail_trail_name"] log.Println("Stopping CloudTrail trail " + trailName) _, err := cloudtrailClient.StopLogging(context.Background(), &cloudtrail.StopLoggingInput{ Name: aws.String(trailName), }) if err != nil { return errors.New("unable to stop CloudTrail logging: " + err.Error()) } return nil }
Instrumenting Terraform
Stratus Red Team uses Terraform to spin up and destroy prerequisite infrastructure and configuration. This is transparent to the end user. You don’t even need to have Terraform installed! Stratus Red Team uses Hashicorp’s terraform-exec library to download and instrument Terraform. The Terraform binary is stored at ~/.stratus-red-team/terraform
, so it doesn’t conflict with your existing Terraform version.
When you warm up or clean up a technique, Stratus Red Team programmatically calls terraform apply
and terraform destroy
.
State Storage
Stratus Red Team is stateful. It needs to keep state about:
- the status of each attack technique
- the Terraform state of each attack technique prerequisites
- the Terraform outputs of each attack technique prerequisites
It stores this information on your local filesystem, under ~/.stratus-red-team/[technique-id]
.
Philosophy and Design Choices
I had to make a several design choices while building Stratus Red Team. This section acts as architectural decision records, giving the reasoning behind these choices.
Programming Language: Python vs. Go
While I have much more prior exposure to Python, it’s also a language I actively dislike for its lack of static typing. From my experience, it makes development slow and error-prone – especially when using third-party libraries such as the AWS SDK. What’s more, there is no solid Terraform wrapper for Python.
This is why I chose to use Go. Hashicorp maintains an official Terraform wrapper. Go is strongly typed, meaning that when using the AWS SDK, you know exactly what types, field names, and field types it expects. This speeds the development workflow a lot for me: if it compiles, you’re confident it runs.
The main downside of choosing Go is the lack of extensibility. Contrary to Python, Go cannot dynamically load user-provided code easily. This means the only way to add new attack techniques to Stratus Red Team is to package them in the main binary, or to define them programmatically when using Stratus Red Team as a library.
Handling Prerequisite Infrastructure
Attack techniques need prerequisite infrastructure to run. For instance, an attack technique removing VPC Flow Logs from a VPC needs a VPC, a VPC Flow Logs configuration, and a CloudWatch Log Group.
There are several ways to approach this:
- Make the end user responsible for manually creating the required infrastructure
- Provide Terraform code to the end user, and make them responsible for creating the required infrastructure
- Package Terraform code in the binary, and take care of creating and removing the required infrastructure
I felt that options 1 and 2 did not bring much value for a CLI tool. They would rather fit an “exploitation walk-through” or tutorial, as they don’t encapsulate complexity.
This is why I chose to go with option 3. While reducing complexity, it also gives less flexibility to the end user. Typically, Stratus Red Team currently does not support detonating attack techniques against existing infrastructure. For instance, when detonating “Backdoor an S3 Bucket via its Bucket Policy“, Stratus Red Team will create a new S3 bucket and detonate the technique against it. You cannot point it at an existing S3 bucket. If you feel like this is an important limitation, let me know in the corresponding issue!
What Makes a Good Attack Technique?
It was important for me to be able to answer the question: What attack techniques are packaged in Stratus Red Team, and why? Here’s my opinionated view on that, which I discuss in more detail in the Philosophy page.
- A technique should be granular, i.e., emulate a single step of an attack chain.
- A technique should emulate plausible attacker activity. It should always be possible to derive a realistic threat detection rule from it. An example of an unrealistic detection would be: Raise an alert every time sts:GetCallerIdentity is called.
- A technique should be self-sufficient and should not make any assumptions about the prior state of your AWS account. This is easier said than done, as it makes it challenging to implement techniques such as “Disable GuardDuty Detector” (because AWS allows only a single GuardDuty Detector per region).
While these are subjective and opinionated, I want to make sure that Stratus Red Team remains a project that cloud security practitioners can use to test, validate and enhance real-world threat detection use cases.
Choosing Supported Platforms
From the beginning, I envisioned that Stratus Red Team should support several cloud platforms – and I built it with that in mind. For the initial version, I chose to focus on AWS. I plan to add Kubernetes and Azure support in the future, and possibly GCP.
What About Testing?
The core of Stratus Red Team comes with non-trivial logic. In this context, it was essential for me to have some unit tests for it. I wrote over 35 unit tests and learned a lot in the process. One learning is that the earlier you think about testing, the less refactoring you need later on.
Once I tackled the core, I wondered how to handle the testing of attack techniques, which are also defined as Go code. Unfortunately, I discovered there was no good solution. The AWS SDK for Go V2 does not provide any Go interface allowing to generate mocks. Without going into too much detail, this means it’s challenging to unit test attack techniques in an environment where the AWS services and API calls used are meant to evolve quickly.
We could test attack techniques at another level: detonate them against a live AWS account, and ensure the detonation produced expected results. But this would be slow, error-prone, and add limited value. This is why there are currently no unit tests for the code of attack techniques.
What’s Next for Stratus Red Team
I’m proud I was able to ship Stratus Red Team in a few weeks, and super happy that my employer, Datadog, gave me the opportunity. Now that an initial version is out, I’m eager to listen to your feedback and use it to improve the project. What worked well, what would you improve? What did you like, or what’s missing? I would love to hear about you – my Twitter DMs are open. You can also e-mail me on the address listed here, or open a GitHub issue.
After initial feedback and usage from the community, I would like to:
- Add more AWS attack techniques
- Introduce Kubernetes support
- Introduce opt-in telemetry to understand attack techniques people use the most (turned off by default)
Thank you for reading! Let’s continue the discussion on Twitter.
Follow the blog on Feedly: