Compare commits
5 Commits
1.0
...
82562b0106
| Author | SHA1 | Date | |
|---|---|---|---|
| 82562b0106 | |||
| 6127f4357b | |||
| dd6b7668d6 | |||
| d51d84b88a | |||
| d8affb25d6 |
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug
|
||||||
|
target
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Generated by cargo mutants
|
||||||
|
# Contains mutation testing data
|
||||||
|
**/mutants.out*/
|
||||||
|
|
||||||
|
# rustc will dump stack traces when hitting an internal compiler error to PWD
|
||||||
|
rustc-ice-*.txt
|
||||||
|
|
||||||
|
# RustRover
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
Generated
-1344
File diff suppressed because it is too large
Load Diff
@@ -8,4 +8,6 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
dns-lookup = "2.0.4"
|
dns-lookup = "2.0.4"
|
||||||
|
rayon = "1.12.0"
|
||||||
reqwest = { version = "0.12.4", features = ["blocking"] }
|
reqwest = { version = "0.12.4", features = ["blocking"] }
|
||||||
|
trust-dns-resolver = "0.23.2"
|
||||||
|
|||||||
+324
-83
@@ -1,21 +1,31 @@
|
|||||||
use std::fs;
|
|
||||||
use reqwest::{self, StatusCode};
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
|
use rayon::ThreadPoolBuilder;
|
||||||
|
use reqwest::{self, StatusCode};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::BufWriter;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::sync::mpsc::{channel, Sender};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use dns_lookup::lookup_host;
|
use std::{collections::HashMap, fs};
|
||||||
|
use trust_dns_resolver::config::*;
|
||||||
|
use trust_dns_resolver::Resolver;
|
||||||
|
|
||||||
|
enum OutputMessage {
|
||||||
|
UrlResult(String),
|
||||||
|
SubDomainResult(String),
|
||||||
|
Shutdown,
|
||||||
|
}
|
||||||
|
|
||||||
/// Subdomain Bruteforcer, and directory bruteforcer written in rust, and multi threaded!!!
|
/// Subdomain Bruteforcer, and directory bruteforcer written in rust, and multi threaded!!!
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
struct Args{
|
struct Args {
|
||||||
/// target to attack, can be a URL or a dns name, you can specify more than one by comma separating the targets
|
/// target to attack, can be a URL or a dns name, you can specify more than one by comma separating the targets
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
target: String,
|
target: Option<String>,
|
||||||
|
|
||||||
///Threads to use, there is not upper limit so if you lock up your comptuer that's on you
|
|
||||||
#[arg(long)]
|
|
||||||
threads: usize,
|
|
||||||
|
|
||||||
/// wordlist to use for subdomains
|
/// wordlist to use for subdomains
|
||||||
#[arg(short, long, default_value_t = String::from("none"))]
|
#[arg(short, long, default_value_t = String::from("none"))]
|
||||||
@@ -24,42 +34,158 @@ struct Args{
|
|||||||
///wordlist to use for directories
|
///wordlist to use for directories
|
||||||
#[arg(short, long, default_value_t = String::from("none"))]
|
#[arg(short, long, default_value_t = String::from("none"))]
|
||||||
dirwordlist: String,
|
dirwordlist: String,
|
||||||
|
|
||||||
|
///output files to write, will create two files yourinput_urls.txt and yourinput_subs.txt
|
||||||
|
#[arg(short, long)]
|
||||||
|
outfile: Option<String>,
|
||||||
|
|
||||||
|
///input file full of urls formatted to one url per line.
|
||||||
|
#[arg(short, long)]
|
||||||
|
urlfile: Option<PathBuf>,
|
||||||
|
|
||||||
|
///input file full of domains formatted to one domain per line.
|
||||||
|
#[arg(short, long)]
|
||||||
|
domainfile: Option<PathBuf>,
|
||||||
|
|
||||||
|
///number of threads to use by default it will use the rayon global pool default.
|
||||||
|
#[arg(long)]
|
||||||
|
threads: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_sub(
|
||||||
fn try_sub(domain: String){
|
domain: String,
|
||||||
let ips = lookup_host(&domain);
|
wildcard_reses: HashMap<&String, Vec<String>>,
|
||||||
if ips.is_ok(){
|
tx: Sender<OutputMessage>,
|
||||||
let mut ip_string = String::new();
|
output: bool,
|
||||||
for ip in ips.unwrap(){
|
) {
|
||||||
ip_string = format!("{},{}",ip, ip_string);
|
let mut opts = ResolverOpts::default();
|
||||||
|
opts.edns0 = true;
|
||||||
|
let resolver = Resolver::new(ResolverConfig::default(), opts).unwrap();
|
||||||
|
let mut ips = Vec::new();
|
||||||
|
if let Ok(ipv4s) = resolver.ipv4_lookup(&domain) {
|
||||||
|
ipv4s.iter().for_each(|ip| ips.push(ip.0.to_string()));
|
||||||
}
|
}
|
||||||
println!("{} {}", domain, ip_string);
|
if let Ok(ipv6s) = resolver.ipv6_lookup(&domain) {
|
||||||
|
ipv6s.iter().for_each(|ip| ips.push(ip.0.to_string()));
|
||||||
|
}
|
||||||
|
let mut wild_card = None;
|
||||||
|
for target in wildcard_reses.keys() {
|
||||||
|
if domain.contains(&target.to_string()) {
|
||||||
|
wild_card = wildcard_reses.get(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ips.is_empty() {
|
||||||
|
if let Some(wild_ips) = wild_card {
|
||||||
|
if ips.len() == wild_ips.len() {
|
||||||
|
let mut wild_only = true;
|
||||||
|
for ip in &ips {
|
||||||
|
if !wild_ips.contains(ip) {
|
||||||
|
wild_only = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wild_only {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::SubDomainResult(format!(
|
||||||
|
"{}: {}",
|
||||||
|
&domain,
|
||||||
|
ips.join(", ")
|
||||||
|
))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", domain, ips.join(", "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_dir(url: String, tx: Sender<OutputMessage>, output: bool) {
|
||||||
fn try_dir(url: String){
|
|
||||||
let resp_stat = reqwest::blocking::get(&url);
|
let resp_stat = reqwest::blocking::get(&url);
|
||||||
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 => println!("{} {}",resp, url),
|
StatusCode::OK => {
|
||||||
StatusCode::ACCEPTED => println!("{} {}", resp, url),
|
if output {
|
||||||
StatusCode::CONTINUE => println!("{} {}", resp, url),
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
StatusCode::CREATED => println!("{} {}", resp, url),
|
eprintln!("error sending output! {}", e);
|
||||||
StatusCode::FOUND => println!("{} {}", resp, url),
|
}
|
||||||
StatusCode::IM_A_TEAPOT => println!("And what a beautiful teapot you are {}", url),
|
}
|
||||||
StatusCode::MOVED_PERMANENTLY => println!("{} {}", resp, url),
|
println!("{} {}", resp, url);
|
||||||
StatusCode::PERMANENT_REDIRECT => println!("{} {}", resp, url),
|
}
|
||||||
StatusCode::TEMPORARY_REDIRECT => println!("{} {}", resp, url),
|
StatusCode::ACCEPTED => {
|
||||||
_ => ()
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
StatusCode::CONTINUE => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
StatusCode::CREATED => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
StatusCode::FOUND => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
StatusCode::IM_A_TEAPOT => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("And what a beautiful teapot you are {}", url);
|
||||||
|
}
|
||||||
|
StatusCode::MOVED_PERMANENTLY => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
StatusCode::PERMANENT_REDIRECT => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
StatusCode::TEMPORARY_REDIRECT => {
|
||||||
|
if output {
|
||||||
|
if let Err(e) = tx.send(OutputMessage::UrlResult(format!("{} {}", resp, url))) {
|
||||||
|
eprintln!("error sending output! {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{} {}", resp, url);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("
|
print!(
|
||||||
|
"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -129,74 +255,189 @@ fn main() {
|
|||||||
╙█▄▄▄▀▀▀▓▄▄▄▄▄▄▄▓▀▀
|
╙█▄▄▄▀▀▀▓▄▄▄▄▄▄▄▓▀▀
|
||||||
|
|
||||||
|
|
||||||
");
|
"
|
||||||
|
);
|
||||||
let mut dirs_to_try = Vec::new();
|
let mut dirs_to_try = Vec::new();
|
||||||
let mut subs_to_try = Vec::new();
|
let mut subs_to_try = Vec::new();
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let mut targets = Vec::new();
|
let mut targets = Vec::new();
|
||||||
for target in args.target.split(",").collect::<Vec<&str>>(){
|
let (tx, rx) = channel();
|
||||||
|
if let Some(given_targets) = args.target {
|
||||||
|
for target in given_targets.split(",").collect::<Vec<&str>>() {
|
||||||
targets.push(target.to_owned());
|
targets.push(target.to_owned());
|
||||||
}
|
}
|
||||||
if args.dirwordlist != String::from("none"){
|
}
|
||||||
let dirwordlist = fs::read_to_string(args.dirwordlist).expect("error reading directory wordlist");
|
if let Some(url_file) = args.urlfile {
|
||||||
for dir in dirwordlist.split("\n").collect::<Vec<&str>>(){
|
if let Ok(url_string) = fs::read_to_string(url_file) {
|
||||||
dirs_to_try.push(dir.trim_end().trim_start().to_owned());
|
url_string.lines().into_iter().for_each(|url| {
|
||||||
|
targets.push(url.to_string());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if args.subwordlist != String::from("none"){
|
if let Some(domain_file) = args.domainfile {
|
||||||
let subwordlist = fs::read_to_string(args.subwordlist).expect("error reading subdomain word list");
|
if let Ok(domain_string) = fs::read_to_string(domain_file) {
|
||||||
for sub in subwordlist.split("\n").collect::<Vec<&str>>(){
|
domain_string.lines().into_iter().for_each(|domain| {
|
||||||
subs_to_try.push(sub.trim_end().trim_start().to_owned())
|
targets.push(domain.to_string());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut domains_to_try = Vec::new();
|
if targets.is_empty() {
|
||||||
let mut urls_to_try = Vec::new();
|
println!("no targets provided!");
|
||||||
println!("loading targets, and wordlists...");
|
exit(1);
|
||||||
for target in targets{
|
}
|
||||||
if target.contains("/"){
|
if let Some(thread) = args.threads {
|
||||||
for dir in &dirs_to_try{
|
ThreadPoolBuilder::new()
|
||||||
let url = format!("{}/{}", target, dir);
|
.num_threads(thread)
|
||||||
urls_to_try.push(url.to_owned());
|
.build_global()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"INFO:::{} threads will be used:::",
|
||||||
|
rayon::current_num_threads()
|
||||||
|
);
|
||||||
|
println!("detecting if a wild card record exists...");
|
||||||
|
let mut opts = ResolverOpts::default();
|
||||||
|
opts.edns0 = true;
|
||||||
|
let resolver = Resolver::new(ResolverConfig::default(), opts).unwrap();
|
||||||
|
let mut wild_card_results = HashMap::new();
|
||||||
|
for target in &targets {
|
||||||
|
if !target.contains("http") {
|
||||||
|
subs_to_try.push(target.clone());
|
||||||
|
let mut ips = Vec::new();
|
||||||
|
if let Ok(ipv4s) = resolver.ipv4_lookup(&format!("burstpyrofoo.{}", target)) {
|
||||||
|
ipv4s.iter().for_each(|ip| {
|
||||||
|
ips.push(ip.0.to_string());
|
||||||
|
});
|
||||||
|
println!("INFO:::wildcard found: {} {}:::", target, ips.join(", "));
|
||||||
|
}
|
||||||
|
if let Ok(ipv6s) = resolver.ipv6_lookup(&format!("burstpyrofoo.{}", target)) {
|
||||||
|
println!("wildcard found!");
|
||||||
|
ipv6s.iter().for_each(|ip| {
|
||||||
|
ips.push(ip.0.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !ips.is_empty() {
|
||||||
|
wild_card_results.insert(target, ips);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dirs_to_try.push(target.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if target.contains(".") == true{
|
if args.dirwordlist != String::from("none") {
|
||||||
for sub in &subs_to_try{
|
let dirwordlist =
|
||||||
let domain = format!("{}.{}", sub, target);
|
fs::read_to_string(args.dirwordlist).expect("error reading directory wordlist");
|
||||||
domains_to_try.push(domain.to_owned());
|
for dir in dirwordlist.split("\n").collect::<Vec<&str>>() {
|
||||||
}
|
for target in &targets {
|
||||||
}
|
if target.contains("http") {
|
||||||
else{
|
dirs_to_try.push(format!("{}/{}", target, dir.trim()));
|
||||||
println!("{} is not a valid target, please supply either a domain or url", target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut threads = Vec::new();
|
|
||||||
let urls_len = urls_to_try.len();
|
|
||||||
let domains_len = domains_to_try.len();
|
|
||||||
println!("DONE!, {} URLS to try, and {} subdomains to try", &urls_len, &domains_len);
|
|
||||||
if urls_len > 0{
|
|
||||||
let dir_chunk_size = urls_len / &args.threads;
|
|
||||||
let url_vecs: Vec<Vec<String>> = urls_to_try.chunks(dir_chunk_size).map(|x| x.to_vec()).collect();
|
|
||||||
for urlvec in url_vecs{
|
|
||||||
for url in urlvec{
|
|
||||||
threads.push(thread::spawn(move || {
|
|
||||||
try_dir(url)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if domains_len > 0 {
|
}
|
||||||
let domain_chunk_size = domains_len /&args.threads;
|
if args.subwordlist != String::from("none") {
|
||||||
let domain_vecs: Vec<Vec<String>> = domains_to_try.chunks(domain_chunk_size).map(|x| x.to_vec()).collect();
|
let subwordlist =
|
||||||
for domainvec in domain_vecs{
|
fs::read_to_string(args.subwordlist).expect("error reading subdomain word list");
|
||||||
for domain in domainvec{
|
for sub in subwordlist.split("\n").collect::<Vec<&str>>() {
|
||||||
threads.push(thread::spawn(move || {
|
for target in &targets {
|
||||||
try_sub(domain);
|
if !target.contains("http") {
|
||||||
}))
|
subs_to_try.push(format!("{}.{}", sub.trim(), target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for thread in threads{
|
|
||||||
let _ = thread.join();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("done bruteforcing, happy hunting!");
|
println!("INFO:::loading targets, and wordlists...:::");
|
||||||
|
let urls_len = dirs_to_try.len();
|
||||||
|
let domains_len = subs_to_try.len();
|
||||||
|
println!(
|
||||||
|
"INFO:::DONE!, {} URLS to try, and {} subdomains to try:::",
|
||||||
|
&urls_len, &domains_len
|
||||||
|
);
|
||||||
|
let mut output = false;
|
||||||
|
let mut urlpath = PathBuf::new();
|
||||||
|
let mut subpath = PathBuf::new();
|
||||||
|
if args.outfile.is_some() {
|
||||||
|
output = true;
|
||||||
|
let path = args.outfile.clone().unwrap();
|
||||||
|
urlpath = PathBuf::from(format!("{}_urls.txt", &path));
|
||||||
|
subpath = PathBuf::from(format!("{}_subs.txt", &path));
|
||||||
|
println!(
|
||||||
|
"INFO:::results will be saved to {}_urls.txt and {}_subs.txt:::",
|
||||||
|
path, path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let write_handler = thread::spawn(move || {
|
||||||
|
if output {
|
||||||
|
let urlfile = File::create(urlpath).unwrap();
|
||||||
|
let subfile = File::create(subpath).unwrap();
|
||||||
|
let mut urlwrite = BufWriter::new(urlfile);
|
||||||
|
let mut subwrite = BufWriter::new(subfile);
|
||||||
|
const FLUSHEVERY: usize = 10;
|
||||||
|
let mut url_counter = 0;
|
||||||
|
let mut sub_counter = 0;
|
||||||
|
loop {
|
||||||
|
let msg = rx.recv().unwrap();
|
||||||
|
match msg {
|
||||||
|
OutputMessage::UrlResult(res) => {
|
||||||
|
if let Err(e) = writeln!(urlwrite, "{}", res) {
|
||||||
|
println!("error writing url file! {}", e);
|
||||||
|
} else {
|
||||||
|
url_counter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputMessage::SubDomainResult(res) => {
|
||||||
|
if let Err(e) = writeln!(subwrite, "{}", res) {
|
||||||
|
println!("error writing sub file! {}", e);
|
||||||
|
} else {
|
||||||
|
sub_counter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputMessage::Shutdown => {
|
||||||
|
urlwrite.flush().unwrap();
|
||||||
|
subwrite.flush().unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if url_counter == FLUSHEVERY {
|
||||||
|
if let Err(e) = urlwrite.flush() {
|
||||||
|
println!("error writing url file! {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sub_counter == FLUSHEVERY {
|
||||||
|
if let Err(e) = subwrite.flush() {
|
||||||
|
println!("error writing sub file! {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("INFO:::results will be printed to console and not saved...:::");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rayon::scope(|s| {
|
||||||
|
if !dirs_to_try.is_empty() {
|
||||||
|
s.spawn(|_| {
|
||||||
|
dirs_to_try.par_iter().for_each(|url| {
|
||||||
|
try_dir(url.to_string(), tx.clone(), output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !subs_to_try.is_empty() {
|
||||||
|
s.spawn(|_| {
|
||||||
|
subs_to_try.par_iter().for_each(|sub| {
|
||||||
|
try_sub(
|
||||||
|
sub.to_string(),
|
||||||
|
wild_card_results.clone(),
|
||||||
|
tx.clone(),
|
||||||
|
output,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
println!("INFO:::enumeration finished!:::");
|
||||||
|
if output {
|
||||||
|
println!("INFO:::waiting for output writer to finish...:::");
|
||||||
|
tx.send(OutputMessage::Shutdown).unwrap();
|
||||||
|
}
|
||||||
|
write_handler.join().unwrap();
|
||||||
|
println!("INFO:::done bruteforcing, happy hunting!:::");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user