Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f8432bda6 | |||
| 0ea3ddea2b | |||
| 9c3f4b2950 |
Generated
+1
-1
@@ -875,7 +875,7 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustbuster"
|
name = "rustbuster"
|
||||||
version = "0.1.0"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"dns-lookup",
|
"dns-lookup",
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rustbuster"
|
name = "rustbuster"
|
||||||
version = "0.1.0"
|
version = "2.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -9,7 +9,7 @@ edition = "2021"
|
|||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
dns-lookup = "2.0.4"
|
dns-lookup = "2.0.4"
|
||||||
futures = "0.3.32"
|
futures = "0.3.32"
|
||||||
|
indicatif = "0.18.4"
|
||||||
reqwest = { version = "0.12.4", features = ["blocking"] }
|
reqwest = { version = "0.12.4", features = ["blocking"] }
|
||||||
tokio = { version = "1.52.3", features = ["full"] }
|
tokio = { version = "1.52.3", features = ["full"] }
|
||||||
trust-dns-resolver = "0.23.2"
|
trust-dns-resolver = "0.23.2"
|
||||||
urlencoding = "2.1.3"
|
|
||||||
|
|||||||
+46
-24
@@ -1,5 +1,7 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use futures::{stream, StreamExt};
|
use futures::{stream, StreamExt};
|
||||||
|
use indicatif::ProgressBar;
|
||||||
|
use indicatif::ProgressStyle;
|
||||||
use reqwest::{self, StatusCode};
|
use reqwest::{self, StatusCode};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
@@ -10,7 +12,6 @@ use std::sync::Arc;
|
|||||||
use std::{collections::HashMap, fs};
|
use std::{collections::HashMap, fs};
|
||||||
use tokio::sync::mpsc::{channel, Sender};
|
use tokio::sync::mpsc::{channel, Sender};
|
||||||
use trust_dns_resolver::{config::*, TokioAsyncResolver};
|
use trust_dns_resolver::{config::*, TokioAsyncResolver};
|
||||||
use urlencoding::encode;
|
|
||||||
|
|
||||||
enum OutputMessage {
|
enum OutputMessage {
|
||||||
UrlResult(String),
|
UrlResult(String),
|
||||||
@@ -44,7 +45,7 @@ struct Args {
|
|||||||
|
|
||||||
///input file full of domains formatted to one domain per line.
|
///input file full of domains formatted to one domain per line.
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
domainfile: Option<PathBuf>,
|
indomainfile: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_sub(
|
async fn try_sub(
|
||||||
@@ -53,6 +54,7 @@ async fn try_sub(
|
|||||||
tx: Sender<OutputMessage>,
|
tx: Sender<OutputMessage>,
|
||||||
output: bool,
|
output: bool,
|
||||||
resolver: Arc<TokioAsyncResolver>,
|
resolver: Arc<TokioAsyncResolver>,
|
||||||
|
pb: Arc<ProgressBar>,
|
||||||
) {
|
) {
|
||||||
let mut ips = Vec::new();
|
let mut ips = Vec::new();
|
||||||
if let Ok(ipv4s) = resolver.ipv4_lookup(&domain).await {
|
if let Ok(ipv4s) = resolver.ipv4_lookup(&domain).await {
|
||||||
@@ -93,25 +95,26 @@ async fn try_sub(
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", domain, ips.join(", "));
|
pb.println(&format!("{} {}", domain, ips.join(", ")));
|
||||||
}
|
}
|
||||||
|
pb.inc(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool, pb: Arc<ProgressBar>) {
|
||||||
let resp_stat = reqwest::get(&encode(&url).to_string()).await;
|
let resp_stat = reqwest::get(&url).await;
|
||||||
if resp_stat.is_ok() {
|
if resp_stat.is_ok() {
|
||||||
let resp = resp_stat.unwrap().status();
|
let resp = resp_stat.unwrap().status();
|
||||||
match resp {
|
match resp {
|
||||||
StatusCode::OK => {
|
StatusCode::OK => {
|
||||||
if output {
|
if output {
|
||||||
if let Err(e) = tx
|
if let Err(e) = tx
|
||||||
.send(OutputMessage::UrlResult(format!("{} {}", resp, url)))
|
.send(OutputMessage::UrlResult(format!("{} {}", resp, &url)))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, &url));
|
||||||
}
|
}
|
||||||
StatusCode::ACCEPTED => {
|
StatusCode::ACCEPTED => {
|
||||||
if output {
|
if output {
|
||||||
@@ -122,7 +125,7 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
StatusCode::CONTINUE => {
|
StatusCode::CONTINUE => {
|
||||||
if output {
|
if output {
|
||||||
@@ -133,7 +136,7 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
StatusCode::CREATED => {
|
StatusCode::CREATED => {
|
||||||
if output {
|
if output {
|
||||||
@@ -144,7 +147,7 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
StatusCode::FOUND => {
|
StatusCode::FOUND => {
|
||||||
if output {
|
if output {
|
||||||
@@ -155,7 +158,7 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
StatusCode::IM_A_TEAPOT => {
|
StatusCode::IM_A_TEAPOT => {
|
||||||
if output {
|
if output {
|
||||||
@@ -166,7 +169,10 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("And what a beautiful teapot you are {}", url);
|
pb.println(&format!(
|
||||||
|
"{} {} - and what a beautiful teapot you are!",
|
||||||
|
resp, url
|
||||||
|
));
|
||||||
}
|
}
|
||||||
StatusCode::MOVED_PERMANENTLY => {
|
StatusCode::MOVED_PERMANENTLY => {
|
||||||
if output {
|
if output {
|
||||||
@@ -177,7 +183,7 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
StatusCode::PERMANENT_REDIRECT => {
|
StatusCode::PERMANENT_REDIRECT => {
|
||||||
if output {
|
if output {
|
||||||
@@ -188,7 +194,7 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
StatusCode::TEMPORARY_REDIRECT => {
|
StatusCode::TEMPORARY_REDIRECT => {
|
||||||
if output {
|
if output {
|
||||||
@@ -199,11 +205,12 @@ async fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
|||||||
eprintln!("error sending output! {}", e);
|
eprintln!("error sending output! {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{} {}", resp, url);
|
pb.println(&format!("{} {}", resp, url));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pb.inc(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@@ -298,7 +305,7 @@ async fn main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(domain_file) = args.domainfile {
|
if let Some(domain_file) = args.indomainfile {
|
||||||
if let Ok(domain_string) = fs::read_to_string(domain_file) {
|
if let Ok(domain_string) = fs::read_to_string(domain_file) {
|
||||||
domain_string.lines().into_iter().for_each(|domain| {
|
domain_string.lines().into_iter().for_each(|domain| {
|
||||||
targets.push(domain.to_string());
|
targets.push(domain.to_string());
|
||||||
@@ -349,7 +356,11 @@ async fn main() {
|
|||||||
for dir in dirwordlist.split("\n").collect::<Vec<&str>>() {
|
for dir in dirwordlist.split("\n").collect::<Vec<&str>>() {
|
||||||
for target in &targets {
|
for target in &targets {
|
||||||
if target.contains("http") {
|
if target.contains("http") {
|
||||||
dirs_to_try.push(format!("{}/{}", target, dir.trim()));
|
if dir.starts_with("/") || target.ends_with("/") {
|
||||||
|
dirs_to_try.push(format!("{}{}", target, dir.trim()));
|
||||||
|
} else {
|
||||||
|
dirs_to_try.push(format!("{}/{}", target, dir.trim()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,8 +377,8 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("INFO:::loading targets, and wordlists...:::");
|
println!("INFO:::loading targets, and wordlists...:::");
|
||||||
let urls_len = dirs_to_try.len();
|
let urls_len = dirs_to_try.len() as u64;
|
||||||
let domains_len = subs_to_try.len();
|
let domains_len = subs_to_try.len() as u64;
|
||||||
println!(
|
println!(
|
||||||
"INFO:::DONE!, {} URLS to try, and {} subdomains to try:::",
|
"INFO:::DONE!, {} URLS to try, and {} subdomains to try:::",
|
||||||
&urls_len, &domains_len
|
&urls_len, &domains_len
|
||||||
@@ -432,13 +443,22 @@ async fn main() {
|
|||||||
println!("INFO:::results will be printed to console and not saved...:::");
|
println!("INFO:::results will be printed to console and not saved...:::");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
let total = urls_len + domains_len;
|
||||||
|
let pb = Arc::new(ProgressBar::new(total));
|
||||||
|
pb.set_style(
|
||||||
|
ProgressStyle::with_template("[{elapsed_precise}] {bar:40.orange/red} {pos}/{len} ({eta})")
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
let resolver = TokioAsyncResolver::tokio(ResolverConfig::default(), opts);
|
let resolver = TokioAsyncResolver::tokio(ResolverConfig::default(), opts);
|
||||||
let resolver = Arc::new(resolver);
|
let resolver = Arc::new(resolver);
|
||||||
|
pb.println("starting...");
|
||||||
|
pb.force_draw();
|
||||||
let dir_stream = stream::iter(dirs_to_try.into_iter().map(|url| {
|
let dir_stream = stream::iter(dirs_to_try.into_iter().map(|url| {
|
||||||
|
let pb = pb.clone();
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
let output = output.clone();
|
let output = output.clone();
|
||||||
async move {
|
async move {
|
||||||
try_dir(url, tx, output).await;
|
try_dir(url, tx, output, pb).await;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let sub_stream = stream::iter(subs_to_try.into_iter().map(|sub| {
|
let sub_stream = stream::iter(subs_to_try.into_iter().map(|sub| {
|
||||||
@@ -446,8 +466,9 @@ async fn main() {
|
|||||||
let output = output.clone();
|
let output = output.clone();
|
||||||
let wc = wild_card_results.clone();
|
let wc = wild_card_results.clone();
|
||||||
let resolver = resolver.clone();
|
let resolver = resolver.clone();
|
||||||
|
let pb = pb.clone();
|
||||||
async move {
|
async move {
|
||||||
try_sub(sub, wc, tx, output, resolver.clone()).await;
|
try_sub(sub, wc, tx, output, resolver.clone(), pb).await;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -461,11 +482,12 @@ async fn main() {
|
|||||||
.buffer_unordered(concurrency)
|
.buffer_unordered(concurrency)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.await;
|
.await;
|
||||||
println!("INFO:::enumeration finished!:::");
|
pb.println("INFO:::enumeration finished!:::");
|
||||||
if output {
|
if output {
|
||||||
println!("INFO:::waiting for output writer to finish...:::");
|
pb.println("INFO:::waiting for output writer to finish...:::");
|
||||||
tx.send(OutputMessage::Shutdown).await.unwrap();
|
tx.send(OutputMessage::Shutdown).await.unwrap();
|
||||||
}
|
}
|
||||||
write_handler.await.unwrap();
|
write_handler.await.unwrap();
|
||||||
println!("INFO:::done bruteforcing, happy hunting!:::");
|
pb.println("INFO:::done bruteforcing, happy hunting!:::");
|
||||||
|
pb.finish_with_message("Done!");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user