コンテンツにスキップ

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.

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).

  • 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
docker compose logs -f ghostwriter
curl http://localhost:8000/admin/

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()

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'
)

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.

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

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"
# 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.

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 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)

Organize findings by category:

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

Ghostwriter generates Word documents using Jinja2 templates:

# Template Structure
templates/
├── report_template.docx
├── executive_summary.docx
├── technical_findings.docx
└── appendix.docx
# 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 }}
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

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 }}

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)

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

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"

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

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

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"

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"]

Log specific commands for audit trail:

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

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"

Tag infrastructure by purpose and category:

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

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

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"

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))

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/
# 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"
# 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
# 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 }}

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
}
{% if findings|length > 0 %}
  <h2>Findings</h2>
  {% for finding in findings %}
    <h3>{{ finding.title }}</h3>
  {% endfor %}
{% else %}
  <p>No findings identified.</p>
{% endif %}
{% 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 %}
RolePermissionsAccess
AdminFull accessAll projects, users, settings
ManagerManage projects, usersAssigned projects, team management
OperatorExecute, log findingsAssigned projects only
ViewerRead-onlyAssigned projects, reports
# Navigation: Admin > Users > Select User
Role: Admin | Manager | Operator | Viewer
Projects: Multi-select assigned projects
Teams: Assign to teams
Permissions: Custom permission configuration

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)
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
# 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
  • 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
  • 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
  • Rotate C2 infrastructure regularly
  • Monitor domain reputation proactively
  • Document all infrastructure assignments
  • Use separate infrastructure for different engagement types
  • Track SSL certificate expiration dates
  • 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
  • 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
  • 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