-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New attack technique: Persistence AWS Lambda Layer Extension (#427)
* Add lambda-layer-extension technique * build documentation * Minor docs editing * Minor code changes --------- Co-authored-by: Christophe Tafani-Dereeper <[email protected]>
- Loading branch information
1 parent
7a96eb0
commit d151fe9
Showing
12 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
docs/attack-techniques/AWS/aws.persistence.lambda-layer-extension.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
--- | ||
title: Add a Malicious Lambda Extension | ||
--- | ||
|
||
# Add a Malicious Lambda Extension | ||
|
||
|
||
<span class="smallcaps w3-badge w3-blue w3-round w3-text-white" title="This attack technique can be detonated multiple times">idempotent</span> | ||
|
||
Platform: AWS | ||
|
||
## MITRE ATT&CK Tactics | ||
|
||
|
||
- Persistence | ||
- Privilege Escalation | ||
|
||
## Description | ||
|
||
|
||
Establishes persistence by adding a malicious lambda extension. | ||
|
||
<span style="font-variant: small-caps;">Warm-up</span>: | ||
|
||
- Create a Lambda function and a lambda extension (layer). | ||
|
||
<span style="font-variant: small-caps;">Detonation</span>: | ||
|
||
- Add the extension as a layer to the Lambda function. | ||
|
||
References: | ||
|
||
- https://www.clearvector.com/blog/lambda-spy/ | ||
|
||
|
||
## Instructions | ||
|
||
```bash title="Detonate with Stratus Red Team" | ||
stratus detonate aws.persistence.lambda-layer-extension | ||
``` | ||
## Detection | ||
|
||
|
||
Through CloudTrail's <code>UpdateFunctionConfiguration20150331v2</code> event. | ||
|
||
While matching this event may be impractical and prone to false positives in most environments, the following can help to craft more precise detections: | ||
|
||
- Identify calls to <code>UpdateFunctionConfiguration20150331v2</code> where the <code>responseElements</code> field contains <code>layer</code>, indicating that the function's layers were modified. | ||
- Identify calls to <code>UpdateFunctionConfiguration20150331v2</code> where <code>responseElements.layers</code> includes a layer that's from a different AWS account.' | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
v2/internal/attacktechniques/aws/persistence/lambda-layer-extension/main.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package aws | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"errors" | ||
"log" | ||
|
||
"github.com/aws/aws-sdk-go-v2/service/lambda" | ||
"github.com/datadog/stratus-red-team/v2/pkg/stratus" | ||
"github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack" | ||
) | ||
|
||
//go:embed main.tf | ||
var tf []byte | ||
|
||
func init() { | ||
stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ | ||
ID: "aws.persistence.lambda-layer-extension", | ||
FriendlyName: "Add a Malicious Lambda Extension", | ||
Description: ` | ||
Establishes persistence by adding a malicious lambda extension. | ||
Warm-up: | ||
- Create a Lambda function and a lambda extension (layer). | ||
Detonation: | ||
- Add the extension as a layer to the Lambda function. | ||
References: | ||
- https://www.clearvector.com/blog/lambda-spy/ | ||
`, | ||
Detection: ` | ||
Through CloudTrail's <code>UpdateFunctionConfiguration20150331v2</code> event. | ||
While matching this event may be impractical and prone to false positives in most environments, the following can help to craft more precise detections: | ||
- Identify calls to <code>UpdateFunctionConfiguration20150331v2</code> where the <code>responseElements</code> field contains <code>layer</code>, indicating that the function's layers were modified. | ||
- Identify calls to <code>UpdateFunctionConfiguration20150331v2</code> where <code>responseElements.layers</code> includes a layer that's from a different AWS account.' | ||
`, | ||
Platform: stratus.AWS, | ||
PrerequisitesTerraformCode: tf, | ||
IsIdempotent: true, | ||
MitreAttackTactics: []mitreattack.Tactic{mitreattack.Persistence, mitreattack.PrivilegeEscalation}, | ||
Detonate: detonate, | ||
Revert: revert, | ||
}) | ||
} | ||
|
||
func detonate(params map[string]string, providers stratus.CloudProviders) error { | ||
ctx := context.Background() | ||
lambdaClient := lambda.NewFromConfig(providers.AWS().GetConnection()) | ||
lambdaExtensionLayerArn := params["lambda_extension_layer_arn"] | ||
lambdaArn := params["lambda_arn"] | ||
|
||
// Update the function configuration with our layer | ||
_, err := lambdaClient.UpdateFunctionConfiguration(ctx, &lambda.UpdateFunctionConfigurationInput{ | ||
FunctionName: &lambdaArn, | ||
Layers: []string{lambdaExtensionLayerArn}, | ||
}) | ||
|
||
if err != nil { | ||
return errors.New("unable to update function configuration: " + err.Error()) | ||
} | ||
|
||
log.Println("Added simulated malicious layer to Lambda function ", lambdaArn) | ||
return nil | ||
} | ||
|
||
func revert(params map[string]string, providers stratus.CloudProviders) error { | ||
ctx := context.Background() | ||
lambdaArn := params["lambda_arn"] | ||
lambdaClient := lambda.NewFromConfig(providers.AWS().GetConnection()) | ||
|
||
// Update the function configuration with an empty list of layers | ||
_, err := lambdaClient.UpdateFunctionConfiguration(ctx, &lambda.UpdateFunctionConfigurationInput{ | ||
FunctionName: &lambdaArn, | ||
Layers: []string{}, | ||
}) | ||
|
||
if err != nil { | ||
return errors.New("unable to update function configuration: " + err.Error()) | ||
} | ||
log.Printf("Layers have been removed from the Lambda function %s\n", lambdaArn) | ||
return nil | ||
} |
113 changes: 113 additions & 0 deletions
113
v2/internal/attacktechniques/aws/persistence/lambda-layer-extension/main.tf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
terraform { | ||
required_providers { | ||
aws = { | ||
source = "hashicorp/aws" | ||
version = "~> 4.0" | ||
} | ||
} | ||
} | ||
provider "aws" { | ||
skip_region_validation = true | ||
skip_credentials_validation = true | ||
skip_get_ec2_platforms = true | ||
default_tags { | ||
tags = { | ||
StratusRedTeam = true | ||
} | ||
} | ||
} | ||
|
||
locals { | ||
resource_prefix = "stratus-red-team-lambda-layer" | ||
} | ||
|
||
resource "aws_iam_role" "lambda_role" { | ||
name = "${local.resource_prefix}-lambda-role" | ||
|
||
assume_role_policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = [ | ||
{ | ||
Action = "sts:AssumeRole" | ||
Effect = "Allow" | ||
Principal = { | ||
"Service" : [ | ||
"lambda.amazonaws.com" | ||
] | ||
} | ||
}, | ||
] | ||
}) | ||
} | ||
|
||
resource "aws_iam_policy" "lambda_logs" { | ||
name = "${local.resource_prefix}-lambda-logs" | ||
description = "Allows Lambda function to write logs to CloudWatch" | ||
|
||
policy = <<EOF | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Action": [ | ||
"logs:CreateLogGroup", | ||
"logs:CreateLogStream", | ||
"logs:PutLogEvents" | ||
], | ||
"Effect": "Allow", | ||
"Resource": "*" | ||
} | ||
] | ||
} | ||
EOF | ||
} | ||
|
||
resource "aws_iam_role_policy_attachment" "lambda_logs_attach" { | ||
role = aws_iam_role.lambda_role.name | ||
policy_arn = aws_iam_policy.lambda_logs.arn | ||
} | ||
|
||
resource "aws_s3_bucket" "bucket" { | ||
bucket = "${local.resource_prefix}-bucket" | ||
force_destroy = true | ||
} | ||
resource "aws_s3_bucket_object" "code" { | ||
bucket = aws_s3_bucket.bucket.id | ||
key = "simpleLambda.zip" | ||
content_base64 = "UEsDBBQACAAIAAAAIYoAAAAAAAAAAAAAAAAPAAAAc2ltcGxlTGFtYmRhLnB5RIuxCgIxEAX7+4pntQpXHJZpbSws/IWcu8cJya4ke2IQ/11M43TDMCwL1qicpOzlKeojbqYuLz+EAQCK+FYU7y4/qHr0rZ6MhQKO0zT+02zcKIDOkpJhKZaRG+o9P5Lg2nw1xSXmmeOO+vUZvgEAAP//UEsHCCE/h3lyAAAAgQAAAFBLAQIUAxQACAAIAAAAIYohP4d5cgAAAIEAAAAPAAAAAAAAAAAAAACkgQAAAABzaW1wbGVMYW1iZGEucHlQSwUGAAAAAAEAAQA9AAAArwAAAAAA" | ||
} | ||
|
||
resource "aws_lambda_function" "lambda" { | ||
s3_bucket = aws_s3_bucket.bucket.id | ||
s3_key = aws_s3_bucket_object.code.key | ||
function_name = "${local.resource_prefix}-simpleLambda" | ||
role = aws_iam_role.lambda_role.arn | ||
handler = "${local.resource_prefix}-simpleLambda.handler" | ||
timeout = 20 | ||
|
||
runtime = "python3.10" | ||
|
||
publish = true | ||
} | ||
|
||
resource "aws_s3_bucket_object" "code_layer" { | ||
bucket = aws_s3_bucket.bucket.id | ||
key = "simpleLayer.zip" | ||
content_base64 = "UEsDBAoAAAAAAJSuZFcAAAAAAAAAAAAAAAAZABwAcHl0aG9uLWV4YW1wbGUtZXh0ZW5zaW9uL1VUCQADGK9GZTekSmV1eAsAAQToAwAABOgDAABQSwMECgAAAAAAj65kV24aFP4QAAAAEAAAACkAHABweXRob24tZXhhbXBsZS1leHRlbnNpb24vcmVxdWlyZW1lbnRzLnR4dFVUCQADDq9GZQ6vRmV1eAsAAQToAwAABOgDAAByZXF1ZXN0cz09Mi4zMS4wUEsDBBQAAAAIAI+uZFc1xSKHgwMAAPkIAAAlABwAcHl0aG9uLWV4YW1wbGUtZXh0ZW5zaW9uL2V4dGVuc2lvbi5weVVUCQADDa9GZQ6vRmV1eAsAAQToAwAABOgDAACtVVtv6kYQfudXTMkDRAJDT9+Q/EBPUGs1kChwmiMhtFrsMd7K3nV3F3I4Ef+9Y68vkORcItWyZO94bt/MN+OrX0Z7o0dbIUcoD5AfbaLkb50r+Kjyoxa7xMI041+V9EKVDSCQoQdKg7AGeByLVHCLxoNpmsJDoW3gAQ3qA0YeOVne33we3ooQpcFhEKG0IhaoJzAPVsNxpyOyXGkL/xgl63dl6jeN/+7R2OZsxE7ytDkdTSfWKoOc2yQVW6jk93TsdCj2LlVbnsKBa8G3KRoS4RdLmQglQfIMIeEGrIKM2zABmyAQHuwZ8qgpU4iExtAqfSy1rzu30/nvN1M2+7yaLZbB3YItpvMZ+GXEPmOFMWPXnrP2Cpsyj3BvLKXZxg5VhJ0IYxJhuLfInAbLtQrRGCF3fTyQi+tJB+i6ghx1rHRWe6LjsFSA1gIS1Fiq51pI24+76+c38z1tqEEhCmoQlE4m8FyU34v2WW6qwKfuAOJ0bxJ/pfeEvICxVYRPQ55Sw1sICZcRwXat6bsH2eqiYHX6IgaJGFHAnBuqeCJM1UuI1JMsWhAmIo1qONSqdwJx3vxn9zx5MPsiLFXFe4GjcEu88ZA+98cFrgKDxp0wFjVrWtSvcv+ZFJxtEcx7K1yCPEJtiCbP5bm4erc820Z8OKvjDRdUr94E3owyKO1OLiF+TBWPLr2VPTNkvm5kpTxY/H3316w3uJQu//y0url7XPQa8eY8gkaTK5pWClHPn5crY/uN+l6nftxNrM0no9GzomrKg9BKrnvTxyWrIDx8WqyC+YxN74Pe5jT6MP4wHo5/pXvUFHlU173bZlgw0a9AttKqhn71LOWuuuSMiajM1aXtVTrr1zVu109v887uEsWehE0guKFpcTFfjYgrnt1rWWVVsasiNXNd6rtvFb9+jhxniU9q323Dnmh0EIokJo2PHyN75OWAAO0VtwbeZu+3GLHDM0L8r6QokxlJEnQvifuCBJcfrchQ7a2/UBKbDy0Ety39kl5ewS3TbwhjKVSrSbuqVF67qVodc+xtwPfP5mZyEfkdW6r2UBX8e0uqvs6XVQMmNXiZw4/+IxUTMy6azXZVbe5qdbqZcu/exTL3lsEfwWI1uNz019/VX80e5q8MqrBVru3v0ECqdiKsx9kJ66F+vZiryX05U41ZAZaayFjx/2WsaF2XsQI6Y12H3dXhP1BLAwQKAAAAAACPrmRXAAAAAAAAAAAAAAAACwAcAGV4dGVuc2lvbnMvVVQJAAMNr0ZlpLNKZXV4CwABBOgDAAAE6AMAAFBLAwQUAAAACACPrmRXursQb/UAAABnAQAAIwAcAGV4dGVuc2lvbnMvcHl0aG9uLWV4YW1wbGUtZXh0ZW5zaW9uVVQJAAMNr0ZlDq9GZXV4CwABBOgDAAAE6AMAAHWPsU7DMBRFd3/FxenQSiTpjMQQaJAiJSlqK9Etct2X2pJjR7GLWhD/TlohYIDtDeeee190k+60TXfCKxbh0fXnQR9UQNaJN2cT6bpbFFYmcAN08BBtq40WgXyCzBisLrTHijwNr7RPRsn6ebGNSy3JeoqLPdmgW03DHapiE88Z8xQQ09Gh1z21QhvGli9181SUeZ1V+T2fTMc5ZEVHmMxnnJVZ9bDImny7yet1saybL+x3iiPClE6BBivMDJfLeu0srholPIJDJ4JUCIowPnEtYIykcuCT9z9LPgAjjlYqbQ8/Ts7oRBI8dX1I/0um33jSn/knUEsBAh4DCgAAAAAAlK5kVwAAAAAAAAAAAAAAABkAGAAAAAAAAAAQAO1BAAAAAHB5dGhvbi1leGFtcGxlLWV4dGVuc2lvbi9VVAUAAxivRmV1eAsAAQToAwAABOgDAABQSwECHgMKAAAAAACPrmRXbhoU/hAAAAAQAAAAKQAYAAAAAAABAAAApIFTAAAAcHl0aG9uLWV4YW1wbGUtZXh0ZW5zaW9uL3JlcXVpcmVtZW50cy50eHRVVAUAAw6vRmV1eAsAAQToAwAABOgDAABQSwECHgMUAAAACACPrmRXNcUih4MDAAD5CAAAJQAYAAAAAAABAAAA7YHGAAAAcHl0aG9uLWV4YW1wbGUtZXh0ZW5zaW9uL2V4dGVuc2lvbi5weVVUBQADDa9GZXV4CwABBOgDAAAE6AMAAFBLAQIeAwoAAAAAAI+uZFcAAAAAAAAAAAAAAAALABgAAAAAAAAAEADtQagEAABleHRlbnNpb25zL1VUBQADDa9GZXV4CwABBOgDAAAE6AMAAFBLAQIeAxQAAAAIAI+uZFe6uxBv9QAAAGcBAAAjABgAAAAAAAEAAADtge0EAABleHRlbnNpb25zL3B5dGhvbi1leGFtcGxlLWV4dGVuc2lvblVUBQADDa9GZXV4CwABBOgDAAAE6AMAAFBLBQYAAAAABQAFAPMBAAA/BgAAAAA=" | ||
} | ||
|
||
resource "aws_lambda_layer_version" "lambda_extension_layer" { | ||
s3_bucket = aws_s3_bucket.bucket.id | ||
s3_key = aws_s3_bucket_object.code_layer.key | ||
layer_name = "${local.resource_prefix}-my-lambda-extension" | ||
|
||
compatible_runtimes = ["python3.10"] | ||
} | ||
|
||
output "lambda_extension_layer_arn" { | ||
value = aws_lambda_layer_version.lambda_extension_layer.arn | ||
} | ||
|
||
output "lambda_arn" { | ||
value = aws_lambda_function.lambda.arn | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters