mirror of
https://github.com/s-b-repo/rustsploit
synced 2026-06-27 09:54:12 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0303f7df74 | |||
| 6894c7523c | |||
| 4403218c05 | |||
| a373f07870 | |||
| ba92aa5d9e | |||
| 4efe2a974a | |||
| 699827a054 | |||
| 799ded9523 | |||
| ab748265a0 | |||
| 22852e571d |
+6
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustsploit"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
|
||||
@@ -64,7 +64,7 @@ rlimit = "0.11"
|
||||
|
||||
|
||||
# Bluetooth
|
||||
btleplug = "0.12"
|
||||
btleplug = { version = "0.12", optional = true }
|
||||
|
||||
# WPair migrated from ratatui+crossterm TUI to rustyline REPL — deps removed.
|
||||
|
||||
@@ -163,3 +163,7 @@ strip = true
|
||||
inherits = "release"
|
||||
lto = "thin" # Faster than fat LTO
|
||||
codegen-units = 4 # Parallel codegen
|
||||
|
||||
[features]
|
||||
default = ["bluetooth"]
|
||||
bluetooth = ["dep:btleplug"]
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
Modular offensive tooling for embedded targets, written in Rust and inspired by RouterSploit/Metasploit. Rustsploit ships an interactive shell, a command-line runner, and an ever-growing library of exploits, scanners, and credential modules for routers, cameras, appliances, and general network services.
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -63,6 +64,23 @@ Full documentation lives in the **[Rustsploit Wiki](docs/Home.md)**. Below is a
|
||||
```bash
|
||||
sudo apt update && sudo apt install -y build-essential pkg-config libssl-dev libdbus-1-dev cmake && (command -v cargo > /dev/null 2>&1 || (curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && . "$HOME/.cargo/env")) && git clone https://github.com/s-b-repo/rustsploit.git && cd rustsploit && cargo run
|
||||
```
|
||||
## How to turn Bluetooth OFF (e.g. on FreeBSD without Bluetooth hardware):
|
||||
|
||||
```
|
||||
cargo build --no-default-features
|
||||
```
|
||||
## or
|
||||
```
|
||||
cargo run --no-default-features
|
||||
```
|
||||
## How to turn Bluetooth ON
|
||||
```
|
||||
cargo build --features bluetooth
|
||||
```
|
||||
## or
|
||||
```
|
||||
cargo run --features bluetooth
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>What each dependency does</summary>
|
||||
|
||||
@@ -16,6 +16,9 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check which features are enabled
|
||||
let features = Features::detect();
|
||||
|
||||
// Discover categories dynamically from subdirectories of src/modules/
|
||||
let mut categories: Vec<String> = Vec::new();
|
||||
let entries = match fs::read_dir(modules_root) {
|
||||
@@ -31,6 +34,11 @@ fn main() {
|
||||
if path.is_dir() {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if !name.starts_with('.') {
|
||||
// Skip categories that are entirely disabled
|
||||
if features.should_skip_category(name) {
|
||||
println!("cargo:warning=Skipping category '{}' (feature disabled)", name);
|
||||
continue;
|
||||
}
|
||||
categories.push(name.to_string());
|
||||
}
|
||||
}
|
||||
@@ -42,6 +50,9 @@ fn main() {
|
||||
for cat in &categories {
|
||||
println!("cargo:rerun-if-changed=src/modules/{}", cat);
|
||||
}
|
||||
|
||||
// Also rerun if features change
|
||||
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_BLUETOOTH");
|
||||
|
||||
// Compile regexes once, reuse across all categories.
|
||||
let run_re = Regex::new(r"pub\s+async\s+fn\s+run\s*\(\s*[^)]*:\s*&str\s*\)")
|
||||
@@ -60,7 +71,7 @@ fn main() {
|
||||
let out_file = format!("{}_dispatch.rs", dispatch_name(cat));
|
||||
let display_name = capitalize(cat);
|
||||
|
||||
match generate_dispatch(&root, &out_file, &mod_prefix, &display_name, &run_re, &info_re, &check_re) {
|
||||
match generate_dispatch(&root, &out_file, &mod_prefix, &display_name, &run_re, &info_re, &check_re, &features) {
|
||||
Ok(_module_count) => {
|
||||
registry_entries.push(RegistryEntry {
|
||||
category: cat.clone(),
|
||||
@@ -81,6 +92,40 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Feature detection and module filtering
|
||||
struct Features {
|
||||
bluetooth: bool,
|
||||
}
|
||||
|
||||
impl Features {
|
||||
fn detect() -> Self {
|
||||
Self {
|
||||
bluetooth: env::var("CARGO_FEATURE_BLUETOOTH").is_ok(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a category should be entirely skipped
|
||||
fn should_skip_category(&self, category: &str) -> bool {
|
||||
match category {
|
||||
"bluetooth" => !self.bluetooth,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a module path should be skipped (for feature-gated submodules)
|
||||
fn should_skip_module(&self, module_path: &str) -> bool {
|
||||
// If bluetooth feature is disabled, skip any module under bluetooth/
|
||||
if !self.bluetooth && module_path.starts_with("bluetooth/") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add more feature checks here as needed
|
||||
// Example: if !self.some_feature && module_path.starts_with("some/path/")
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct RegistryEntry {
|
||||
category: String,
|
||||
dispatch_name: String,
|
||||
@@ -118,6 +163,7 @@ fn generate_dispatch(
|
||||
run_re: &Regex,
|
||||
info_re: &Regex,
|
||||
check_re: &Regex,
|
||||
features: &Features,
|
||||
) -> Result<usize, Box<dyn std::error::Error>> {
|
||||
let out_dir = env::var("OUT_DIR").map_err(|_| "OUT_DIR environment variable not set")?;
|
||||
let dest_path = Path::new(&out_dir).join(out_file);
|
||||
@@ -127,7 +173,7 @@ fn generate_dispatch(
|
||||
return Err(format!("Module directory '{}' does not exist", root).into());
|
||||
}
|
||||
|
||||
let mappings = find_modules(root_path, run_re, info_re, check_re)?;
|
||||
let mappings = find_modules(root_path, run_re, info_re, check_re, features)?;
|
||||
|
||||
// Sort for deterministic output
|
||||
let mut sorted_mappings: Vec<_> = mappings.into_iter().collect();
|
||||
@@ -411,6 +457,7 @@ fn find_modules(
|
||||
run_re: &Regex,
|
||||
info_re: &Regex,
|
||||
check_re: &Regex,
|
||||
features: &Features,
|
||||
) -> Result<HashSet<ModuleMapping>, Box<dyn std::error::Error>> {
|
||||
let mut mappings = HashSet::new();
|
||||
|
||||
@@ -422,6 +469,12 @@ fn find_modules(
|
||||
|
||||
if let Ok(relative) = path.strip_prefix(root) {
|
||||
let rel_str = relative.with_extension("").to_string_lossy().replace("\\", "/");
|
||||
|
||||
// Skip modules that are feature-gated out
|
||||
if features.should_skip_module(&rel_str) {
|
||||
println!("cargo:warning=Skipping module '{}' (feature disabled)", rel_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut content = String::new();
|
||||
if File::open(path).and_then(|mut f| f.read_to_string(&mut content)).is_ok() {
|
||||
|
||||
@@ -60,7 +60,7 @@ If your module discovers credentials, hosts, or services, use the framework help
|
||||
|
||||
```rust
|
||||
crate::cred_store::store_credential(host, port, "ssh", user, pass,
|
||||
crate::cred_store::CredType::Password, "my_module");
|
||||
crate::cred_store::CredType::Password, "my_module");
|
||||
crate::workspace::track_host(ip, Some("hostname"), None);
|
||||
crate::workspace::track_service(ip, 22, "tcp", "ssh", Some("OpenSSH 8.9"));
|
||||
```
|
||||
|
||||
+18
-3
@@ -7,23 +7,38 @@ use super::types::{
|
||||
ServerInfo, ToolsCapability,
|
||||
};
|
||||
|
||||
// You can place this function in src/mcp/server.rs or a shared utility module
|
||||
fn errno() -> i32 {
|
||||
unsafe {
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
{ *libc::__error() }
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{ *libc::__errno_location() }
|
||||
|
||||
// Add fallbacks for other OSes if needed
|
||||
#[cfg(not(any(target_os = "freebsd", target_os = "macos", target_os = "linux")))]
|
||||
{ 0 } // Or compile_error! to force checking for a new OS
|
||||
}
|
||||
}
|
||||
|
||||
fn isolate_protocol_stdout() -> anyhow::Result<tokio::fs::File> {
|
||||
use std::os::fd::FromRawFd;
|
||||
unsafe {
|
||||
let saved_fd = libc::dup(1);
|
||||
if saved_fd < 0 {
|
||||
anyhow::bail!("dup(1) failed: errno {}", *libc::__errno_location());
|
||||
anyhow::bail!("dup(1) failed: errno {}", errno());
|
||||
}
|
||||
let null_path = b"/dev/null\0";
|
||||
let null_fd = libc::open(null_path.as_ptr() as *const libc::c_char, libc::O_WRONLY);
|
||||
if null_fd < 0 {
|
||||
libc::close(saved_fd);
|
||||
anyhow::bail!("open(/dev/null) failed: errno {}", *libc::__errno_location());
|
||||
anyhow::bail!("open(/dev/null) failed: errno {}", errno());
|
||||
}
|
||||
if libc::dup2(null_fd, 1) < 0 {
|
||||
libc::close(null_fd);
|
||||
libc::close(saved_fd);
|
||||
anyhow::bail!("dup2(null, 1) failed: errno {}", *libc::__errno_location());
|
||||
anyhow::bail!("dup2(null, 1) failed: errno {}", errno());
|
||||
}
|
||||
libc::close(null_fd);
|
||||
let std_file = std::fs::File::from_raw_fd(saved_fd);
|
||||
|
||||
@@ -318,7 +318,7 @@ fn sendmmsg_batch(
|
||||
msg
|
||||
}).collect();
|
||||
|
||||
let ret = unsafe { libc::sendmmsg(fd, msgs.as_mut_ptr(), count as u32, 0) };
|
||||
let ret = unsafe { libc::sendmmsg(fd, msgs.as_mut_ptr(), (count as u32).try_into().unwrap(), 0) };
|
||||
if ret < 0 {
|
||||
let errno = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
|
||||
(0, Some(errno))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod bluetooth;
|
||||
pub mod cameras;
|
||||
pub mod cowrie;
|
||||
pub mod crypto;
|
||||
@@ -20,3 +19,6 @@ pub mod vnc;
|
||||
pub mod voip;
|
||||
pub mod webapps;
|
||||
pub mod windows;
|
||||
|
||||
#[cfg(feature = "bluetooth")]
|
||||
pub mod bluetooth;
|
||||
|
||||
Reference in New Issue
Block a user