mirror of
https://github.com/s-b-repo/rustsploit
synced 2026-06-27 09:54:12 +00:00
286 lines
11 KiB
Markdown
286 lines
11 KiB
Markdown
# 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 resolution** — `use 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
|
|
|
|
```text
|
|
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:
|
|
|
|
```rust
|
|
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`)
|
|
|
|
```rust
|
|
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`)
|
|
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
// 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
|
|
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
.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:
|
|
|
|
```rust
|
|
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.
|