Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

💡 [REQUEST] - Handling state between steps for complex TTPs #478

Open
godlovepenn opened this issue Jan 10, 2024 · 1 comment
Open

💡 [REQUEST] - Handling state between steps for complex TTPs #478

godlovepenn opened this issue Jan 10, 2024 · 1 comment
Assignees
Labels
enhancement New feature or request question Clarification and/or additional information required to move forward

Comments

@godlovepenn
Copy link

Implementation PR

No response

Reference Issues

No response

Summary

  • For a complex TTP involving multiple steps, it would be beneficial to implement a state mechanism, allowing step 9 to access the output of step 3.
  • In my current approach, as demonstrated in the example below, I managed this by writing to an environment file (aws_resource_ids.txt), which subsequent steps can then read.
  • Github Actions does this too so it's not an easy problem.

Basic Example

Sample TTP

---
name: create-and-delete-aws-resources
description: Creates an Ubuntu machine with a Public IP and sets up SSH access
requirements:
  platforms:
    - os: darwin
    - os: linux

args:
  - name: group
    type: string
    default: "TestSimulation"

steps:
  - name: create-vpc
    description: "Create a new VPC named {{.Args.group}}VPC"
    inline: |
      VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query 'Vpc.VpcId' --output text)
      echo "VPC_ID=$VPC_ID" > aws_resource_ids.txt
      aws ec2 create-tags --resources "$VPC_ID" --tags Key=Name,Value={{.Args.group}}VPC
    cleanup:
      description: "Delete {{.Args.group}}VPC"
      inline: |
        source aws_resource_ids.txt
        aws ec2 delete-vpc --vpc-id "$VPC_ID"

  - name: create-internet-gateway
    description: "Create an Internet Gateway and attach it to {{.Args.group}}VPC"
    inline: |
      source aws_resource_ids.txt
      IGW_ID=$(aws ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId' --output text)
      echo "IGW_ID=$IGW_ID" >> aws_resource_ids.txt
      aws ec2 attach-internet-gateway --internet-gateway-id "$IGW_ID" --vpc-id "$VPC_ID"
      aws ec2 create-tags --resources "$IGW_ID" --tags Key=Name,Value={{.Args.group}}IGW

  - name: create-subnet
    description: "Create a Subnet named {{.Args.group}}Subnet in {{.Args.group}}VPC"
    inline: |
      source aws_resource_ids.txt
      SUBNET_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" --cidr-block 10.0.1.0/24 --query 'Subnet.SubnetId' --output text)
      echo "SUBNET_ID=$SUBNET_ID" >> aws_resource_ids.txt
      aws ec2 create-tags --resources "$SUBNET_ID" --tags Key=Name,Value={{.Args.group}}Subnet
      aws ec2 modify-subnet-attribute --subnet-id "$SUBNET_ID" --map-public-ip-on-launch

  - name: create-route-table
    description: "Create a Route Table named {{.Args.group}}RouteTable in {{.Args.group}}VPC"
    inline: |
      source aws_resource_ids.txt
      ROUTE_TABLE_ID=$(aws ec2 create-route-table --vpc-id "$VPC_ID" --query 'RouteTable.RouteTableId' --output text)
      echo "ROUTE_TABLE_ID=$ROUTE_TABLE_ID" >> aws_resource_ids.txt
      aws ec2 create-tags --resources "$ROUTE_TABLE_ID" --tags Key=Name,Value={{.Args.group}}RouteTable
      aws ec2 create-route --route-table-id "$ROUTE_TABLE_ID" --destination-cidr-block 0.0.0.0/0 --gateway-id "$IGW_ID"
      aws ec2 associate-route-table --route-table-id "$ROUTE_TABLE_ID" --subnet-id "$SUBNET_ID"

    cleanup:
      description: "Delete {{.Args.group}}Subnet, {{.Args.group}}IGW, and {{.Args.group}}RouteTable"
      inline: |
        source aws_resource_ids.txt
        # deleting subnet
        aws ec2 delete-subnet --subnet-id "$SUBNET_ID"
        # detach and delete internet gateway
        aws ec2 detach-internet-gateway --internet-gateway-id "$IGW_ID" --vpc-id "$VPC_ID"
        aws ec2 delete-internet-gateway --internet-gateway-id "$IGW_ID"
        # delete route table
        aws ec2 delete-route-table --route-table-id "$ROUTE_TABLE_ID"

  - name: create-security-group
    description: "Create Security Group in the specified VPC named {{.Args.group}}SecurityGroup"
    inline: |
      source aws_resource_ids.txt
      SECURITY_GROUP_ID=$(aws ec2 create-security-group --group-name "{{.Args.group}}SecurityGroup" --description "Security group for {{.Args.group}} instances" --vpc-id "$VPC_ID" --query 'GroupId' --output text)
      echo "SECURITY_GROUP_ID=$SECURITY_GROUP_ID" >> aws_resource_ids.txt
      aws ec2 authorize-security-group-ingress --group-id "$SECURITY_GROUP_ID" --protocol tcp --port 22 --cidr 0.0.0.0/0

    cleanup:
      description: "Delete {{.Args.group}}SecurityGroup"
      inline: |
        source aws_resource_ids.txt
        aws ec2 delete-security-group --group-id "$SECURITY_GROUP_ID"

  - name: create-key-pair
    description: "Create Key Pair named {{.Args.group}}_key"
    inline: |
      source aws_resource_ids.txt
      aws ec2 create-key-pair --key-name "{{.Args.group}}"_key --query 'KeyMaterial' --output text > "{{.Args.group}}_key.pem"
      chmod 600 "{{.Args.group}}_key.pem"
    cleanup:
      description: "Delete {{.Args.group}} Key Pair"
      inline: |
        aws ec2 delete-key-pair --key-name "{{.Args.group}}_key"
        rm -f "{{.Args.group}}_key.pem"

  - name: get-latest-ubuntu-ami-id
    description: "Retrieve ami id for ubuntu 22.04 amd64 "
    inline: |

      # https://raw.githubusercontent.com/l50/dotfiles/main/aws
      amiNamePattern="ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
      AMI_ID=$(aws ec2 describe-images --filters "Name=name,Values=$amiNamePattern" --owners amazon --query 'sort_by(Images, &CreationDate)[-1].ImageId' --output text)
      echo "AMI_ID=$AMI_ID" >> aws_resource_ids.txt

  - name: create-ec2-instance
    description: "Launch EC2 Instance named {{.Args.group}}Ubuntu"
    inline: |
      source aws_resource_ids.txt
      INSTANCE_ID=$(aws ec2 run-instances --image-id "$AMI_ID" --count 1 --instance-type "t2.micro" --key-name "{{.Args.group}}_key" --security-group-ids "$SECURITY_GROUP_ID" --subnet-id "$SUBNET_ID" --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value={{.Args.group}}Ubuntu}]' --query 'Instances[0].InstanceId' --output text)
      echo "INSTANCE_ID=$INSTANCE_ID" >> aws_resource_ids.txt
      aws ec2 wait instance-running --instance-ids "$INSTANCE_ID"
      echo "Instance is now running"
      PUBLIC_IP=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" --query 'Reservations[0].Instances[0].PublicIpAddress' --output text )
      echo "PUBLIC_IP=$PUBLIC_IP" >> aws_resource_ids.txt
      echo "Public IP of the instance: $PUBLIC_IP"
      echo "SSH to machine with ssh -i {{.Args.group}}_key.pem ubuntu@$PUBLIC_IP"
    cleanup:
      description: "Terminate {{.Args.group}}Ubuntu Instance"
      inline: |
        source aws_resource_ids.txt
        aws ec2 terminate-instances --instance-ids "$INSTANCE_ID"
        aws ec2 wait instance-terminated --instance-ids "$INSTANCE_ID"

Execution Command
ttpforge run ttp.yaml --arg group=TestSimulation --cleanup-delay-seconds=60

Drawbacks

  • Any solution that writes output to standard output will be less than ideal, particularly for TTPs intended to be stealthy."

Unresolved questions

No response

@godlovepenn godlovepenn added question Clarification and/or additional information required to move forward enhancement New feature or request labels Jan 10, 2024
@d3sch41n d3sch41n self-assigned this Jan 11, 2024
@d3sch41n
Copy link
Contributor

Great issue!

This should be a medium-scope change that can go onto the H1 development roadmap I'll be drafting when I return.

We can at the very least get rid of all the source calls by emulating Github actions' behavior.

I implemented a version of this a long time ago that one TTP from the internal catalog uses, but it should be revamped.

Claiming this one for when I return

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Clarification and/or additional information required to move forward
Projects
None yet
Development

No branches or pull requests

2 participants