Add support for using wordlists.

Random user agent per request support.
Bump dependencies.
Performance improvement dropping the tasks once finished.

Signed-off-by: Edu4rdSHL <edu4rdshl@protonmail.com>
This commit is contained in:
Edu4rdSHL 2021-05-09 04:51:02 -05:00
parent a4220feeb2
commit 4439d45a10
No known key found for this signature in database
GPG key ID: 3A574A4009F553E5
5 changed files with 349 additions and 363 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target /target
/hosts.txt /hosts.txt
*.txt

609
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -12,8 +12,9 @@ readme = "README.md"
# 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
[dependencies] [dependencies]
tokio = { version = "0.2.22", features = ["full"] } tokio = { version = "1.5.0", features = ["full", "io-util"] }
futures = "0.3.5" futures = "0.3.14"
clap = "2.33.3" clap = "2.33.3"
reqwest = { version = "0.10.8", features = ["default-tls"] } reqwest = { version = "0.11.3", features = ["default-tls"] }
openssl = { version = "0.10.30", features = ["vendored"] } openssl = { version = "0.10.34", features = ["vendored"] }
rand = "0.8.3"

View file

@ -1,7 +1,9 @@
mod utils;
use { use {
clap::{value_t, App, Arg}, clap::{value_t, App, Arg},
futures::stream::StreamExt, futures::stream::StreamExt,
reqwest, reqwest::{self, header::USER_AGENT},
tokio::{ tokio::{
self, self,
io::{self, AsyncReadExt}, io::{self, AsyncReadExt},
@ -28,13 +30,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.takes_value(true) .takes_value(true)
.help("Timeout in seconds. Default: 3"), .help("Timeout in seconds. Default: 3"),
) )
.arg(
Arg::with_name("user-agent")
.short("u")
.long("user-agent")
.takes_value(true)
.help("User agent string."),
)
.arg( .arg(
Arg::with_name("show-codes") Arg::with_name("show-codes")
.short("s") .short("s")
@ -42,6 +37,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.takes_value(false) .takes_value(false)
.help("Show status codes for discovered hosts."), .help("Show status codes for discovered hosts."),
) )
.arg(
Arg::with_name("domain")
.short("d")
.long("domain")
.takes_value(true)
.help("Target domain."),
)
.arg( .arg(
Arg::with_name("1xx") Arg::with_name("1xx")
.short("1") .short("1")
@ -94,41 +96,53 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
0 0
}; };
let threads = value_t!(matches.value_of("threads"), usize).unwrap_or_else(|_| 100); let threads = value_t!(matches.value_of("threads"), usize).unwrap_or_else(|_| 100);
let timeout = value_t!(matches.value_of("timeout"), u64).unwrap_or_else(|_| 3); let timeout = value_t!(matches.value_of("timeout"), u64).unwrap_or_else(|_| 5);
let user_agent = value_t!(matches.value_of("user-agent"), String).unwrap_or_else(|_| "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36".to_string()); let user_agents_list = utils::user_agents();
let show_status_codes = matches.is_present("show-codes"); let show_status_codes = matches.is_present("show-codes");
let client = reqwest::Client::builder() let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(timeout)) .timeout(std::time::Duration::from_secs(timeout))
.danger_accept_invalid_certs(true) .danger_accept_invalid_certs(true)
.user_agent(user_agent)
.build()?; .build()?;
// Read stdin // Read stdin
let mut buffer = String::new();
let mut stdin = io::stdin(); let mut stdin = io::stdin();
let mut buffer = String::new();
stdin.read_to_string(&mut buffer).await?; stdin.read_to_string(&mut buffer).await?;
let hosts: Vec<String> = buffer.lines().map(str::to_owned).collect();
let hosts: Vec<String> = if matches.is_present("domain") {
let domain = value_t!(matches, "domain", String).unwrap();
buffer
.lines()
.map(|word| format!("{}.{}", word, domain))
.collect()
} else {
buffer.lines().map(str::to_owned).collect()
};
futures::stream::iter(hosts.into_iter().map(|host| { futures::stream::iter(hosts.into_iter().map(|host| {
// Use a random user agent
let user_agent = utils::return_random_string(&user_agents_list);
// HTTP/HTTP URLs // HTTP/HTTP URLs
let https_url = format!("https://{}", host); let https_url = format!("https://{}", host);
let http_url = format!("http://{}", host); let http_url = format!("http://{}", host);
// Create futures // Create futures
let https_send_fut = client.get(&https_url).send(); let https_send_fut = client.get(&https_url).header(USER_AGENT, &user_agent);
let http_send_fut = client.get(&http_url).send(); let http_send_fut = client.get(&http_url).header(USER_AGENT, &user_agent);
async move { async move {
let mut response_code = 0; let mut response_code = 0;
let mut valid_url = String::new(); let mut valid_url = String::new();
if let Ok(resp) = https_send_fut.await { if let Ok(resp) = https_send_fut.send().await {
valid_url = https_url; valid_url = https_url;
response_code = resp.status().as_u16(); response_code = resp.status().as_u16();
} else if let Ok(resp) = http_send_fut.await { drop(resp)
} else if let Ok(resp) = http_send_fut.send().await {
valid_url = http_url; valid_url = http_url;
response_code = resp.status().as_u16() response_code = resp.status().as_u16();
drop(resp)
} }
if (!valid_url.is_empty() && conditional_response_code == 0) if (!valid_url.is_empty() && conditional_response_code == 0)
|| ((!valid_url.is_empty() && conditional_response_code != 0) || ((!valid_url.is_empty() && conditional_response_code != 0)
&& (response_code >= conditional_response_code && (response_code >= conditional_response_code

41
src/utils.rs Normal file
View file

@ -0,0 +1,41 @@
use rand::{seq::SliceRandom, thread_rng};
pub fn user_agents() -> Vec<String> {
vec!["Mozilla/5.0 (Windows NT 6.1; WOW64; rv:77.0) Gecko/20190101 Firefox/77.0".to_string(),
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:77.0) Gecko/20100101 Firefox/77.0".to_string(),
"Mozilla/5.0 (X11; Linux ppc64le; rv:75.0) Gecko/20100101 Firefox/75.0".to_string(),
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/75.0".to_string(),
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.10; rv:75.0) Gecko/20100101 Firefox/75.0".to_string(),
"Mozilla/5.0 (X11; Linux; rv:74.0) Gecko/20100101 Firefox/74.0".to_string(),
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/73.0".to_string(),
"Mozilla/5.0 (X11; OpenBSD i386; rv:72.0) Gecko/20100101 Firefox/72.0".to_string(),
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:71.0) Gecko/20100101 Firefox/71.0".to_string(),
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:70.0) Gecko/20191022 Firefox/70.0".to_string(),
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:70.0) Gecko/20190101 Firefox/70.0".to_string(),
"Mozilla/5.0 (Windows; U; Windows NT 9.1; en-US; rv:12.9.1.11) Gecko/20100821 Firefox/70".to_string(),
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:69.2.1) Gecko/20100101 Firefox/69.2".to_string(),
"Mozilla/5.0 (Windows NT 6.1; rv:68.7) Gecko/20100101 Firefox/68.7".to_string(),
"Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0".to_string(),
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19582".to_string(),
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19577".to_string(),
"Mozilla/5.0 (X11) AppleWebKit/62.41 (KHTML, like Gecko) Edge/17.10859 Safari/452.6".to_string(),
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14931".to_string(),
"Chrome (AppleWebKit/537.1; Chrome50.0; Windows NT 6.3) AppleWebKit/537.36 (KHTML like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393".to_string(),
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.9200".to_string(),
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586".to_string(),
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246".to_string(),
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36".to_string(),
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36".to_string(),
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36".to_string(),
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36".to_string(),
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36".to_string(),
]
}
pub fn return_random_string(strings: &[String]) -> String {
if strings.is_empty() {
String::new()
} else {
strings.choose(&mut thread_rng()).unwrap().to_string()
}
}