تخطَّ إلى المحتوى

Ghostwriter

Ghostwriter is an open-source engagement management platform built by SpecterOps for organizing red team operations, tracking findings, generating professional reports, and managing infrastructure. It provides centralized tracking of clients, projects, findings, and domain/server infrastructure with powerful Jinja2-based report templating.

Installation

Clone the repository and deploy using Docker Compose:

git clone https://github.com/GhostManager/Ghostwriter.git
cd Ghostwriter
docker compose up -d

Access the application at http://localhost:8000 after containers start (allow 30-60 seconds for initialization).

Manual Setup Requirements

  • Python 3.10+
  • PostgreSQL 14+
  • Redis
  • Node.js 16+
git clone https://github.com/GhostManager/Ghostwriter.git
cd Ghostwriter
pip install -r requirements.txt
npm install
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver

Verify Installation

docker compose logs -f ghostwriter
curl http://localhost:8000/admin/

Initial Setup

Default Admin Credentials

Change default admin credentials immediately after deployment:

# Via Django shell
docker compose exec ghostwriter python manage.py shell
from django.contrib.auth.models import User
user = User.objects.get(username='admin')
user.set_password('new_secure_password')
user.save()

Creating Users

Navigate to Admin Panel > Users or use the API:

# Create user via Django shell
from django.contrib.auth.models import User
User.objects.create_user(
    username='operator1',
    email='operator@company.com',
    password='secure_password'
)

API Token Generation

Generate API tokens for automation:

# Via Admin Panel: Profile > API Tokens > Create Token
# Via API:
curl -X POST http://localhost:8000/api/token-auth/ \
  -H "Content-Type: application/json" \
  -d '{"username":"operator1","password":"secure_password"}'

Store tokens securely in .env files.

Project Management

Creating Clients

Add organizational clients to organize engagements:

# Navigation: Clients > Add Client
# Fields:
# - Client Name: Company name
# - Client Timezone: For report generation timing
# - Short Name: Abbreviation (e.g., ACME)
# - Description: Company background/info

Creating Projects

Link projects to clients:

# Project Details
Name: "ACME 2026 Pentest"
Client: "ACME Corporation"
Codename: "OPERATION_SWIFT"
Start Date: "2026-04-17"
End Date: "2026-05-17"
Type: "Penetration Test"
Scope: "Internal network, web applications"
Objectives: "Identify vulnerabilities, test defenses"

Setting Engagement Dates and Scope

# Navigation: Project > Engagement > Edit
Start Date: Planning phase start
End Date: Reporting deadline
On Hold: Check to pause logging/activity
Team: Assign operators and managers

Define scope in the project description or attachments for clarity.

Finding Library

Creating Reusable Findings

Build a library of pre-configured findings for consistent reporting:

# Navigation: Finding Library > Create Finding
Title: "SQL Injection in Login Form"
Category: "Input Validation"
Finding Type: "Vulnerability"
Severity: "Critical"
CVSS Score: "9.8"
Description: HTML/rich text description
Recommendation: Remediation steps

Severity Ratings and CVSS

Severity Levels:
- Info (Informational)
- Low (CVSS: 0.1-3.9)
- Medium (CVSS: 4.0-6.9)
- High (CVSS: 7.0-8.9)
- Critical (CVSS: 9.0-10.0)

Categories and Organization

Organize findings by category:

- Input Validation
- Authentication
- Authorization
- Cryptography
- Configuration
- Sensitive Data Exposure
- Business Logic
- Session Management
- Dependency Usage
- Infrastructure

Report Generation

DOCX Templates

Ghostwriter generates Word documents using Jinja2 templates:

# Template Structure
templates/
├── report_template.docx
├── executive_summary.docx
├── technical_findings.docx
└── appendix.docx

Jinja2 Template Syntax

# Basic variable insertion
{{ report.title }}
{{ project.codename }}
{{ finding.severity }}

# Conditionals
{% if finding.severity == 'Critical' %}
  This finding requires immediate attention.
{% endif %}

# Loops
{% for finding in findings %}
  Finding: {{ finding.title }}
  Severity: {{ finding.severity }}
{% endfor %}

# Filters
{{ report.date|strftime('%B %d, %Y') }}
{{ description|wordcount }}

Common Report Types

TypePurposeIncludes
Executive SummaryHigh-level overview for managementFinding counts, risk ratings, timeline
Technical ReportDetailed findings for IT teamsFindings, CVSS scores, evidence, recommendations
Detailed ReportComprehensive assessmentAll findings, methodology, testing timeline
Summary ReportBrief overviewTop findings, risk summary

Custom Fields and Variables

Define custom fields in project settings:

# Available in templates:
{{ report.client_name }}
{{ report.project_name }}
{{ report.assessment_type }}
{{ report.assessment_start }}
{{ report.assessment_end }}
{{ report.assessor_name }}
{{ report.company_name }}
{{ findings }}
{{ executive_summary }}

Rich Text Findings and Evidence

Store findings with attachments:

# Findings include:
- HTML/Markdown description
- Code snippets
- Screenshots (embedded as base64 or file references)
- Proof of concept demonstrations
- Evidence artifacts (logs, outputs)

Infrastructure Tracking

Cloud Servers

Track cloud infrastructure used during engagement:

# Navigation: Infrastructure > Servers > Add Server
Name: "C2_Server_01"
IP Address: "10.0.0.5"
Provider: "AWS"
Instance Type: "t3.medium"
Region: "us-east-1"
Purpose: "C2 Infrastructure"
Compromised: Yes/No
Notes: Deployment date, role

Domains

Register and track domains for engagement:

# Navigation: Infrastructure > Domains > Add Domain
Name: "example-corp.com"
Type: "Phishing Domain"
Health: Active/Suspended/Taken Down
Registrar: "Namecheap"
Registered Date: "2026-04-10"
Expiration Date: "2027-04-10"
DNS Provider: "Route53"

DNS Records

Configure DNS for phishing, C2, and communication:

# DNS Record Types
A: 192.168.1.100
CNAME: example.redirect-domain.com
MX: mail.domain.com
TXT: v=spf1 include:sendgrid.net ~all
NS: ns1.provider.com

Domain Health Checks

Monitor domain reputation and deliverability:

# Automated checks monitor:
- Blacklist status (Spamhaus, Barracuda)
- MX record validation
- SPF/DKIM/DMARC configuration
- SSL certificate validity
- Subdomain enumeration
- DNS resolution

Oplog

Operation Logging

Log activities, commands, and timeline events:

# Navigation: Project > Oplog > Add Entry
Timestamp: "2026-04-17 14:32:00"
Title: "Initial Access via Phishing"
Description: "Deployed phishing email campaign"
Operator: "operator1"
Tool: "Gophish"
Tags: "phishing,initial-access"
Status: "Success"

Tool Tracking

Track tools and commands executed:

Tools:
- name: "Cobalt Strike"
  version: "4.7"
  beacon_id: "0x1234"
  host: "C2_Server_01"

- name: "PowerShell Empire"
  listener: "http_listener"
  modules_used: ["Invoke-WebRequest", "Get-ADUser"]

Command Logging

Log specific commands for audit trail:

Command: "Get-ADUser -Filter * -Properties *"
Tool: "PowerShell"
Host: "WORKSTATION-01"
Result: "Retrieved 150 user objects"
Evidence: "output.txt"

Domain and Server Management

Domain Checkout

Assign domains to team members during engagements:

# Navigation: Infrastructure > Domains > Checkout
Domain: "example-corp.com"
Checked Out By: "operator1"
Start Date: "2026-04-17"
End Date: "2026-05-17"
Purpose: "Phishing domain for engagement"
Notes: "Maintain low profile, monitor traffic"

Categorization Tracking

Tag infrastructure by purpose and category:

Categories:
- C2 Infrastructure
- Phishing Domain
- Proxy/Relay
- Malware Hosting
- Information Gathering
- Social Engineering

Health Monitoring

Track infrastructure status:

# Status Indicators
- Active: In use
- Dormant: Available but not in use
- Burned: Compromised or flagged
- Retired: End of engagement
- Monitoring: Under observation by defenders

# Health Checks
- DNS Resolution: Working
- SSL Certificate: Valid
- Blacklist Status: Clean
- Network Connectivity: Online

SSL Certificates

Manage SSL certificates for domains:

# Certificate Details
Domain: "example-corp.com"
Certificate: "self-signed" | "Let's Encrypt" | "Commercial"
Expiration: "2027-04-17"
Common Name: "example-corp.com"
Subject Alt Names: "*.example-corp.com"
Issued By: "DigiCert"

API Usage

GraphQL API

Query project data via GraphQL:

import requests
import json

url = "http://localhost:8000/graphql/"
headers = {
    "Authorization": "Token YOUR_API_TOKEN",
    "Content-Type": "application/json"
}

query = """
{
  allProjects {
    id
    codename
    client {
      name
    }
    startDate
    endDate
  }
}
"""

response = requests.post(
    url,
    json={"query": query},
    headers=headers
)
print(json.dumps(response.json(), indent=2))

REST Endpoints

Common API endpoints:

# Projects
GET /api/projects/
POST /api/projects/
GET /api/projects/{id}/
PATCH /api/projects/{id}/

# Findings
GET /api/findings/
POST /api/findings/
GET /api/findings/{id}/

# Infrastructure
GET /api/servers/
POST /api/servers/
GET /api/domains/

# Oplog
GET /api/oplog/
POST /api/oplog/

Authentication

# Token Auth
curl -H "Authorization: Token YOUR_API_TOKEN" \
  http://localhost:8000/api/projects/

# Generate Token
curl -X POST http://localhost:8000/api-token-auth/ \
  -d "username=operator1&password=password"

Common Queries

# Fetch all Critical findings
GET /api/findings/?severity=Critical

# Get project by codename
GET /api/projects/?codename=OPERATION_SWIFT

# List checked out domains
GET /api/domains/?checked_out=true

# Get oplog entries for project
GET /api/oplog/?project=1

Template Customization

Jinja2 Filters

# String Filters
{{ finding.title|upper }}
{{ finding.title|lower }}
{{ finding.description|wordcount }}

# Date Filters
{{ report.date|strftime('%B %d, %Y') }}
{{ report.date|date('Y-m-d') }}

# List Filters
{{ findings|length }}
{{ findings|first }}
{{ findings|rejectattr('severity', 'equalto', 'Info')|list }}

Custom Variables

Define custom variables in template context:

# In report generation:
context = {
    'company': 'ACME Corp',
    'testing_period': '30 days',
    'tester_name': 'Red Team',
    'custom_rating': 'High Risk',
    'findings_count': 42
}

Conditional Sections

{% if findings|length > 0 %}
  <h2>Findings</h2>
  {% for finding in findings %}
    <h3>{{ finding.title }}</h3>
  {% endfor %}
{% else %}
  <p>No findings identified.</p>
{% endif %}

Loops and Iterations

{% for finding in findings|dictsort(attribute='severity') %}
  <section>
    <h3>{{ finding.title }}</h3>
    <p>{{ finding.description }}</p>
  </section>
{% endfor %}

# Nested loops
{% for project in projects %}
  {% for finding in project.findings %}
    {{ finding.title }}
  {% endfor %}
{% endfor %}

User Management

Roles and Permissions

RolePermissionsAccess
AdminFull accessAll projects, users, settings
ManagerManage projects, usersAssigned projects, team management
OperatorExecute, log findingsAssigned projects only
ViewerRead-onlyAssigned projects, reports

Assigning Roles

# Navigation: Admin > Users > Select User
Role: Admin | Manager | Operator | Viewer
Projects: Multi-select assigned projects
Teams: Assign to teams
Permissions: Custom permission configuration

Teams

Organize operators into teams:

# Navigation: Teams > Create Team
Team Name: "Red Team Alpha"
Members: operator1, operator2, operator3
Projects: Link to relevant projects
Lead: operator1 (team manager)

Troubleshooting

Common Issues

IssueSolution
Cannot loginVerify database is running; check POSTGRES_PASSWORD in docker-compose.yml
Slow report generationReduce findings per report; optimize Jinja2 templates; increase server resources
Docker container crashesCheck logs: docker compose logs ghostwriter
API token expiredGenerate new token; store securely
Database migration errorsRun python manage.py migrate --fake-initial
Port 8000 already in useChange port in docker-compose.yml or docker compose -p ghostwriter2 up -d

Debug Mode

# Enable debug logging
DEBUG=True docker compose up

# Check application logs
docker compose logs -f ghostwriter

# Access Django shell
docker compose exec ghostwriter python manage.py shell

Best Practices

Engagement Organization

  • Use consistent codenames across all documents
  • Create client-specific templates for branding
  • Organize findings by engagement phase (reconnaissance, exploitation, post-exploitation)
  • Use tags extensively for filtering and reporting

Finding Management

  • Create reusable findings with generic descriptions
  • Include proof-of-concept code in findings
  • Document remediation steps clearly
  • Assign appropriate CVSS scores consistently
  • Use categories to organize finding library

Infrastructure Security

  • Rotate C2 infrastructure regularly
  • Monitor domain reputation proactively
  • Document all infrastructure assignments
  • Use separate infrastructure for different engagement types
  • Track SSL certificate expiration dates

Report Generation

  • Test templates with sample data before engagement
  • Create role-specific report variations
  • Include executive and technical summaries
  • Embed evidence and screenshots appropriately
  • Use consistent formatting across all reports

Operational Security

  • Limit API token scope to specific operations
  • Rotate API tokens regularly
  • Audit user access logs monthly
  • Archive completed projects and findings
  • Use encrypted connections for all API calls

Team Collaboration

  • Establish naming conventions for projects and findings
  • Create shared finding templates before engagements
  • Assign oplog responsibility clearly
  • Review and approve findings before finalizing reports
  • Maintain team documentation and playbooks
ToolPurposeIntegration
AttackForgeEngagement management and reportingSimilar functionality; cloud-based
PlexTracPlatform for findings and reportingCompetitor; different UI/workflow
DradisSecurity assessment collaborationFinding collection and reporting
DefectDojoVulnerability managementIntegration with CI/CD pipelines
OWASP ZAPWeb application securityFinding import capabilities
NessusVulnerability scanningScan import and integration
Burp SuiteWeb penetration testingFinding export integration