diff --git a/example-ttps/introduction/dotfile-backdoor-demo.yaml b/example-ttps/introduction/dotfile-backdoor-demo.yaml new file mode 100644 index 00000000..23ecec0a --- /dev/null +++ b/example-ttps/introduction/dotfile-backdoor-demo.yaml @@ -0,0 +1,57 @@ +--- +name: dotfile_backdoor +description: | + This TTP demonstrates the core features of TTPForge: + - Various Attacker Actions Implemented as Executable YAML + - Simple but powerful Command-line Argument Support + - Last-in-First-Out Cleanup Execution + - Checking Conditions at Runtime to Avoid Errors +args: + - name: target_file_path + description: The file that we should try to backdoor + default: ~/.zshrc + - name: payload_file_path + description: | + The path to which we should write the payload file. + The backdoor we insert into the target file will reference this + payload. + default: /tmp/ttpforge-dotfile-backdoor-demo-payload.sh + - name: payload_cmd + description: | + The shell command that our payload should execute + default: echo 'Hello from TTPForge! You have been pwned!' + - name: backup_file_path + description: | + The file path to which the target file should be backed up + default: /tmp/ttpforge-dotfile-backdoor-backup +steps: + - name: verify_dotfile_exists + description: | + Uses the `checks:` feature to verify that the target file + actually exists before we try to write to it + print_str: | + Verifying that {{.Args.target_file_path}} exists... + checks: + - path_exists: {{.Args.target_file_path}} + msg: "Target file {{.Args.target_file_path}} must exist" + - name: create_payload_file + description: | + This step uses the `create_file:` action to drop our payload to disk + create_file: {{.Args.payload_file_path}} + contents: | + #!/bin/bash + # Created by TTPForge + {{.Args.payload_cmd}} + mode: 0755 + cleanup: default + - name: backdoor_target_file + edit_file: {{.Args.target_file_path}} + backup_file: {{.Args.backup_file_path}} + edits: + - append: | + # ADDED BY TTPFORGE - SHOULD BE CLEANED UP AUTOMATICALLY + # BUT IF NOT YOU CAN DELETE THIS :) + {{.Args.payload_file_path}} + cleanup: + inline: | + cp {{.Args.backup_file_path}} {{.Args.target_file_path}} diff --git a/pkg/blocks/step.go b/pkg/blocks/step.go index af7421a2..80186080 100644 --- a/pkg/blocks/step.go +++ b/pkg/blocks/step.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" + "github.com/facebookincubator/ttpforge/pkg/checks" "github.com/facebookincubator/ttpforge/pkg/logging" "gopkg.in/yaml.v3" ) @@ -31,8 +32,9 @@ import ( // common to every type of step (such as Name). // It centralizes validation to simplify the code type CommonStepFields struct { - Name string `yaml:"name,omitempty"` - Description string `yaml:"description,omitempty"` + Name string `yaml:"name,omitempty"` + Description string `yaml:"description,omitempty"` + Checks []checks.Check `yaml:"checks,omitempty"` // CleanupSpec is exported so that UnmarshalYAML // can see it - however, it should be considered diff --git a/pkg/blocks/ttps.go b/pkg/blocks/ttps.go index be02a334..224fc2da 100755 --- a/pkg/blocks/ttps.go +++ b/pkg/blocks/ttps.go @@ -28,7 +28,9 @@ import ( "time" "github.com/facebookincubator/ttpforge/pkg/args" + "github.com/facebookincubator/ttpforge/pkg/checks" "github.com/facebookincubator/ttpforge/pkg/logging" + "github.com/spf13/afero" "gopkg.in/yaml.v3" ) @@ -283,8 +285,20 @@ func (t *TTP) RunSteps(execCtx *TTPExecutionContext) (*StepResultsRecord, int, e } return nil, firstStepToCleanupIdx, err } - firstStepToCleanupIdx++ + // if the user specified custom success checks, run them now + verificationCtx := checks.VerificationContext{ + FileSystem: afero.NewOsFs(), + } + for checkIdx, check := range step.Checks { + if err := check.Verify(verificationCtx); err != nil { + return nil, firstStepToCleanupIdx, fmt.Errorf("success check %d of step %q failed: %w", checkIdx+1, step.Name, err) + } + logging.L().Debugf("Success check %d (%q) of step %q PASSED", checkIdx+1, check.Msg, step.Name) + } + + // step execution successful - record results + firstStepToCleanupIdx++ execResult := &ExecutionResult{ ActResult: *stepResult, } diff --git a/ttpforge-repo-config.yaml b/ttpforge-repo-config.yaml new file mode 100644 index 00000000..97364fac --- /dev/null +++ b/ttpforge-repo-config.yaml @@ -0,0 +1,3 @@ +--- +ttp_search_paths: + - example-ttps