362 lines
16 KiB
Rust
362 lines
16 KiB
Rust
use std::fs::{read_to_string, remove_file, OpenOptions};
|
|
use std::process::Command;
|
|
use std::thread::JoinHandle;
|
|
use std::thread::{spawn, sleep};
|
|
use std::io::Write;
|
|
use std::time::Duration;
|
|
use dns_lookup::lookup_host;
|
|
use crate::get_user_input;
|
|
use crate::Project;
|
|
use crate::open_append;
|
|
|
|
#[allow(unused)]
|
|
pub fn run_dns_enumeration(project: &Project, given_domains: Option<&Vec<String>>, standalone: bool) -> Option<JoinHandle<()>>{
|
|
let notes_folder = project.notes_folder.clone();
|
|
let mut enumeration = notes_folder.clone();
|
|
enumeration.push("enumeration.md");
|
|
let enumeration_file_res = open_append(&enumeration);
|
|
if enumeration_file_res.is_none(){
|
|
println!("error opening enumeration_file!");
|
|
println!("try creating it manually.");
|
|
return None;
|
|
}
|
|
let mut enumeration_file = enumeration_file_res.unwrap();
|
|
let mut domaind = Vec::new();
|
|
if given_domains.is_none(){
|
|
loop{
|
|
let domain = get_user_input("domain to add? enter DONE in all caps when you're finsihed");
|
|
match domain.as_str(){
|
|
"DONE" => break,
|
|
_ => domaind.push(domain),
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
for domain in given_domains.unwrap(){
|
|
domaind.push(domain.to_owned());
|
|
}
|
|
}
|
|
let working_project = project.clone();
|
|
let dns_handle = spawn(move || {
|
|
for domain in &domaind{
|
|
let output_res = Command::new("distrobox")
|
|
.arg("enter")
|
|
.arg("--root")
|
|
.arg(working_project.boxname.to_owned())
|
|
.arg("--")
|
|
.arg("dnsrecon")
|
|
.arg("-d")
|
|
.arg(domain)
|
|
.arg("-c")
|
|
.arg("dns_temp.csv")
|
|
.output();
|
|
if output_res.is_err(){
|
|
let error = output_res.err().unwrap();
|
|
println!("From DNS Enumeration Thread: error running dnsrecon in the project's distrobox!");
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
println!("sleping for 10 seconds to allow for sudo password input.");
|
|
sleep(Duration::from_secs(10));
|
|
let output_string_res = read_to_string("dns_temp.csv");
|
|
if output_string_res.is_err(){
|
|
let error = output_string_res.err().unwrap();
|
|
println!("From DNS Enumeration Thread: error reading output data!");
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
let output_string = output_string_res.unwrap();
|
|
let lines: Vec<&str> = output_string.split("\n").collect();
|
|
let mut out_data = String::new();
|
|
if standalone{
|
|
out_data.push_str("# DNS Enumeration\n");
|
|
out_data.push_str("## DNS Records\n");
|
|
}
|
|
let mut data_vec = Vec::new();
|
|
let mut first_line = true;
|
|
for line in lines{
|
|
if first_line == true{
|
|
first_line = false;
|
|
}
|
|
else{
|
|
if line.len() > 1{
|
|
let words: Vec<&str> = line.split(",").collect();
|
|
let domain_name = words[2].to_owned();
|
|
let domain_type = words[1].to_owned();
|
|
let mut data = String::new();
|
|
if words[3].len() > 2{
|
|
data = words[3].to_owned();
|
|
}
|
|
else{
|
|
data = words[6].to_owned();
|
|
}
|
|
let data_line = format!("| {} | {} | {} |", domain_name, domain_type, data);
|
|
data_vec.push(data_line);
|
|
}
|
|
}
|
|
}
|
|
let domain_header = format!("#### {}\n", domain);
|
|
out_data.push_str(&domain_header);
|
|
if standalone{
|
|
out_data.push_str("#### DNS Records\n");
|
|
}
|
|
out_data.push_str("| Domain name | Record type | data |\n");
|
|
out_data.push_str("| ----------- | ----------- | ---- |\n");
|
|
for thang in data_vec{
|
|
let out_line = format!("{}\n", thang);
|
|
out_data.push_str(&out_line);
|
|
}
|
|
if standalone{
|
|
out_data.push_str("\n---\n");
|
|
}
|
|
println!("From DNS Enumeration Thread: Finished gathering data for {} writing to notes...", domain);
|
|
write!(enumeration_file, "{}", &out_data).unwrap();
|
|
let remove_res = remove_file("dns_temp.csv");
|
|
if remove_res.is_err(){
|
|
println!("From DNS Enumeration Thread: error removing temporay data file!");
|
|
println!("From DNS Enumeration Thread: please manually delete dns_temp.csv");
|
|
}
|
|
}
|
|
});
|
|
return Some(dns_handle);
|
|
}
|
|
|
|
#[allow(unused)]
|
|
pub fn bruteforce_subs(project: &Project, given_domains: Option<&Vec<String>>, given_wordlist: Option<String>, standalone: bool) -> Option<JoinHandle<()>>{
|
|
let mut enumeration_path = project.notes_folder.clone();
|
|
enumeration_path.push("enumeration.md");
|
|
let enumeration_file_res = OpenOptions::new().append(true).create(true).open(enumeration_path);
|
|
if enumeration_file_res.is_err(){
|
|
let error = enumeration_file_res.err().unwrap();
|
|
println!("error opening enumeration notes file!");
|
|
println!("{}", error);
|
|
return None;
|
|
}
|
|
let mut enumeration_file = enumeration_file_res.unwrap();
|
|
let mut domains = Vec::new();
|
|
if given_domains.is_none(){
|
|
loop{
|
|
let domain = get_user_input("Domain to add? Enter DONE in all caps when done.");
|
|
if domain == "DONE".to_owned(){
|
|
break;
|
|
}
|
|
else{
|
|
domains.push(domain);
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
for domain in given_domains.unwrap(){
|
|
domains.push(domain.to_owned());
|
|
};
|
|
}
|
|
let mut wordlist = String::new();
|
|
if given_wordlist.is_none(){
|
|
wordlist = get_user_input("path to wordlist?");
|
|
}
|
|
else{
|
|
wordlist = given_wordlist.unwrap();
|
|
}
|
|
let working_project = project.clone();
|
|
let mut out_data = String::new();
|
|
if standalone{
|
|
out_data.push_str("# DNS Enumeration\n");
|
|
out_data.push_str("## Subdomain Enumeration\n");
|
|
}
|
|
let gobuster_thread = spawn( move ||{
|
|
for domain in domains{
|
|
if standalone{
|
|
out_data.push_str(format!("#### {}\n", &domain).as_str());
|
|
}
|
|
let gobuster_cmd_res = Command::new("distrobox")
|
|
.arg("enter")
|
|
.arg("--root")
|
|
.arg(working_project.boxname.to_owned())
|
|
.arg("--")
|
|
.arg("gobuster")
|
|
.arg("dns")
|
|
.arg("-d")
|
|
.arg(&domain)
|
|
.arg("-w")
|
|
.arg(wordlist.to_owned())
|
|
.output();
|
|
if gobuster_cmd_res.is_err(){
|
|
let error = gobuster_cmd_res.err().unwrap();
|
|
println!("From gobuster thread: Error running gobuster command!");
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
println!("sleeping for 10 seconds to allow for sudo password input.");
|
|
sleep(Duration::from_secs(10));
|
|
let gobuser_output = gobuster_cmd_res.unwrap().stdout;
|
|
println!("From Gobuster Thread: Sudomain enumeration Done!");
|
|
let gobuster_string = String::from_utf8_lossy(&gobuser_output);
|
|
let mut domain_names = Vec::new();
|
|
let lines: Vec<&str> = gobuster_string.split("\n").collect();
|
|
for line in lines{
|
|
if line.contains("Found:"){
|
|
let domain = line.split_whitespace().collect::<Vec<&str>>()[1];
|
|
domain_names.push(domain.to_owned());
|
|
}
|
|
}
|
|
out_data.push_str("\n| domain name | ips |\n");
|
|
out_data.push_str("| ----------- | --- |\n");
|
|
for name in domain_names{
|
|
let ips = lookup_host(&name);
|
|
if ips.is_ok(){
|
|
let mut ip_string = String::new();
|
|
for ip in ips.unwrap(){
|
|
ip_string = format!("{},{}", ip, ip_string);
|
|
}
|
|
out_data.push_str(format!("| {} | {} |\n", name, ip_string).as_str());
|
|
}
|
|
}
|
|
}
|
|
if standalone{
|
|
out_data.push_str("\n---\n");
|
|
}
|
|
let write_res = write!(enumeration_file, "{}", out_data);
|
|
if write_res.is_err(){
|
|
let error = write_res.err().unwrap();
|
|
println!("FROM Gobuster Thread: error writing notes!");
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
write_res.unwrap();
|
|
});
|
|
return Some(gobuster_thread);
|
|
}
|
|
|
|
pub fn dns_squatting(project: &Project, given_domains: Option<&Vec<String>>, standalone: bool) -> Option<JoinHandle<()>>{
|
|
let mut enumeration_notes = project.notes_folder.clone();
|
|
enumeration_notes.push("enumeration.md");
|
|
let open_enumeration_notes_res = OpenOptions::new().append(true).create(true).open(enumeration_notes);
|
|
if open_enumeration_notes_res.is_err(){
|
|
let error = open_enumeration_notes_res.err().unwrap();
|
|
println!("Error opening enumeration notes");
|
|
println!("{}", error);
|
|
return None;
|
|
}
|
|
let mut enumeration_file = open_enumeration_notes_res.unwrap();
|
|
let mut domains = Vec::new();
|
|
if given_domains.is_none(){
|
|
loop{
|
|
let domain = get_user_input("Domain to add? enter DONE in all caps when you're finished");
|
|
if domain == "DONE"{
|
|
break;
|
|
}
|
|
else{
|
|
domains.push(domain);
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
domains = given_domains.unwrap().to_owned();
|
|
}
|
|
let working_project = project.clone();
|
|
let squatting_thread = spawn(move || {
|
|
let write_res = write!(enumeration_file, "### Domain Squatting\n");
|
|
if write_res.is_err(){
|
|
let error = write_res.err().unwrap();
|
|
println!("error writing to enumeration notes file!");
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
write_res.unwrap();
|
|
for domain in domains{
|
|
if standalone{
|
|
write!(enumeration_file, "#### {}\n", domain).unwrap();
|
|
}
|
|
write!(enumeration_file, "\n| type | domain name | ns servers |\n").unwrap();
|
|
write!(enumeration_file, "| ---- | ----------- | ---------- |\n").unwrap();
|
|
let twist_output = Command::new("distrobox")
|
|
.arg("enter")
|
|
.arg("--root")
|
|
.arg(working_project.boxname.to_owned())
|
|
.arg("--")
|
|
.arg("dnstwist")
|
|
.arg("-r")
|
|
.arg(domain)
|
|
.output();
|
|
if twist_output.is_err(){
|
|
let error = twist_output.err().unwrap();
|
|
println!("From DNSTwist thread: Error running dnstwist command!");
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
println!("sleeping for 10 seconds to allow for sudo password input.");
|
|
sleep(Duration::from_secs(10));
|
|
let twist_output_vec = twist_output.unwrap().stdout;
|
|
let output_string = String::from_utf8_lossy(&twist_output_vec);
|
|
let output_lines = output_string.split("\n");
|
|
for line in output_lines{
|
|
if line.len() > 0{
|
|
let words: Vec<&str> = line.split_whitespace().collect();
|
|
let twist_type = words[0];
|
|
let name = words[1];
|
|
let ns_servers = words[2..].join(" ");
|
|
write!(enumeration_file, "| {} | {} | {} |\n", twist_type, name, ns_servers).unwrap();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return Some(squatting_thread);
|
|
}
|
|
|
|
pub fn do_all_dns_enumeration(project: &Project) -> Option<JoinHandle<()>>{
|
|
let mut enumeration_path = project.notes_folder.clone();
|
|
enumeration_path.push("enumeration.md");
|
|
let enumeration_file_res = OpenOptions::new().append(true).create(true).open(enumeration_path);
|
|
if enumeration_file_res.is_err(){
|
|
let error = enumeration_file_res.err().unwrap();
|
|
println!("error opening enumeration notes file!");
|
|
println!("{}", error);
|
|
return None;
|
|
}
|
|
let mut enumeration_file = enumeration_file_res.unwrap();
|
|
let mut domains = Vec::new();
|
|
loop{
|
|
let domain = get_user_input("Domain to add? enter DONE in all caps when you're finished");
|
|
if domain == "DONE"{
|
|
break;
|
|
}
|
|
else{
|
|
domains.push(domain);
|
|
}
|
|
}
|
|
let wordlist = get_user_input("path to wordlist for sub domain bruteforcing?");
|
|
let working_project = project.clone();
|
|
let all_dns_handle = spawn(move ||{
|
|
let mut write_success = true;
|
|
let write_res = write!(enumeration_file, "# DNS Enumeration\n");
|
|
if write_res.is_err(){
|
|
let error = write_res.err().unwrap();
|
|
println!("From All DNS thread: Error writing notes file!");
|
|
println!("{}", error);
|
|
write_success = false;
|
|
}
|
|
if write_success{
|
|
for domain in &domains{
|
|
let thread_domain = vec![domain.to_owned()];
|
|
write!(enumeration_file, "## {}\n", &domain).unwrap();
|
|
write!(enumeration_file, "### DNS Records\n").unwrap();
|
|
let dns_enum_thread = run_dns_enumeration(&working_project, Some(&thread_domain), false);
|
|
if dns_enum_thread.is_some(){
|
|
let _ = dns_enum_thread.unwrap().join();
|
|
}
|
|
write!(enumeration_file, "### Subdomain Enumeration\n").unwrap();
|
|
let gobuster_thread = bruteforce_subs(&working_project, Some(&thread_domain), Some(wordlist.to_owned()), false);
|
|
if gobuster_thread.is_some(){
|
|
let _ = gobuster_thread.unwrap().join();
|
|
}
|
|
write!(enumeration_file, "### Domain Squatting\n").unwrap();
|
|
let twist_thread = dns_squatting(&working_project, Some(&thread_domain), false);
|
|
if twist_thread.is_some(){
|
|
let _ = twist_thread.unwrap().join();
|
|
}
|
|
write!(enumeration_file, "\n---\n").unwrap();
|
|
}
|
|
}
|
|
});
|
|
return Some(all_dns_handle);
|
|
} |