Skip to content

Latest commit

 

History

History
239 lines (189 loc) · 8.88 KB

File metadata and controls

239 lines (189 loc) · 8.88 KB

Hardened GCE VM Sandbox Setup & Isolation Guide

This guide describes how to provision, harden, and verify a Google Compute Engine (GCE) VM sandbox for dynamic exploit reproduction and patch verification in Mantis.

An automated idempotent setup script is provided at reference/scripts/setup_gce_sandbox.sh:

PROJECT_ID="your-project-id" SOURCE_INSTANCE="your-dev-vm" ./reference/scripts/setup_gce_sandbox.sh

Configuration Variables

Set these environment variables in your shell before running the manual setup commands:

export PROJECT_ID="${PROJECT_ID:-$(gcloud config get-value project)}"
export REGION="us-central1"
export ZONE="us-central1-a"
export VPC_NAME="mantis-isolated-vpc"
export SUBNET_NAME="mantis-isolated-subnet"
export SUBNET_RANGE="10.0.0.0/24"
export DNS_POLICY_NAME="mantis-block-public-dns"
export IMAGE_NAME="mantis-assessment-disk-v1"
export DEV_BUILD_VM="my-dev-build-vm"

1. Assessment Disk Image Creation & Golden Image Prerequisites

Before capturing your golden assessment disk image from the source build VM, ensure the following prerequisites are installed and configured:

Golden Image Prerequisites

  1. Passwordless sudo (NOPASSWD):

    • During instance initialization, GceEnvironment provisions the guest workspace directory via SSH (core/environments/gce_env.py:269):
      sudo mkdir -p /workspace && sudo chown -R $(whoami) /workspace
    • The SSH user connecting to the sandbox VM must have passwordless sudo rights in /etc/sudoers or /etc/sudoers.d/ (e.g. standard %sudo ALL=(ALL) NOPASSWD:ALL or %admin ALL=(ALL) NOPASSWD:ALL). Standard GCP Ubuntu LTS images configure this by default for the provisioning user.
  2. python3 Interpreter:

    • GceEnvironment runs automated active in-guest security isolation audits (_verify_guest_isolation() in core/environments/gce_env.py:338) by piping a base64-encoded isolation verification script directly to python3:
      echo '<probe_script>' | base64 -d | python3 -
    • Ensure python3 (or python3-minimal) is installed on the image and available in PATH (/usr/bin/python3). Without python3, instance startup fails fail-closed during guest isolation verification.
  3. Pre-Warmed Build Tools & Dependencies:

    • Because the isolated VPC has zero external internet routing and no Cloud NAT, all compilers, build runtimes, package manager caches, test frameworks, and dependencies needed to compile the target repository and reproduce vulnerabilities must be pre-installed and pre-built on the VM before capturing the disk image.

Image Capture Workflow

  1. Provision a development VM with all necessary build runtimes, compilers, package managers, and test suites.
  2. Confirm that passwordless sudo and python3 are configured as described above.
  3. Build your target repository on the VM to warm all local build caches, dependencies, and artifacts.
  4. Capture a custom disk image from the source build VM:
gcloud compute images create "${IMAGE_NAME}" \
    --project="${PROJECT_ID}" \
    --source-disk="${DEV_BUILD_VM}" \
    --source-disk-zone="${ZONE}" \
    --force \
    --description="Assessment disk image with pre-warmed build dependencies for Mantis"

[!IMPORTANT] Disk Images vs Machine Images: Custom disk images (gcloud compute images create --source-disk=...) allow full instance identity override (--no-service-account --no-scopes), ensuring the sandbox VM runs with zero IAM credentials (serviceAccounts: null). GCE Machine Images (--source-machine-image) lock in the service account identity from the source VM and disallow --no-service-account.


2. Private Isolated VPC & Network Containment

Create a dedicated VPC with zero external access and Private Google Access disabled:

# 1. Custom VPC
gcloud compute networks create "${VPC_NAME}" \
    --project="${PROJECT_ID}" \
    --subnet-mode=custom

# 2. Private subnet (no internet route, no Cloud NAT, no Google API access)
gcloud compute networks subnets create "${SUBNET_NAME}" \
    --project="${PROJECT_ID}" \
    --network="${VPC_NAME}" \
    --region="${REGION}" \
    --range="${SUBNET_RANGE}" \
    --no-enable-private-ip-google-access

# 3. Allow SSH strictly from Google Cloud Identity-Aware Proxy (IAP) IP range
gcloud compute firewall-rules create "allow-iap-ssh-${VPC_NAME}" \
    --project="${PROJECT_ID}" \
    --network="${VPC_NAME}" \
    --allow=tcp:22 \
    --source-ranges=35.235.240.0/20

3. Link-Local DNS Exfiltration Defense (169.254.169.254:53)

By default in GCE, queries to the link-local metadata resolver (169.254.169.254:53) perform recursive public DNS lookups out-of-band via the hypervisor, creating an exfiltration path even without external IP routing.

Seal this path at the VPC infrastructure level using Cloud DNS:

Option A: Cloud DNS Response Policy (RPZ Wildcard Blackhole)

# Create response policy bound to isolated VPC
gcloud dns response-policies create "${DNS_POLICY_NAME}" \
    --project="${PROJECT_ID}" \
    --networks="${VPC_NAME}" \
    --description="Block all public DNS lookups"

# Wildcard rule returning 0.0.0.0 for all domains (*.)
gcloud dns response-policies rules create block-all-domains \
    --project="${PROJECT_ID}" \
    --response-policy="${DNS_POLICY_NAME}" \
    --dns-name="*." \
    --local-data=name="*.",type="A",ttl=300,rrdatas="0.0.0.0"

Option B: Outbound DNS Server Policy (Private Sinkhole & Logging)

# Redirect all VM DNS queries away from public recursion to an unassigned private IP
gcloud dns policies create mantis-dns-blackhole \
    --project="${PROJECT_ID}" \
    --networks="${VPC_NAME}" \
    --description="Redirect VM DNS queries to private blackhole" \
    --private-alternative-name-servers=10.0.0.254 \
    --enable-logging

4. Mantis Workflow Configuration

Add the GCE sandbox configuration to workflow.json:

{
  "sandbox": {
    "type": "gce",
    "options": {
      "project": "YOUR_PROJECT_ID",
      "zone": "us-central1-a",
      "image": "mantis-assessment-disk-v1",
      "subnet": "mantis-isolated-subnet",
      "workdir": "/workspace",
      "tunnel_through_iap": true,
      "no_service_account": true,
      "no_external_ip": true,
      "verify_isolation": true,
      "timeout_seconds": 60
    }
  }
}

5. Automated Active Isolation Audit Probes

When verify_isolation: true is set (the default), GceEnvironment executes an active in-guest probe before executing any PoCs or analysis tasks:

  1. IAM Token Leak Probe: Queries http://169.254.169.254/.../service-accounts/default/token. Fails if access tokens are accessible.
  2. Direct Internet Egress Probe: Attempts TCP connection to external IP (1.1.1.1:80). Fails if reachable.
  3. Public DNS Recursion Probe: Attempts resolving example.com. Fails if public IP is returned.
  4. Private Google Access Probe: Attempts TCP connection to storage.googleapis.com:443. Fails if reachable.

If any check fails, the VM is immediately deleted and Mantis halts with a fail-closed RuntimeError detailing the misconfiguration.


6. Single-VM Scope & Multi-VM Architecture Considerations

[!NOTE] The GCE sandbox setup is currently designed and configured for single-VM execution only.

If an operator wants to adapt this setup for multi-VM campaigns (e.g. distributed targets or multi-node exploit chains), they must resolve at least the following architectural constraints:

  1. DNS Name Resolution (*.internal): The wildcard Cloud DNS response policy (*. → 0.0.0.0) catches everything, including internal metadata domains (*.internal), making peer VMs unresolvable by hostname. Multi-VM setups require explicit private DNS zone rules bypassing the wildcard sinkhole for internal peer records.
  2. Internal VM-to-VM Ingress: The firewall section creates IAP ingress on tcp:22 and nothing else. Because GCP denies ingress by default, all VM-to-VM network traffic between sandbox instances is blocked (there is no allow-internal rule).
  3. Instance Tagging & Firewall Scoping: Instances created by GceEnvironment do not currently attach network --tags. An operator adding an internal communication rule cannot scope it to sandbox VMs by tag, but only by CIDR (which means scoping it to the entire subnet).