phishing defense

Performing Phishing Simulation with GoPhish

GoPhish is an open-source phishing simulation framework used by security teams to conduct authorized phishing awareness campaigns. It provides campaign management, email template creation, landing page cloning, and comprehensive reporting. This skill covers deploying GoPhish, creating realistic phishing scenarios, and analyzing campaign results to measure and improve organizational resilience.

awarenessdmarcemail-securitygophishphishingsimulationsocial-engineering
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

GoPhish is an open-source phishing simulation framework used by security teams to conduct authorized phishing awareness campaigns. It provides campaign management, email template creation, landing page cloning, and comprehensive reporting. This skill covers deploying GoPhish, creating realistic phishing scenarios, and analyzing campaign results to measure and improve organizational resilience.

When to Use

  • When conducting security assessments that involve performing phishing simulation with gophish
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • GoPhish binary or Docker image (https://github.com/gophish/gophish)
  • SMTP server or relay for sending test emails
  • Written authorization from management for phishing simulation
  • Target email list (HR-approved)
  • SSL/TLS certificate for landing pages
  • Python 3.8+ for automation scripts

Key Concepts

GoPhish Architecture

  • Admin Panel: Web UI for campaign management (default port 3333)
  • Phishing Server: Serves landing pages and tracks clicks (default port 80/443)
  • SMTP Configuration: Outbound email sending profile
  • Campaign Engine: Orchestrates email delivery, tracking, and reporting

Campaign Components

  1. Sending Profile: SMTP server configuration for outbound email
  2. Email Template: The phishing email content with tracking
  3. Landing Page: The fake page users are directed to
  4. User Group: Target recipients for the campaign
  5. Campaign: Combines all components with scheduling

Workflow

Step 1: Deploy GoPhish

# Docker deployment
docker pull gophish/gophish
docker run -d --name gophish -p 3333:3333 -p 8080:80 gophish/gophish
 
# Or binary deployment
wget https://github.com/gophish/gophish/releases/latest/download/gophish-v0.12.1-linux-64bit.zip
unzip gophish-v0.12.1-linux-64bit.zip
chmod +x gophish
./gophish

Step 2: Configure Sending Profile

  • Name: "Internal Mail Server"
  • SMTP From: awareness-test@yourdomain.com
  • Host: smtp.yourdomain.com:587
  • Username/Password: Service account credentials
  • Enable TLS

Step 3: Create Email Template

  • Use realistic scenarios: password reset, IT notification, HR update
  • Include GoPhish tracking pixel: {{.Tracker}}
  • Include phishing link: {{.URL}}
  • Personalize with {{.FirstName}}, {{.LastName}}, {{.Position}}

Step 4: Create Landing Page

  • Clone legitimate login page using GoPhish's import feature
  • Enable credential capture (for authorized testing only)
  • Configure redirect to training page after submission
  • Add SSL certificate for HTTPS

Step 5: Import Users and Launch Campaign

  • Import CSV with: First Name, Last Name, Email, Position
  • Set campaign schedule (stagger sends to avoid detection)
  • Launch and monitor in real-time

Step 6: Analyze Results with process.py

Use the automation script to pull campaign data via GoPhish API and generate detailed analytics reports.

Tools & Resources

Validation

  • Successfully deploy GoPhish and access admin panel
  • Create and send a test phishing email to a test mailbox
  • Capture simulated credentials on landing page
  • Generate campaign report with open/click/submit rates
  • Redirect users to awareness training after interaction
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.6 KB

API Reference — Performing Phishing Simulation with GoPhish

Libraries Used

  • requests: HTTP client for GoPhish REST API

CLI Interface

python agent.py --url https://gophish.local:3333 --api-key <key> campaigns
python agent.py --url <url> --api-key <key> metrics --id 1
python agent.py --url <url> --api-key <key> resources
python agent.py --url <url> --api-key <key> report --id 1
python agent.py --url <url> --api-key <key> launch --name "Q1 Test" --template-id 1 --page-id 1 --smtp-id 1 --group-ids 1 2 --phish-url https://phish.local

GoPhishClient API Endpoints

GET /api/campaigns/ — List all campaigns

GET /api/campaigns/{id} — Campaign details with results

POST /api/campaigns/ — Create and launch campaign

GET /api/groups/ — List target groups

GET /api/templates/ — List email templates

GET /api/smtp/ — List sending profiles

Core Functions

get_campaign_metrics(...) — Campaign performance analysis

Tracks: sent, opened, clicked, submitted, reported. Calculates percentage rates.

generate_report(...) — Risk assessment with recommendations

Risk levels: CRITICAL (>10% credential submission), HIGH (>20% click rate), MEDIUM.

list_resources(...) — Enumerate available GoPhish configurations

Campaign Status Tracking

Status Description
Email Sent Email delivered to target
Email Opened Tracking pixel loaded
Clicked Link Target clicked phishing URL
Submitted Data Target entered credentials
Reported Target reported phishing email

Dependencies

pip install requests
standards.md2.7 KB

Standards & References: Phishing Simulation with GoPhish

Legal & Compliance Framework

  • Computer Fraud and Abuse Act (CFAA): Ensure written authorization before conducting simulations
  • GDPR (EU): Data protection requirements for handling employee email addresses and click data
  • CCPA (California): Employee data privacy considerations
  • Company Acceptable Use Policy: Must align simulation with organizational policies

Industry Standards

  • NIST SP 800-50: Building an Information Technology Security Awareness and Training Program
  • NIST SP 800-16: Information Technology Security Training Requirements
  • SANS Security Awareness Maturity Model: Five levels from non-existent to metrics framework
  • ISO 27001:2022: A.6.3 - Information security awareness, education and training

MITRE ATT&CK References

  • T1566.001: Phishing: Spearphishing Attachment
  • T1566.002: Phishing: Spearphishing Link
  • T1598: Phishing for Information
  • T1204.001: User Execution: Malicious Link
  • T1204.002: User Execution: Malicious File

GoPhish Technical Reference

API Endpoints

Endpoint Method Description
/api/campaigns/ GET List all campaigns
/api/campaigns/ POST Create new campaign
/api/campaigns/{id} GET Get campaign details
/api/campaigns/{id}/results GET Get campaign results
/api/campaigns/{id}/summary GET Get campaign summary
/api/templates/ GET/POST Manage email templates
/api/pages/ GET/POST Manage landing pages
/api/smtp/ GET/POST Manage sending profiles
/api/groups/ GET/POST Manage user groups
/api/import/email POST Import email template
/api/import/site POST Import/clone website

Campaign Event Types

Event Description
Email Sent Email delivered to target
Email Opened Tracking pixel loaded
Clicked Link User clicked phishing URL
Submitted Data User entered credentials
Email Reported User reported via plugin

Phishing Simulation Best Practices

  1. Always obtain written authorization from executive management
  2. Coordinate with IT/security teams to whitelist simulation infrastructure
  3. Start with easier-to-identify phishing and increase difficulty gradually
  4. Never punish employees for failing - focus on education
  5. Provide immediate training after user interaction
  6. Run campaigns regularly (monthly/quarterly) for sustained awareness
  7. Vary scenarios across campaign types (credential harvesting, attachment, link)
  8. Respect opt-outs where legally required
  9. Protect campaign data - treat click/submit data as sensitive
  10. Report metrics anonymously when possible at department level
workflows.md3.5 KB

Workflows: Phishing Simulation with GoPhish

Workflow 1: End-to-End Campaign Execution

Phase 1: Authorization & Planning
  |
  +-- Obtain written authorization from management
  +-- Define campaign objectives and success criteria
  +-- Select target groups (by department, role, risk level)
  +-- Choose phishing scenario (credential harvest, link click, attachment)
  +-- Set campaign timeline
  |
Phase 2: Infrastructure Setup
  |
  +-- Deploy GoPhish server (Docker or bare metal)
  +-- Configure SSL/TLS certificate for landing page
  +-- Set up SMTP sending profile
  +-- Whitelist GoPhish IP in email gateway
  +-- Configure DNS for phishing domain
  +-- Test email deliverability
  |
Phase 3: Content Creation
  |
  +-- Design email template with GoPhish variables
  +-- Create or clone landing page
  +-- Set up redirect to training page
  +-- Configure credential capture (if authorized)
  +-- Test with internal team first
  |
Phase 4: Target Preparation
  |
  +-- Import user list (CSV: first,last,email,position)
  +-- Segment into groups if needed
  +-- Verify email addresses are valid
  |
Phase 5: Campaign Launch
  |
  +-- Set send schedule (staggered over hours/days)
  +-- Launch campaign
  +-- Monitor real-time dashboard
  +-- Handle any delivery issues
  |
Phase 6: Analysis & Reporting
  |
  +-- Wait for campaign duration to complete
  +-- Export results via API
  +-- Generate analytics report
  +-- Present findings to stakeholders
  +-- Identify high-risk groups for targeted training

Workflow 2: Progressive Difficulty Model

Quarter 1: Easy to Detect
  +-- Generic greeting, spelling errors
  +-- Unrelated external domain
  +-- Obvious call to action
  +-- Expected: < 20% click rate
  |
Quarter 2: Moderate Difficulty
  +-- Personalized with name/department
  +-- Look-alike domain
  +-- Relevant pretext (IT maintenance, HR policy)
  +-- Expected: < 15% click rate
  |
Quarter 3: Difficult
  +-- Highly targeted content
  +-- Convincing sender spoofing
  +-- Timely pretext (tax season, annual review)
  +-- Expected: < 10% click rate
  |
Quarter 4: Advanced
  +-- Spear-phishing with OSINT
  +-- Multi-step pretext
  +-- Mimics real vendor communication
  +-- Expected: < 5% click rate

Workflow 3: Automated Campaign via API

[Python Script] --> GoPhish API
  |
  +-- POST /api/smtp/ (create sending profile)
  +-- POST /api/templates/ (create email template)
  +-- POST /api/pages/ (create landing page)
  +-- POST /api/groups/ (import target users)
  +-- POST /api/campaigns/ (launch campaign)
  |
  [Wait for campaign duration]
  |
  +-- GET /api/campaigns/{id}/summary
  +-- GET /api/campaigns/{id}/results
  |
  [Generate report with metrics]
  |
  +-- Calculate: open rate, click rate, submit rate, report rate
  +-- Compare against baseline and industry benchmarks
  +-- Export to PDF/HTML report

Workflow 4: Post-Campaign Remediation

Campaign Results Available
  |
  v
[Identify users who submitted credentials]
  |
  +-- Immediately: Force password reset
  +-- Within 24h: Send targeted training content
  +-- Within 1 week: Manager notification (aggregate only)
  |
  v
[Identify users who clicked but did not submit]
  |
  +-- Send phishing awareness micro-training
  +-- Include specific red flags they missed
  |
  v
[Identify users who reported the email]
  |
  +-- Send positive reinforcement
  +-- Recognize in security champions program
  |
  v
[Aggregate department-level metrics]
  |
  +-- Present to leadership
  +-- Identify highest-risk departments
  +-- Plan targeted training interventions
  +-- Schedule next campaign

Scripts 2

agent.py7.5 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for performing phishing simulation campaigns with GoPhish API."""

import json
import os
import argparse
from datetime import datetime

try:
    import requests
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
except ImportError:
    requests = None


class GoPhishClient:
    """Client for GoPhish REST API."""

    def __init__(self, base_url, api_key):
        self.base_url = base_url.rstrip("/")
        self.headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}

    def _get(self, path):
        resp = requests.get(f"{self.base_url}{path}", headers=self.headers, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        resp.raise_for_status()
        return resp.json()

    def _post(self, path, data):
        resp = requests.post(f"{self.base_url}{path}", headers=self.headers, json=data, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        resp.raise_for_status()
        return resp.json()

    def get_campaigns(self):
        return self._get("/api/campaigns/")

    def get_campaign(self, campaign_id):
        return self._get(f"/api/campaigns/{campaign_id}")

    def get_campaign_results(self, campaign_id):
        return self._get(f"/api/campaigns/{campaign_id}/results")

    def create_campaign(self, name, template_id, page_id, smtp_id, group_ids, url, launch_date=None):
        data = {"name": name, "template": {"id": template_id}, "page": {"id": page_id},
                "smtp": {"id": smtp_id}, "groups": [{"id": gid} for gid in group_ids], "url": url}
        if launch_date:
            data["launch_date"] = launch_date
        return self._post("/api/campaigns/", data)

    def get_groups(self):
        return self._get("/api/groups/")

    def get_templates(self):
        return self._get("/api/templates/")

    def get_sending_profiles(self):
        return self._get("/api/smtp/")


def list_campaigns(base_url, api_key):
    """List all phishing simulation campaigns."""
    client = GoPhishClient(base_url, api_key)
    campaigns = client.get_campaigns()
    return {
        "total_campaigns": len(campaigns),
        "campaigns": [{"id": c["id"], "name": c["name"], "status": c["status"],
                        "created_date": c.get("created_date"), "launch_date": c.get("launch_date")}
                       for c in campaigns],
    }


def get_campaign_metrics(base_url, api_key, campaign_id):
    """Get detailed metrics for a phishing campaign."""
    client = GoPhishClient(base_url, api_key)
    campaign = client.get_campaign(campaign_id)
    results = campaign.get("results", [])
    stats = {"total": len(results), "sent": 0, "opened": 0, "clicked": 0, "submitted": 0, "reported": 0}
    for r in results:
        status = r.get("status", "").lower()
        if "sent" in status or "email sent" in status:
            stats["sent"] += 1
        if "opened" in status or "email opened" in status:
            stats["opened"] += 1
        if "clicked" in status:
            stats["clicked"] += 1
        if "submitted" in status:
            stats["submitted"] += 1
        if "reported" in status:
            stats["reported"] += 1
    total = max(stats["sent"], 1)
    return {
        "campaign_id": campaign_id, "name": campaign.get("name"),
        "status": campaign.get("status"),
        "stats": stats,
        "rates": {
            "open_rate": round(stats["opened"] / total * 100, 1),
            "click_rate": round(stats["clicked"] / total * 100, 1),
            "submit_rate": round(stats["submitted"] / total * 100, 1),
            "report_rate": round(stats["reported"] / total * 100, 1),
        },
    }


def launch_campaign(base_url, api_key, name, template_id, page_id, smtp_id, group_ids, url):
    """Launch a new phishing simulation campaign."""
    client = GoPhishClient(base_url, api_key)
    result = client.create_campaign(name, template_id, page_id, smtp_id, group_ids, url)
    return {"campaign_created": True, "campaign": result}


def list_resources(base_url, api_key):
    """List available templates, groups, and sending profiles."""
    client = GoPhishClient(base_url, api_key)
    return {
        "groups": [{"id": g["id"], "name": g["name"], "targets": len(g.get("targets", []))}
                   for g in client.get_groups()],
        "templates": [{"id": t["id"], "name": t["name"]} for t in client.get_templates()],
        "sending_profiles": [{"id": s["id"], "name": s["name"], "host": s.get("host")}
                             for s in client.get_sending_profiles()],
    }


def generate_report(base_url, api_key, campaign_id):
    """Generate phishing simulation report with recommendations."""
    metrics = get_campaign_metrics(base_url, api_key, campaign_id)
    recommendations = []
    if metrics["rates"]["click_rate"] > 20:
        recommendations.append("HIGH click rate — mandatory security awareness training needed")
    if metrics["rates"]["submit_rate"] > 10:
        recommendations.append("CRITICAL — over 10% submitted credentials, implement MFA immediately")
    if metrics["rates"]["report_rate"] < 5:
        recommendations.append("Low report rate — train users on how to report phishing")
    return {
        "generated": datetime.utcnow().isoformat(),
        **metrics,
        "risk_level": "CRITICAL" if metrics["rates"]["submit_rate"] > 10 else "HIGH" if metrics["rates"]["click_rate"] > 20 else "MEDIUM",
        "recommendations": recommendations,
    }


def main():
    if not requests:
        print(json.dumps({"error": "requests not installed"}))
        return
    parser = argparse.ArgumentParser(description="GoPhish Phishing Simulation Agent")
    parser.add_argument("--url", required=True, help="GoPhish server URL")
    parser.add_argument("--api-key", required=True, help="GoPhish API key")
    sub = parser.add_subparsers(dest="command")
    sub.add_parser("campaigns", help="List campaigns")
    m = sub.add_parser("metrics", help="Campaign metrics")
    m.add_argument("--id", type=int, required=True)
    sub.add_parser("resources", help="List templates, groups, profiles")
    r = sub.add_parser("report", help="Generate campaign report")
    r.add_argument("--id", type=int, required=True)
    l = sub.add_parser("launch", help="Launch new campaign")
    l.add_argument("--name", required=True)
    l.add_argument("--template-id", type=int, required=True)
    l.add_argument("--page-id", type=int, required=True)
    l.add_argument("--smtp-id", type=int, required=True)
    l.add_argument("--group-ids", nargs="+", type=int, required=True)
    l.add_argument("--phish-url", required=True)
    args = parser.parse_args()
    if args.command == "campaigns":
        result = list_campaigns(args.url, args.api_key)
    elif args.command == "metrics":
        result = get_campaign_metrics(args.url, args.api_key, args.id)
    elif args.command == "resources":
        result = list_resources(args.url, args.api_key)
    elif args.command == "report":
        result = generate_report(args.url, args.api_key, args.id)
    elif args.command == "launch":
        result = launch_campaign(args.url, args.api_key, args.name, args.template_id,
                                 args.page_id, args.smtp_id, args.group_ids, args.phish_url)
    else:
        parser.print_help()
        return
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
process.py20.0 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
GoPhish Campaign Automation and Analytics

Automates phishing simulation campaigns via the GoPhish REST API.
Creates campaigns, monitors progress, and generates detailed analytics reports.

Usage:
    python process.py create --config campaign.json
    python process.py status --campaign-id 1
    python process.py report --campaign-id 1 --output report.html
    python process.py list
"""

import argparse
import json
import sys
import csv
import os
from datetime import datetime, timezone
from pathlib import Path
from dataclasses import dataclass, field
from typing import Optional
from collections import defaultdict

try:
    import requests
    HAS_REQUESTS = True
except ImportError:
    HAS_REQUESTS = False


GOPHISH_API_URL = os.environ.get("GOPHISH_API_URL", "https://localhost:3333")
GOPHISH_API_KEY = os.environ.get("GOPHISH_API_KEY", "")


class GoPhishClient:
    """Client for interacting with the GoPhish REST API."""

    def __init__(self, api_url: str, api_key: str, verify_ssl: bool = False):
        self.api_url = api_url.rstrip("/")
        self.api_key = api_key
        self.verify_ssl = verify_ssl
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        })
        self.session.verify = verify_ssl

    def _get(self, endpoint: str) -> dict:
        resp = self.session.get(f"{self.api_url}{endpoint}")
        resp.raise_for_status()
        return resp.json()

    def _post(self, endpoint: str, data: dict) -> dict:
        resp = self.session.post(f"{self.api_url}{endpoint}", json=data)
        resp.raise_for_status()
        return resp.json()

    def _delete(self, endpoint: str) -> bool:
        resp = self.session.delete(f"{self.api_url}{endpoint}")
        resp.raise_for_status()
        return resp.status_code == 200

    # Sending Profiles
    def create_sending_profile(self, name: str, host: str, from_address: str,
                                username: str = "", password: str = "",
                                ignore_cert: bool = False) -> dict:
        data = {
            "name": name,
            "host": host,
            "from_address": from_address,
            "username": username,
            "password": password,
            "ignore_cert_errors": ignore_cert
        }
        return self._post("/api/smtp/", data)

    def list_sending_profiles(self) -> list:
        return self._get("/api/smtp/")

    # Email Templates
    def create_template(self, name: str, subject: str, html: str,
                        text: str = "", attachments: list = None) -> dict:
        data = {
            "name": name,
            "subject": subject,
            "html": html,
            "text": text,
            "attachments": attachments or []
        }
        return self._post("/api/templates/", data)

    def import_email(self, raw_email: str, convert_links: bool = True) -> dict:
        data = {
            "content": raw_email,
            "convert_links": convert_links
        }
        return self._post("/api/import/email", data)

    def list_templates(self) -> list:
        return self._get("/api/templates/")

    # Landing Pages
    def create_page(self, name: str, html: str, capture_credentials: bool = True,
                    capture_passwords: bool = False, redirect_url: str = "") -> dict:
        data = {
            "name": name,
            "html": html,
            "capture_credentials": capture_credentials,
            "capture_passwords": capture_passwords,
            "redirect_url": redirect_url
        }
        return self._post("/api/pages/", data)

    def import_site(self, url: str) -> dict:
        data = {"url": url, "include_resources": False}
        return self._post("/api/import/site", data)

    def list_pages(self) -> list:
        return self._get("/api/pages/")

    # User Groups
    def create_group(self, name: str, targets: list) -> dict:
        data = {
            "name": name,
            "targets": targets
        }
        return self._post("/api/groups/", data)

    def import_group_csv(self, name: str, csv_path: str) -> dict:
        targets = []
        with open(csv_path, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                target = {
                    "first_name": row.get("First Name", row.get("first_name", "")),
                    "last_name": row.get("Last Name", row.get("last_name", "")),
                    "email": row.get("Email", row.get("email", "")),
                    "position": row.get("Position", row.get("position", ""))
                }
                if target["email"]:
                    targets.append(target)
        return self.create_group(name, targets)

    def list_groups(self) -> list:
        return self._get("/api/groups/")

    # Campaigns
    def create_campaign(self, name: str, template_name: str, page_name: str,
                        smtp_name: str, group_names: list, url: str,
                        launch_date: str = "", send_by_date: str = "") -> dict:
        templates = self.list_templates()
        template = next((t for t in templates if t["name"] == template_name), None)

        pages = self.list_pages()
        page = next((p for p in pages if p["name"] == page_name), None)

        smtps = self.list_sending_profiles()
        smtp = next((s for s in smtps if s["name"] == smtp_name), None)

        groups_list = self.list_groups()
        groups = [g for g in groups_list if g["name"] in group_names]

        if not all([template, page, smtp, groups]):
            missing = []
            if not template:
                missing.append(f"template '{template_name}'")
            if not page:
                missing.append(f"page '{page_name}'")
            if not smtp:
                missing.append(f"smtp '{smtp_name}'")
            if not groups:
                missing.append(f"groups {group_names}")
            raise ValueError(f"Missing components: {', '.join(missing)}")

        data = {
            "name": name,
            "template": {"name": template_name},
            "page": {"name": page_name},
            "smtp": {"name": smtp_name},
            "groups": [{"name": g["name"]} for g in groups],
            "url": url
        }
        if launch_date:
            data["launch_date"] = launch_date
        if send_by_date:
            data["send_by_date"] = send_by_date

        return self._post("/api/campaigns/", data)

    def get_campaign(self, campaign_id: int) -> dict:
        return self._get(f"/api/campaigns/{campaign_id}")

    def get_campaign_summary(self, campaign_id: int) -> dict:
        return self._get(f"/api/campaigns/{campaign_id}/summary")

    def get_campaign_results(self, campaign_id: int) -> dict:
        return self._get(f"/api/campaigns/{campaign_id}/results")

    def list_campaigns(self) -> list:
        return self._get("/api/campaigns/")

    def complete_campaign(self, campaign_id: int) -> dict:
        return self._get(f"/api/campaigns/{campaign_id}/complete")


def calculate_campaign_metrics(results: dict) -> dict:
    """Calculate detailed campaign metrics from GoPhish results."""
    timeline = results.get("timeline", [])
    total_targets = len(results.get("results", []))

    events = defaultdict(set)
    for event in timeline:
        email = event.get("email", "")
        message = event.get("message", "")

        if "Email Sent" in message:
            events["sent"].add(email)
        elif "Email Opened" in message:
            events["opened"].add(email)
        elif "Clicked Link" in message:
            events["clicked"].add(email)
        elif "Submitted Data" in message:
            events["submitted"].add(email)
        elif "Email Reported" in message:
            events["reported"].add(email)

    sent = len(events["sent"])
    opened = len(events["opened"])
    clicked = len(events["clicked"])
    submitted = len(events["submitted"])
    reported = len(events["reported"])

    metrics = {
        "total_targets": total_targets,
        "emails_sent": sent,
        "emails_opened": opened,
        "links_clicked": clicked,
        "data_submitted": submitted,
        "emails_reported": reported,
        "open_rate": round(opened / max(sent, 1) * 100, 1),
        "click_rate": round(clicked / max(sent, 1) * 100, 1),
        "submit_rate": round(submitted / max(sent, 1) * 100, 1),
        "report_rate": round(reported / max(sent, 1) * 100, 1),
        "click_to_submit_rate": round(submitted / max(clicked, 1) * 100, 1),
        "resilience_score": round((1 - submitted / max(sent, 1)) * 100, 1),
    }

    # Department breakdown
    dept_stats = defaultdict(lambda: {"sent": 0, "opened": 0, "clicked": 0, "submitted": 0})
    for result in results.get("results", []):
        dept = result.get("position", "Unknown")
        email = result.get("email", "")
        dept_stats[dept]["sent"] += 1
        if email in events["opened"]:
            dept_stats[dept]["opened"] += 1
        if email in events["clicked"]:
            dept_stats[dept]["clicked"] += 1
        if email in events["submitted"]:
            dept_stats[dept]["submitted"] += 1

    metrics["department_breakdown"] = dict(dept_stats)

    return metrics


def generate_html_report(campaign: dict, metrics: dict) -> str:
    """Generate an HTML campaign report."""
    name = campaign.get("name", "Unknown Campaign")
    created = campaign.get("created_date", "")
    status = campaign.get("status", "")

    html = f"""<!DOCTYPE html>
<html>
<head>
<title>Phishing Simulation Report: {name}</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }}
.container {{ max-width: 900px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
h1 {{ color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }}
h2 {{ color: #34495e; margin-top: 30px; }}
.metric-grid {{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin: 20px 0; }}
.metric-card {{ background: #f8f9fa; padding: 20px; border-radius: 6px; text-align: center; border-left: 4px solid #3498db; }}
.metric-value {{ font-size: 32px; font-weight: bold; color: #2c3e50; }}
.metric-label {{ font-size: 14px; color: #7f8c8d; margin-top: 5px; }}
.risk-high {{ border-left-color: #e74c3c; }}
.risk-medium {{ border-left-color: #f39c12; }}
.risk-low {{ border-left-color: #27ae60; }}
table {{ width: 100%; border-collapse: collapse; margin: 15px 0; }}
th {{ background: #34495e; color: white; padding: 12px; text-align: left; }}
td {{ padding: 10px; border-bottom: 1px solid #ecf0f1; }}
tr:hover {{ background: #f8f9fa; }}
.bar {{ height: 20px; background: #3498db; border-radius: 3px; }}
.bar-container {{ background: #ecf0f1; border-radius: 3px; overflow: hidden; }}
.footer {{ margin-top: 30px; padding-top: 15px; border-top: 1px solid #ecf0f1; color: #95a5a6; font-size: 12px; }}
</style>
</head>
<body>
<div class="container">
<h1>Phishing Simulation Report</h1>
<p><strong>Campaign:</strong> {name}<br>
<strong>Date:</strong> {created}<br>
<strong>Status:</strong> {status}<br>
<strong>Generated:</strong> {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}</p>

<h2>Campaign Metrics</h2>
<div class="metric-grid">
<div class="metric-card">
    <div class="metric-value">{metrics['emails_sent']}</div>
    <div class="metric-label">Emails Sent</div>
</div>
<div class="metric-card {'risk-medium' if metrics['open_rate'] > 50 else 'risk-low'}">
    <div class="metric-value">{metrics['open_rate']}%</div>
    <div class="metric-label">Open Rate</div>
</div>
<div class="metric-card {'risk-high' if metrics['click_rate'] > 20 else 'risk-medium' if metrics['click_rate'] > 10 else 'risk-low'}">
    <div class="metric-value">{metrics['click_rate']}%</div>
    <div class="metric-label">Click Rate</div>
</div>
<div class="metric-card {'risk-high' if metrics['submit_rate'] > 10 else 'risk-medium' if metrics['submit_rate'] > 5 else 'risk-low'}">
    <div class="metric-value">{metrics['submit_rate']}%</div>
    <div class="metric-label">Submit Rate</div>
</div>
<div class="metric-card risk-low">
    <div class="metric-value">{metrics['report_rate']}%</div>
    <div class="metric-label">Report Rate</div>
</div>
<div class="metric-card">
    <div class="metric-value">{metrics['resilience_score']}%</div>
    <div class="metric-label">Resilience Score</div>
</div>
</div>

<h2>Funnel Analysis</h2>
<table>
<tr><th>Stage</th><th>Count</th><th>Rate</th><th>Visual</th></tr>
<tr><td>Emails Sent</td><td>{metrics['emails_sent']}</td><td>100%</td>
    <td><div class="bar-container"><div class="bar" style="width:100%"></div></div></td></tr>
<tr><td>Emails Opened</td><td>{metrics['emails_opened']}</td><td>{metrics['open_rate']}%</td>
    <td><div class="bar-container"><div class="bar" style="width:{metrics['open_rate']}%"></div></div></td></tr>
<tr><td>Links Clicked</td><td>{metrics['links_clicked']}</td><td>{metrics['click_rate']}%</td>
    <td><div class="bar-container"><div class="bar" style="width:{metrics['click_rate']}%"></div></div></td></tr>
<tr><td>Data Submitted</td><td>{metrics['data_submitted']}</td><td>{metrics['submit_rate']}%</td>
    <td><div class="bar-container"><div class="bar" style="width:{metrics['submit_rate']}%"></div></div></td></tr>
<tr><td>Emails Reported</td><td>{metrics['emails_reported']}</td><td>{metrics['report_rate']}%</td>
    <td><div class="bar-container"><div class="bar" style="width:{metrics['report_rate']}%"></div></div></td></tr>
</table>

<h2>Department Breakdown</h2>
<table>
<tr><th>Department</th><th>Sent</th><th>Opened</th><th>Clicked</th><th>Submitted</th><th>Click Rate</th></tr>"""

    for dept, stats in sorted(metrics.get("department_breakdown", {}).items()):
        dept_click_rate = round(stats["clicked"] / max(stats["sent"], 1) * 100, 1)
        html += f"""
<tr><td>{dept}</td><td>{stats['sent']}</td><td>{stats['opened']}</td>
<td>{stats['clicked']}</td><td>{stats['submitted']}</td><td>{dept_click_rate}%</td></tr>"""

    html += f"""
</table>

<h2>Industry Benchmarks</h2>
<table>
<tr><th>Metric</th><th>Your Result</th><th>Industry Average</th><th>Target</th></tr>
<tr><td>Click Rate</td><td>{metrics['click_rate']}%</td><td>11-15%</td><td>&lt;5%</td></tr>
<tr><td>Submit Rate</td><td>{metrics['submit_rate']}%</td><td>3-5%</td><td>&lt;2%</td></tr>
<tr><td>Report Rate</td><td>{metrics['report_rate']}%</td><td>10-15%</td><td>&gt;70%</td></tr>
</table>

<h2>Recommendations</h2>
<ul>"""

    if metrics['click_rate'] > 20:
        html += "<li><strong>High Priority:</strong> Click rate exceeds 20%. Implement mandatory phishing awareness training for all employees.</li>"
    if metrics['submit_rate'] > 10:
        html += "<li><strong>Critical:</strong> Submit rate exceeds 10%. Deploy MFA across all applications to mitigate credential harvesting risk.</li>"
    if metrics['report_rate'] < 20:
        html += "<li><strong>Improve Reporting:</strong> Report rate is low. Deploy phishing report button in email client and incentivize reporting.</li>"

    html += """
</ul>

<div class="footer">
<p>This report was generated by the GoPhish Campaign Analytics tool.
Campaign data is confidential and should be handled according to organizational data protection policies.</p>
</div>
</div>
</body>
</html>"""

    return html


def generate_text_report(campaign: dict, metrics: dict) -> str:
    """Generate a text-based campaign report."""
    name = campaign.get("name", "Unknown")
    lines = []
    lines.append("=" * 60)
    lines.append("  PHISHING SIMULATION CAMPAIGN REPORT")
    lines.append("=" * 60)
    lines.append(f"  Campaign: {name}")
    lines.append(f"  Status: {campaign.get('status', '')}")
    lines.append(f"  Created: {campaign.get('created_date', '')}")
    lines.append("")
    lines.append("[METRICS]")
    lines.append(f"  Emails Sent:     {metrics['emails_sent']}")
    lines.append(f"  Emails Opened:   {metrics['emails_opened']} ({metrics['open_rate']}%)")
    lines.append(f"  Links Clicked:   {metrics['links_clicked']} ({metrics['click_rate']}%)")
    lines.append(f"  Data Submitted:  {metrics['data_submitted']} ({metrics['submit_rate']}%)")
    lines.append(f"  Emails Reported: {metrics['emails_reported']} ({metrics['report_rate']}%)")
    lines.append(f"  Resilience:      {metrics['resilience_score']}%")
    lines.append("")
    lines.append("[DEPARTMENT BREAKDOWN]")
    for dept, stats in sorted(metrics.get("department_breakdown", {}).items()):
        rate = round(stats["clicked"] / max(stats["sent"], 1) * 100, 1)
        lines.append(f"  {dept}: {stats['sent']} sent, {stats['clicked']} clicked ({rate}%)")
    lines.append("=" * 60)
    return "\n".join(lines)


def main():
    parser = argparse.ArgumentParser(description="GoPhish Campaign Automation")
    subparsers = parser.add_subparsers(dest="command")

    # Create campaign from config
    create_parser = subparsers.add_parser("create", help="Create campaign from config")
    create_parser.add_argument("--config", required=True, help="Campaign config JSON file")

    # Campaign status
    status_parser = subparsers.add_parser("status", help="Get campaign status")
    status_parser.add_argument("--campaign-id", type=int, required=True)

    # Generate report
    report_parser = subparsers.add_parser("report", help="Generate campaign report")
    report_parser.add_argument("--campaign-id", type=int, required=True)
    report_parser.add_argument("--output", "-o", help="Output file path")
    report_parser.add_argument("--format", choices=["html", "text", "json"], default="text")

    # List campaigns
    subparsers.add_parser("list", help="List all campaigns")

    # Import users
    import_parser = subparsers.add_parser("import-users", help="Import user group from CSV")
    import_parser.add_argument("--csv", required=True, help="CSV file path")
    import_parser.add_argument("--group-name", required=True, help="Group name")

    parser.add_argument("--api-url", default=GOPHISH_API_URL)
    parser.add_argument("--api-key", default=GOPHISH_API_KEY)
    parser.add_argument("--no-verify-ssl", action="store_true")

    args = parser.parse_args()

    if not HAS_REQUESTS:
        print("Error: 'requests' library required. Install with: pip install requests",
              file=sys.stderr)
        sys.exit(1)

    api_url = args.api_url
    api_key = args.api_key

    if not api_key:
        print("Error: GoPhish API key required. Set GOPHISH_API_KEY env var or use --api-key",
              file=sys.stderr)
        sys.exit(1)

    client = GoPhishClient(api_url, api_key, verify_ssl=not args.no_verify_ssl)

    if args.command == "create":
        with open(args.config, "r") as f:
            config = json.load(f)
        result = client.create_campaign(**config)
        print(f"Campaign created: ID={result.get('id')}, Name={result.get('name')}")

    elif args.command == "status":
        summary = client.get_campaign_summary(args.campaign_id)
        print(json.dumps(summary, indent=2))

    elif args.command == "report":
        campaign = client.get_campaign(args.campaign_id)
        results = client.get_campaign_results(args.campaign_id)
        metrics = calculate_campaign_metrics(results)

        if args.format == "html":
            output = generate_html_report(campaign, metrics)
        elif args.format == "json":
            output = json.dumps({"campaign": campaign, "metrics": metrics}, indent=2, default=str)
        else:
            output = generate_text_report(campaign, metrics)

        if args.output:
            with open(args.output, "w", encoding="utf-8") as f:
                f.write(output)
            print(f"Report written to {args.output}")
        else:
            print(output)

    elif args.command == "list":
        campaigns = client.list_campaigns()
        for c in campaigns:
            print(f"  ID: {c['id']} | Name: {c['name']} | Status: {c['status']} | "
                  f"Created: {c.get('created_date', '')}")

    elif args.command == "import-users":
        result = client.import_group_csv(args.group_name, args.csv)
        targets = result.get("targets", [])
        print(f"Group '{args.group_name}' created with {len(targets)} targets")

    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 2.5 KB
Keep exploring