Compare commits

..

10 Commits

Author SHA1 Message Date
S.B 0303f7df74 Fix formatting issue in Contributing.md 2026-05-14 23:51:59 +02:00
S.B 6894c7523c Add alternative command for Bluetooth feature
Added alternative command for running with Bluetooth feature.
2026-04-22 14:09:17 +02:00
S.B 4403218c05 Update panos_authbypass_cve_2025_0108.rs 2026-04-22 14:05:57 +02:00
S.B a373f07870 Update README formatting and section headers 2026-04-22 14:04:32 +02:00
S.B ba92aa5d9e Update README with Bluetooth configuration instructions
Added instructions for turning Bluetooth ON and OFF using cargo commands.
2026-04-22 14:04:05 +02:00
S.B 4efe2a974a Merge pull request #42 from yonasBSD/yonasBSD
fix: Build on FreeBSD.
2026-04-22 14:03:40 +02:00
Yonas 699827a054 fix: Build on FreeBSD. 2026-04-21 18:36:41 -04:00
S.B 799ded9523 Update README.md 2026-04-21 23:21:18 +02:00
S.B ab748265a0 Update Cargo.toml 2026-04-21 21:25:17 +02:00
S.B 22852e571d Merge pull request #40 from s-b-repo/enic-enamle
Enic enamle
2026-04-21 21:24:35 +02:00
7 changed files with 104 additions and 12 deletions
+6 -2
View File
@@ -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"]
+20 -2
View File
@@ -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.
![Demo GIF](https://github.com/s-b-repo/rustsploit/raw/main/preview.gif)
![Testing GIF](https://github.com/s-b-repo/rustsploit/raw/main/testing.gif)
![Rustsploit Interactive Shell Demo](https://github.com/s-b-repo/rustsploit/raw/main/preview.png)
![Rustsploit Testing View](https://github.com/s-b-repo/rustsploit/raw/main/testing.png)
---
@@ -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>
+55 -2
View File
@@ -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() {
+1 -1
View File
@@ -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
View File
@@ -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))
+3 -1
View File
@@ -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;