Skip to content

Latest commit

 

History

History
285 lines (212 loc) · 11 KB

File metadata and controls

285 lines (212 loc) · 11 KB

Module Development

Reference for maintainers and contributors writing new Rustsploit modules.


How Modules Are Discovered

Rustsploit uses a build-time code-generation approach — no manual registry:

  1. build.rs scan — Before compilation, build.rs recursively walks src/modules/ looking for .rs files that are not mod.rs.

  2. Signature detection — A file that exposes pub async fn run( is treated as a callable module.

  3. Name generation — Both a short name (ssh_bruteforce) and a qualified path (creds/generic/ssh_bruteforce) are registered.

  4. Dispatcher emission — Generated files are written into OUT_DIR (not the source tree):

    • exploit_dispatch.rs
    • creds_dispatch.rs
    • scanner_dispatch.rs
    • plugins_dispatch.rs
    • module_registry.rs

    Each dispatch file contains an exhaustive match mapping names → use crate::modules::...::run. The registry file provides a unified module listing across all categories.

  5. Shell + CLI resolutionuse exploits/foo or --module foo both resolve through the dispatcher.

Because it's generated at build time, there is no manual registry drift as long as modules live in the correct folder and export run.


Code Rules

  • No dead code. All code must be intentional and used. Do not leave unused functions, imports, or variables.
  • No unsafe blocks. Do not use unsafe Rust anywhere in this codebase.

Project Code Layout

rustsploit/
├── Cargo.toml
├── build.rs                  # Generates dispatcher by scanning src/modules
├── src/
│   ├── main.rs               # Entry point — CLI or shell mode, input validation
│   ├── cli.rs                # Clap-based CLI parser and dispatcher
│   ├── shell.rs              # Interactive shell loop + UX helpers
│   ├── api.rs                # REST + WebSocket API server — PQ encryption, rate limiting
│   ├── ws.rs                 # PQ-encrypted WebSocket transport (/pq/ws)
│   ├── config.rs             # Global config and target validation
│   ├── module_info.rs        # ModuleInfo, CheckResult, ModuleRank types
│   ├── global_options.rs     # Persistent global options (setg/unsetg)
│   ├── cred_store.rs         # Credential store (JSON persistence)
│   ├── spool.rs              # Console output logging
│   ├── workspace.rs          # Host/service tracking + workspaces
│   ├── loot.rs               # Loot/evidence management
│   ├── export.rs             # JSON/CSV/summary report export
│   ├── jobs.rs               # Background job management
│   ├── mcp/
│   │   ├── mod.rs            # MCP server entry point (--mcp flag)
│   │   ├── server.rs         # JSON-RPC stdio transport with binary-safe reads
│   │   └── tools.rs          # 38 MCP tool implementations
│   ├── commands/
│   │   ├── mod.rs            # Module discovery, fuzzy matching, multi-target dispatch
│   │   ├── exploit.rs
│   │   ├── scanner.rs
│   │   └── creds.rs
│   ├── modules/
│   │   ├── exploits/         # Exploit modules (183 modules, 21 categories)
│   │   ├── scanners/         # Scanner modules (27 modules)
│   │   ├── creds/            # Credential modules (29 modules)
│   │   └── plugins/          # Plugin modules (1 module)
│   ├── native/               # Native integrations
│   │   ├── mod.rs
│   │   ├── rdp.rs            # Native RDP auth (X.224, TLS, CredSSP/NTLM)
│   │   ├── payload_engine.rs # Payload encoding/generation
│   │   ├── url_encoding.rs   # URL encoding utilities
│   │   └── async_tls.rs      # Async TLS helpers
│   └── utils/                # Shared helpers (directory module)
│       ├── mod.rs            # Re-exports
│       ├── prompt.rs         # Config-aware prompts (cfg_prompt_*)
│       ├── sanitize.rs       # Input validation, length limits
│       ├── target.rs         # Target normalization (IPv4/IPv6/CIDR/hostname)
│       ├── network.rs        # HTTP client builders, TCP/UDP connect helpers
│       ├── privilege.rs      # Root privilege check (require_root)
│       └── modules.rs        # Module discovery helpers
├── docs/                     # This wiki
├── lists/                    # Wordlists and data files
└── README.md                 # Product overview

Required Module Signature

Every module must export:

use anyhow::Result;

pub async fn run(target: &str) -> Result<()> {
    // ...
    Ok(())
}

Optional: also expose pub async fn run_interactive(target: &str) -> Result<()> for modules with multiple code paths.


Optional Module Functions

Modules can optionally provide metadata and vulnerability check functions. These are auto-detected by build.rs alongside run():

Module Info (info)

use crate::module_info::{ModuleInfo, ModuleRank};

pub fn info() -> ModuleInfo {
    ModuleInfo {
        name: "My Exploit Module".to_string(),
        description: "Exploits CVE-XXXX-YYYY in FooBar device firmware.".to_string(),
        authors: vec!["Your Name".to_string()],
        references: vec![
            "CVE-XXXX-YYYY".to_string(),
            "https://example.com/advisory".to_string(),
        ],
        disclosure_date: Some("2025-01-15".to_string()),
        rank: ModuleRank::Good,
    }
}

The info shell command and GET /api/module/{category}/{name} endpoint display this metadata.

Rank values: Excellent (reliable, no crash risk), Great, Good (default), Normal, Low, Manual.

Vulnerability Check (check)

use crate::module_info::CheckResult;

pub async fn check(target: &str) -> CheckResult {
    // Non-destructive verification — do NOT exploit
    match test_vulnerability(target).await {
        Ok(true) => CheckResult::Vulnerable("Version 1.2.3 is affected".to_string()),
        Ok(false) => CheckResult::NotVulnerable("Patched version detected".to_string()),
        Err(e) => CheckResult::Error(format!("Check failed: {}", e)),
    }
}

The check shell command and POST /api/check endpoint run this without exploitation.

Auto-Store Credentials and Loot

Modules can auto-store discovered data:

// Store a found credential
crate::cred_store::store_credential(host, port, "ssh", username, password,
    crate::cred_store::CredType::Password, "creds/generic/ssh_bruteforce");

// Store loot (config file, hash dump, etc.)
crate::loot::store_loot(host, "config", "Router config dump", data.as_bytes(), "exploits/router_rce");

// Track a discovered host/service
crate::workspace::track_host(ip, Some("router.local"), Some("Linux 4.x"));
crate::workspace::track_service(ip, 22, "tcp", "ssh", Some("OpenSSH 8.9"));

Adding a New Module — Checklist

  1. Choose a location under src/modules/{exploits,scanners,creds}.
    Use subfolders for vendor families (e.g., exploits/cisco/).
  2. Create the .rs file with the required pub async fn run signature.
  3. Register in mod.rs — add pub mod your_module; to the sibling mod.rs.
    Without this, build.rs ignores the file.
  4. Run cargo check — the dispatcher is regenerated automatically.

Module Skeleton

use anyhow::{Context, Result};
use colored::Colorize;
use crate::utils::{normalize_target, cfg_prompt_port, cfg_prompt_yes_no};

pub async fn run(target: &str) -> Result<()> {
    let target = normalize_target(target)?;
    let port = cfg_prompt_port("port", "Target port", 80).await?;
    let verbose = cfg_prompt_yes_no("verbose", "Verbose output?", false).await?;

    println!("{} Checking {}:{}", "[*]".cyan(), target, port);

    let url = format!("http://{}:{}/status", target, port);
    let body = reqwest::get(&url)
        .await
        .with_context(|| format!("Failed to reach {}", url))?
        .text()
        .await
        .context("Failed to read response body")?;

    if body.contains("vulnerable") {
        println!("{} {} appears vulnerable", "[+]".green(), target);
    } else {
        if verbose {
            println!("{} Response: {}", "[*]".cyan(), body);
        }
        println!("{} {} not vulnerable", "[-]".red(), target);
    }

    Ok(())
}

Output Conventions

Prefix Color Meaning
[+] Green Success / found
[-] Red Not found / not vulnerable
[!] Yellow Warning
[*] Cyan Info / progress

Use .green(), .red(), .yellow(), .cyan() from the colored crate. Keep messages short and actionable.


Async I/O Guidelines

  • Prefer reqwest, tokio::net, tokio::process for async work.
  • Wrap synchronous blocking calls with tokio::task::spawn_blocking (see the SSH module for reference).
  • For concurrency:
    • tokio::sync::Semaphore (wrapped in Arc) for async modules.
    • threadpool + crossbeam-channel for synchronous protocols (Telnet, POP3).

Error Handling

Bubble up errors using anyhow::Context so the shell/CLI surface meaningful messages:

.with_context(|| format!("Failed to connect to {}", target))?

Avoid unwrap() and unwrap_or_default() in critical paths.


Wordlists & Resources

Store under lists/ and document them in lists/readme.md. Reference paths relative to the working directory.


Framework-Level Multi-Target Dispatch

The framework's command dispatcher (src/commands/mod.rs) automatically handles multiple target types for all modules. Module authors do not need to implement multi-target logic themselves -- the dispatcher wraps each module's run() function and handles:

  • Comma-separated targets: 192.168.1.1,192.168.1.2,10.0.0.1 -- splits and dispatches each entry individually.
  • CIDR subnets: 192.168.1.0/24 -- expands the subnet and runs the module against each host IP.
  • File-based target lists: If the target string is a path to an existing file, each line is read and dispatched as a separate target.
  • Random mass scan: 0.0.0.0, 0.0.0.0/0, or random -- generates random public IPs in an infinite loop (Ctrl+C to stop).

This means a module that only handles a single host in its run() function automatically gains subnet scanning, file-based targeting, and mass-scan capability through the framework.


0.0.0.0/0 Internet-Wide Scanning

Modules supporting mass-scan accept 0.0.0.0, 0.0.0.0/0, or random as targets. When detected, the module enters an infinite loop generating random public IPs using:

fn generate_random_public_ip() -> Ipv4Addr { ... }
fn is_excluded_ip(ip: Ipv4Addr) -> bool { ... }

The EXCLUDED_RANGES constant covers bogons, private, reserved, documentation CIDRs, and public DNS servers. Copy this pattern from an existing mass-scan module (e.g., telnet_hose or hikvision_rce).

Honeypot detection is disabled in mass-scan mode to avoid interactive prompts.