Skip to content

Commit

Permalink
Add an example to detonate an attack technique and retrieve relevant …
Browse files Browse the repository at this point in the history
…CloudTrail logs
  • Loading branch information
christophetd committed Jul 29, 2022
1 parent 816f8cc commit 3e5956c
Show file tree
Hide file tree
Showing 4 changed files with 1,153 additions and 0 deletions.
65 changes: 65 additions & 0 deletions examples/detonate-and-dump-cloudtrail-logs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Example: Detonating Stratus Red Team programmatically to understand the logs that an attack technique generates

This example shows a more advanced example of detonating an attack using Stratus Red Team,
then using the Datadog API to query the CloudTrail logs generated by this detonation.

This is made possible by the fact that Stratus Red Team injects an unique header (`stratus-red-team_<uuid>`)
in the user-agent of requests it performs.

Usage:

```
$ go run dump-logs.go aws.defense-evasion.cloudtrail-delete cloudtrail-logs.json
```

Sample output (note that CloudTrail logs by design take several minutes to be delivered by AWS):

```
Detonating 'aws.defense-evasion.cloudtrail-delete' with Stratus Red Team
Execution UID: b071a414-5f74-48d8-9346-31e3b01a24e3
Searching for logs in Datadog
No logs found. Sleeping for 1m0s
Searching for logs in Datadog
No logs found. Sleeping for 1m0s
Searching for logs in Datadog
Found 1 matching logs
```

Here, `cloudtrail-logs.json` will contain (redacted for clarity):

```json
[
{
"awsRegion": "us-east-1",
"eventCategory": "Management",
"eventID": "df1dd5f2-4891-4c74-9918-2c10ba1bbd5a",
"eventName": "DeleteTrail",
"eventSource": "cloudtrail.amazonaws.com",
"eventTime": "2022-07-29T21:17:04Z",
"eventType": "AwsApiCall",
"eventVersion": "1.08",
"evt": {
"name": "DeleteTrail"
},
"http": {
"useragent": "stratus-red-team_b071a414-5f74-48d8-9346-31e3b01a24e3",
},
"managementEvent": true,
"readOnly": false,
"recipientAccountId": "012345678912",
"requestParameters": {
"name": "my-cloudtrail-trail-2"
},
"service": "cloudtrail",
"timestamp": 1659129552928,
"userIdentity": {
"accessKeyId": "ASIA...ZICY",
"accountId": "012345678912",
"arn": "arn:aws:sts::012345678912:assumed-role/my-role/christophetd",
"assumed_role": "my-role",
"principalId": "AROA...N6U4:christophetd",
"type": "AssumedRole"
}
}
]
```
131 changes: 131 additions & 0 deletions examples/detonate-and-dump-cloudtrail-logs/dump-logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/DataDog/datadog-api-client-go/api/v2/datadog"
"github.com/datadog/stratus-red-team/v2/pkg/stratus"
_ "github.com/datadog/stratus-red-team/v2/pkg/stratus/loader" // Note: This import is needed
stratusrunner "github.com/datadog/stratus-red-team/v2/pkg/stratus/runner"
"os"
"strconv"
"time"
)

// Detonates a TTP using Stratus Red Team
func detonateTTP(stratusRedTeamTTP string) (*stratusrunner.Runner, error) {
ttp := stratus.GetRegistry().GetAttackTechniqueByName(stratusRedTeamTTP)
if ttp == nil {
return nil, errors.New("unknown TTP: " + stratusRedTeamTTP)
}
stratusRunner := stratusrunner.NewRunner(ttp, stratusrunner.StratusRunnerNoForce)

fmt.Println("Detonating '" + stratusRedTeamTTP + "' with Stratus Red Team")

_, err := stratusRunner.WarmUp()
if err != nil {
return nil, err
}
err = stratusRunner.Detonate()
if err != nil {
return nil, err
}
return &stratusRunner, nil
}

// Uses the Datadog API to retrieve the logs generated by a specific Stratus Red Team detonation
func findLogs(detonationUuid string) (*[]map[string]interface{}, error) {
ctx := context.WithValue(context.Background(), datadog.ContextAPIKeys, map[string]datadog.APIKey{
"apiKeyAuth": {Key: os.Getenv("DD_API_KEY")},
"appKeyAuth": {Key: os.Getenv("DD_APP_KEY")},
})
cfg := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(cfg)

query := fmt.Sprintf(
"@http.useragent:stratus-red-team_%s OR @userAgent:stratus-red-team_%s",
detonationUuid,
detonationUuid,
)
queryRequest := datadog.LogsListRequest{
Filter: &datadog.LogsQueryFilter{
Query: datadog.PtrString(query),
From: datadog.PtrString(strconv.FormatInt(time.Now().Add(-1*time.Hour).UnixMilli(), 10)),
To: datadog.PtrString(strconv.FormatInt(time.Now().UnixMilli(), 10)),
},
Sort: datadog.LOGSSORT_TIMESTAMP_ASCENDING.Ptr(),
Page: &datadog.LogsListRequestPage{
Limit: datadog.PtrInt32(1000),
},
}
result, _, err := apiClient.LogsApi.ListLogs(ctx, *datadog.NewListLogsOptionalParameters().WithBody(queryRequest))
if err != nil {
return nil, err
}

logs := result.Data
logEntries := []map[string]interface{}{}
if len(logs) == 0 {
return &logEntries, nil
}

for i := range logs {
logEntries = append(logEntries, logs[i].Attributes.Attributes)
}
return &logEntries, nil
}

func dumpLogs(logs *[]map[string]interface{}, filename string) {
fp, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
fmt.Println("unable to open file")
return
}
defer fp.Close()

btes, _ := json.MarshalIndent(logs, " ", " ")
fp.Write(btes)
}

func main() {
if len(os.Args) != 3 {
fmt.Println("Usage: go run <filename>.go <stratus-red-team-ttp-name> <logs-output-file>")
os.Exit(1)
}
runner, err := detonateTTP(os.Args[1])
defer runner.CleanUp()
if err != nil {
fmt.Println(err.Error())
return
}

fmt.Println("Execution UID: " + runner.GetUniqueExecutionId())
start := time.Now()
const timeout = 15 * time.Minute
const interval = 15 * time.Second
found := false
for !found && !time.Now().After(start.Add(timeout)) {
time.Sleep(interval)

fmt.Println("Searching for logs in Datadog")
logs, err := findLogs(runner.GetUniqueExecutionId())
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
if numLogs := len(*logs); numLogs > 0 {
fmt.Println("Found " + strconv.Itoa(numLogs) + " matching logs!")
dumpLogs(logs, os.Args[2])
found = true
} else {
fmt.Println("No logs found. Sleeping for " + interval.String())
}
}

if !found {
fmt.Println("Timed out")
os.Exit(1)
}
}
90 changes: 90 additions & 0 deletions examples/detonate-and-dump-cloudtrail-logs/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
module github.com/datadog/stratus-red-team/example/detonate-and-dump-cloudtrail-logs

go 1.18

replace github.com/datadog/stratus-red-team/v2 => ../../v2

require (
github.com/DataDog/datadog-api-client-go v1.16.0
github.com/datadog/stratus-red-team/v2 v2.2.3
)

require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 // indirect
github.com/DataDog/zstd v1.5.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.7 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.13.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.13.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2 v1.26.0 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.14.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.10.0 // indirect
github.com/aws/aws-sdk-go-v2/service/lambda v1.17.0 // indirect
github.com/aws/aws-sdk-go-v2/service/organizations v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/service/rds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.0.0 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.23.0 // indirect
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.13.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.20.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect
github.com/aws/smithy-go v1.12.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-version v1.4.0 // indirect
github.com/hashicorp/hc-install v0.3.2 // indirect
github.com/hashicorp/terraform-exec v0.15.0 // indirect
github.com/hashicorp/terraform-json v0.13.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/zclconf/go-cty v1.9.1 // indirect
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/api v0.23.3 // indirect
k8s.io/apimachinery v0.23.3 // indirect
k8s.io/client-go v0.23.3 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
Loading

0 comments on commit 3e5956c

Please sign in to comment.