Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions docs/attack-techniques/GCP/gcp.exfiltration.sql-export-bucket.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
title: Exporting Cloud SQL database to Storage bucket
---

# Exporting Cloud SQL database to Storage bucket

<span class="smallcaps w3-badge w3-orange w3-round w3-text-sand" title="This attack technique might be slow to warm up or detonate">slow</span>

<span class="smallcaps w3-badge w3-blue w3-round w3-text-white" title="This attack technique can be detonated multiple times">idempotent</span>

Platform: GCP

## MITRE ATT&CK Tactics


- Exfiltration

## Description


Exfiltrates data from a Cloud SQL database by exporting to internal storage bucket.

<span style="font-variant: small-caps;">Warm-up</span>:

- Create a Cloud SQL instance
- Create a storage bucket and grant objectAdmin to Cloud SQL instance
- Populate the database

<span style="font-variant: small-caps;">Detonation</span>:

- Export the database into the storage bucket

!!! info

Provisioning the Cloud SQL requires a few minutes.

<span style="font-variant: small-caps;">Reference:</span>

- https://cloud.google.com/sdk/gcloud/reference/sql/export/sql
- https://cloud.hacktricks.wiki/en/pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-sql-post-exploitation.html



## Instructions

```bash title="Detonate with Stratus Red Team"
stratus detonate gcp.exfiltration.sql-export-bucket
```


## Detection

Exporting the database is detected as 'cloudsql.instances.export' in Cloud Logging.

Data Access logging for Cloud SQL instance is disabled by default, thus we need to enable it (if not enabled).

- Go to "IAM & Admin" -> "Audit Logs"
- Locate "Cloud SQL"
- on "Permission Types", check the "Admin read"

You can use following query to filter the events:

```
resource.type="cloudsql_database"
protoPayload.serviceName="cloudsql.googleapis.com"
protoPayload.methodName="cloudsql.instances.export"
```

Sample event (shortened for readability):

```json
{
"logName": "projects/my-project-id/logs/cloudaudit.googleapis.com%2Factivity",
"protoPayload": {
"authenticationInfo": {
"principalEmail": "[email protected]",
},
"methodName": "cloudsql.instances.export",
"request": {
@type: "type.googleapis.com/google.cloud.sql.v1.SqlInstancesExportRequest",
"body": {
"exportContext": {
"databases": [
"stratus-db"
],
"fileType": "SQL",
"uri": "gs://my-bucket-id/dump.sql.gz"
}
},
"instance": "my-cloudsql-instance-id",
}
"resourceName": "projects/my-project-id/instances/my-cloudsql-instance-id",
"serviceName": "cloudsql.googleapis.com",
},
"resource": {
"type": "cloudsql_database"
},
"severity": "INFO"
}
```

subsequently, detect the 'storage.objects.create' event for creating the object on bucket.

```json
{
"logName": "projects/my-project-id/logs/cloudaudit.googleapis.com%2Factivity",
"protoPayload": {
"authenticationInfo": {
"principalEmail": "[email protected]",
},
"methodName": "storage.objects.create",
"resourceName": "projects/_/buckets/my-bucket-id/objects/dump.sql.gz",
"serviceName": "cloudsql.googleapis.com",
},
"resource": {
"type": "gcs_bucket"
},
"severity": "INFO"
}
```
2 changes: 2 additions & 0 deletions docs/attack-techniques/GCP/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Note that some Stratus attack techniques may correspond to more than a single AT

- [Exfiltrate Compute Disk by sharing a snapshot](./gcp.exfiltration.share-compute-snapshot.md)

- [Exporting Cloud SQL database to Storage bucket](./gcp.exfiltration.sql-export-bucket.md)


## Persistence

Expand Down
1 change: 1 addition & 0 deletions docs/attack-techniques/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ This page contains the list of all Stratus Attack Techniques.
| [Exfiltrate Compute Disk by sharing it](./GCP/gcp.exfiltration.share-compute-disk.md) | [GCP](./GCP/index.md) | Exfiltration |
| [Exfiltrate Compute Image by sharing it](./GCP/gcp.exfiltration.share-compute-image.md) | [GCP](./GCP/index.md) | Exfiltration |
| [Exfiltrate Compute Disk by sharing a snapshot](./GCP/gcp.exfiltration.share-compute-snapshot.md) | [GCP](./GCP/index.md) | Exfiltration |
| [Exporting Cloud SQL database to Storage bucket](./GCP/gcp.exfiltration.sql-export-bucket.md) | [GCP](./GCP/index.md) | Exfiltration |
| [Backdoor a GCP Service Account through its IAM Policy](./GCP/gcp.persistence.backdoor-service-account-policy.md) | [GCP](./GCP/index.md) | Persistence |
| [Create an Admin GCP Service Account](./GCP/gcp.persistence.create-admin-service-account.md) | [GCP](./GCP/index.md) | Persistence, Privilege Escalation |
| [Create a GCP Service Account Key](./GCP/gcp.persistence.create-service-account-key.md) | [GCP](./GCP/index.md) | Persistence, Privilege Escalation |
Expand Down
7 changes: 7 additions & 0 deletions docs/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@ GCP:
- Exfiltration
platform: GCP
isIdempotent: true
- id: gcp.exfiltration.sql-export-bucket
name: Exporting Cloud SQL database to Storage bucket
isSlow: true
mitreAttackTactics:
- Exfiltration
platform: GCP
isIdempotent: true
Persistence:
- id: gcp.persistence.backdoor-service-account-policy
name: Backdoor a GCP Service Account through its IAM Policy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package gcp

import (
"context"
_ "embed"
"fmt"
"log"
"time"
"google.golang.org/api/sqladmin/v1"
"github.com/datadog/stratus-red-team/v2/pkg/stratus"
"github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack"
)

//go:embed main.tf
var tf []byte

func init() {
const CodeBlock = "```"
const AttackTechniqueId = "gcp.exfiltration.sql-export-bucket"

stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{
ID: AttackTechniqueId,
FriendlyName: "Exporting Cloud SQL database to Storage bucket",
Description: `
Exfiltrates data from a Cloud SQL database by exporting to internal storage bucket.

Warm-up:

- Create a Cloud SQL instance
- Create a storage bucket and grant objectAdmin to Cloud SQL instance
- Populate the database

Detonation:

- Export the database into the storage bucket

!!! info

Provisioning the Cloud SQL requires a few minutes.

Reference:

- https://cloud.google.com/sdk/gcloud/reference/sql/export/sql
- https://cloud.hacktricks.wiki/en/pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-sql-post-exploitation.html
`,
Detection: `
Exporting the database is detected as 'cloudsql.instances.export' in Cloud Logging.

Data Access logging for Cloud SQL instance is disabled by default, thus we need to enable it (if not enabled).

- Go to "IAM & Admin" -> "Audit Logs"
- Locate "Cloud SQL"
- on "Permission Types", check the "Admin read"

You can use following query to filter the events:

` + CodeBlock + `
resource.type="cloudsql_database"
protoPayload.serviceName="cloudsql.googleapis.com"
protoPayload.methodName="cloudsql.instances.export"
` + CodeBlock + `

Sample event (shortened for readability):

` + CodeBlock + `json
{
"logName": "projects/my-project-id/logs/cloudaudit.googleapis.com%2Factivity",
"protoPayload": {
"authenticationInfo": {
"principalEmail": "[email protected]",
},
"methodName": "cloudsql.instances.export",
"request": {
@type: "type.googleapis.com/google.cloud.sql.v1.SqlInstancesExportRequest",
"body": {
"exportContext": {
"databases": [
"stratus-db"
],
"fileType": "SQL",
"uri": "gs://my-bucket-id/dump.sql.gz"
}
},
"instance": "my-cloudsql-instance-id",
}
"resourceName": "projects/my-project-id/instances/my-cloudsql-instance-id",
"serviceName": "cloudsql.googleapis.com",
},
"resource": {
"type": "cloudsql_database"
},
"severity": "INFO"
}
` + CodeBlock + `

subsequently, detect the 'storage.objects.create' event for creating the object on bucket.

` + CodeBlock + `json
{
"logName": "projects/my-project-id/logs/cloudaudit.googleapis.com%2Factivity",
"protoPayload": {
"authenticationInfo": {
"principalEmail": "[email protected]",
},
"methodName": "storage.objects.create",
"resourceName": "projects/_/buckets/my-bucket-id/objects/dump.sql.gz",
"serviceName": "cloudsql.googleapis.com",
},
"resource": {
"type": "gcs_bucket"
},
"severity": "INFO"
}
` + CodeBlock + `
`,
Platform: stratus.GCP,
IsIdempotent: true,
MitreAttackTactics: []mitreattack.Tactic{ mitreattack.Exfiltration },
PrerequisitesTerraformCode: tf,
Detonate: detonate,
})
}

func detonate(params map[string]string, providers stratus.CloudProviders) error {
gcp := providers.GCP()
ctx := context.Background()

projectId := gcp.GetProjectId()
bucketName := params["bucket_name"]
sqlInstance := params["sql_instance"]

// create service for API communication
service, err := sqladmin.NewService(ctx, gcp.Options())
if err != nil {
return fmt.Errorf("Failed to create new service: %v", err)
}

// export the database
req := &sqladmin.InstancesExportRequest {
ExportContext: &sqladmin.ExportContext{
Databases: []string{"stratus-db"},
FileType: "SQL",
Uri: fmt.Sprintf("gs://%s/dump.sql.gz", bucketName),
},
}

if op, err := service.Instances.Export(projectId, sqlInstance, req).Do(); err != nil {
return fmt.Errorf("Failed to export database: %v", err)
}

// wait for the export operation to complete
for {
op, err := service.Operations.Get(projectId, op.Name).Do()
if err != nil {
return fmt.Errorf("Failed to get operation status: %v", err)
}

if op.Status == "DONE" {
if op.Error != nil {
return fmt.Errorf("Export operation failed: %v", op.Error.Errors)
}
break
}

log.Println("Exporting in progress... waiting")
time.Sleep(10 * time.Second)
}

log.Println("Database has been exported to the bucket")

return nil
}
Loading