added the ability to run dnstwist scans for

dns enumeration, and added the ability to modify
the tool's configuration.
This commit is contained in:
Pyro57000
2025-05-27 12:18:52 -05:00
parent 737bee37e7
commit 55a6faac2d
4 changed files with 233 additions and 4 deletions

View File

@@ -17,6 +17,7 @@ use crate::portscan_controls;
use crate::victim_commands;
use crate::enumeration;
use crate:: tool_controls;
use crate::configuration;
fn help(command: Option<String>){
@@ -59,6 +60,7 @@ fn help(command: Option<String>){
"dns records" | "dr" => {println!("Command:dnsrecords\nAliases:dr\n\nThis command will run dns recon inside of your distrobox and save the results to your enumeration notes.")},
"brute force subdomains"| "bsd" | "gobuster dns" | "gd" => {println!("Command:brute force subdomains\nAliases:bsd,gobuster dns, gd\n\nthis command will run gobuster in the project's distrobox and save the results to your notes.")},
"dns enumeration" | "de" | "all dns stuff" | "ads" | "dns stuff" | "ds" => {println!("Command:dns enumeration\nAliases:de, all dns stuff, ads, dns stuff, de\n\nThis command will perform both dns record enumeration with dnsrecon, and subdomain enumeration using gobster inside of your distrobox and save the output to your notes.")},
"modify tool config" | "mtc" => {println!("modify the tool config");}
_ => ()
}
}
@@ -216,7 +218,9 @@ pub fn run_command(cmd: String,
"dns records" | "dr" => {let dns_handle = enumeration::run_dns_enumeration(&active_project, None, true); return dns_handle;},
"brute force subdomains"| "bsd" | "gobuster dns" | "gd" => {let gobuster_handle = enumeration::bruteforce_subs(&active_project, None,None, true); return gobuster_handle},
"dns enumeration" | "de" | "all dns stuff" | "ads" | "dns stuff" | "ds" => {let all_dns_handle = enumeration::do_all_dns_enumeration(&active_project); return all_dns_handle},
"dns squatting scan" | "dnstwist" | "dss" => {let twist_handle = enumeration::dns_squatting(&active_project, None, true); return twist_handle},
"print report information" | "pri" => {info_controls::print_report_information(&active_project); return None;},
"modify tool config" | "mtc" => {configuration::generate_tool_config(&config_path); return None;},
_ => {help(None); println!("\n\n unknown command."); return None;}
}
}

View File

@@ -0,0 +1,147 @@
use std::{fmt::write, path::PathBuf};
use std::fs::read_to_string;
use std::io::Write;
use crate::{get_user_input, open_overwrite, Project};
pub fn generate_tool_config(config_dir: &PathBuf){
let mut config_file_path = config_dir.clone();
println!("{}", config_file_path.display());
let mut current_config = String::new();
let current_config_read_res = read_to_string(&config_file_path);
if current_config_read_res.is_ok(){
current_config = current_config_read_res.unwrap();
println!("current configuration loaded!");
}
print!("{}", current_config);
let mut project_base_folder = PathBuf::new();
let mut project_base_notes = PathBuf::new();
let mut tools_folder = PathBuf::new();
let mut terminal_command = String::new();
let mut box_template = String::new();
let mut cracking_rig = String::new();
let mut rockyou = String::new();
let mut rule = String::new();
let mut upcoming_files = PathBuf::new();
let mut upcoming_notes = PathBuf::new();
let mut pass_spray_file = PathBuf::new();
let mut fingerprint = false;
let mut vault_name = String::new();
let settings: Vec<&str> = current_config.split("\n").collect();
for line in settings{
if line.len() > 1{
let setting_vec: Vec<&str> = line.split(":").collect();
match setting_vec[0]{
"Project_files" => project_base_folder.push(setting_vec[1].trim_end()),
"Project_notes" => project_base_notes.push(setting_vec[1].trim_end()),
"tools_folder" => tools_folder.push(setting_vec[1].trim_end()),
"upcoming_files" => upcoming_files.push(setting_vec[1].trim_end()),
"upcoming_notes" => upcoming_notes.push(setting_vec[1].trim_end()),
"box_template" => box_template = setting_vec[1].trim_end().to_owned(),
"terminal" => terminal_command = setting_vec[1].trim_end().to_owned(),
"cracking_rig" => cracking_rig = setting_vec[1].trim_end().to_owned(),
"rockyou_location" => rockyou = setting_vec[1].trim_end().to_owned(),
"rule_location" => rule = setting_vec[1].trim_end().to_owned(),
"pass_file"=> pass_spray_file.push(setting_vec[1]),
"fingerprint" => {if setting_vec[1].contains("y"){fingerprint = true}},
"vault_name" => vault_name = setting_vec[1].trim_end().to_owned(),
_ => println!("error unknown setting: {}", setting_vec[0])
}
}
}
println!("1.) recreate entire configuration");
println!("2.) modify one setting");
if get_user_input("Selection?").contains("2"){
print!("
1 .) project_files
2 .) project_notes
3 .) tools_folder
4 .) upcoming_files
5 .) upcoming_notes
6 .) box_template
7 .) terminal
8 .) cracking_rig
9 .) rockyou_location
10.) rule_location
11.) pass_file
12.) fingerprint
13.) vault_name
");
match get_user_input("which setting would you like to modify?").as_str(){
"1" => {project_base_folder.clear(); project_base_folder.push(get_user_input("full path to the base project files folder?"));},
"2" => {project_base_notes.clear(); project_base_notes.push(get_user_input("full path to the base project notes folder"));},
"3" => {tools_folder.clear(); tools_folder.push(get_user_input("full path to your custom tools folder?"));},
"4" => {upcoming_files.clear(); upcoming_files.push(get_user_input("full path to your upcoming projects folder"));},
"5" => {upcoming_notes.clear(); upcoming_notes.push(get_user_input("full path to your upcoming project nots folder"));},
"6" => {box_template = get_user_input("name of your distrobox template?")},
"7" => {terminal_command = get_user_input("comand to run your terminal while executing a specific command, ex: konsole -e ")},
"8" => {cracking_rig = get_user_input("username and address of your personal cracking rig, example pyro@crackingrig or pyro@192.168.1.10?")},
"9" => {rockyou = get_user_input("location of rockyou.txt on your cracking rig?")},
"10" => {rule = get_user_input("location of the one rule on your crakcing rig?")},
"11" => {pass_spray_file.clear(); pass_spray_file.push(get_user_input("location of your password spray list file?"));},
"12" => {fingerprint = get_user_input("will you be using fingerprint authentication in your distroboxes?").to_lowercase().contains("y")},
"13" => {vault_name = get_user_input("obsidian vault name?")},
_ => {println!("unknown selection, please try again...");}
};
}
else{
project_base_folder = PathBuf::from(get_user_input("path to store your active projects?"));
project_base_notes = PathBuf::from(get_user_input("path to store your active project notes?"));
upcoming_files = PathBuf::from(get_user_input("path to store your upcomming projects?"));
upcoming_notes = PathBuf::from(get_user_input("path to store your upcomming project notes?"));
tools_folder = PathBuf::from(get_user_input("path where you store your custom tools (like from github and places)?"));
box_template = get_user_input("Name of the distrobox you want to use as a template?");
cracking_rig = String::from("nobody@nothing");
rockyou = String::from("n/a");
rule = String::from("n/a");
let cracking_rig_response = get_user_input("do you have a separate machine to crack passwords on? (not the ambush cracking rig)");
if cracking_rig_response.to_lowercase().contains("y"){
let rig_ip = get_user_input("ip address or hostname of your cracking rig?");
let rig_user = get_user_input("username to log into your cracking rig with?");
rockyou = get_user_input("location of rockyou.txt on the cracking rig?");
rule = get_user_input("location of one rule to rule them all on the cracking rig?");
cracking_rig = format!("{}@{}", rig_user, rig_ip);
}
else{
println!("ok free loader");
}
fingerprint = get_user_input("will you be using fingerprint authentication for your distroboxes?").to_lowercase().contains("y");
terminal_command = get_user_input("command to launch your terminal, while executing a command, for example konsel -e ");
vault_name = get_user_input("the name of the vault you're going to use?");
}
let new_config = format!("
Project_files:{}
Project_notes:{}
tools_folder:{}
upcoming_files:{}
upcoming_notes:{}
box_template:{}
terminal:{}
cracking_rig:{}
rockyou_location:{}
rule_location:{}
pass_file:{}
fingerprint:{}
vault_name:{}
",project_base_folder.display(), project_base_notes.display(), tools_folder.display(), upcoming_files.display(), upcoming_notes.display(), box_template, terminal_command, cracking_rig, rockyou, rule, pass_spray_file.display(), fingerprint, vault_name);
println!("this will be the new config that will be saved:\n");
println!("{}", new_config);
if get_user_input("is this ok?").to_lowercase().contains("y"){
let config_file_res = open_overwrite(&config_file_path);
if config_file_res.is_none(){
println!("failed to open config file in overwrite mode... quitting... nothing was saved.");
return;
}
let mut config_file = config_file_res.unwrap();
let write_res= write!(config_file, "{}", new_config);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("error writing config file!");
println!("{}", error);
println!("nothing was saved...");
return;
}
write_res.unwrap();
}
}

View File

@@ -1,14 +1,12 @@
use core::error;
use std::fmt::write;
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::{self, Write};
use std::io::Write;
use std::time::Duration;
use dns_lookup::lookup_host;
use crate::enumeration;
use crate::get_user_input;
use crate::info_controls::get_scope_entries;
use crate::Project;
use crate::open_append;
@@ -225,6 +223,80 @@ pub fn bruteforce_subs(project: &Project, given_domains: Option<&Vec<String>>, g
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;
}
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");
@@ -271,6 +343,11 @@ pub fn do_all_dns_enumeration(project: &Project) -> Option<JoinHandle<()>>{
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();
}
}

View File

@@ -27,6 +27,7 @@ mod portscan_controls;
mod victim_commands;
mod enumeration;
mod tool_controls;
mod configuration;
pub fn open_overwrite(path: &PathBuf) -> Option<File>{
let file_create_res = fs::OpenOptions::new().create(true).write(true).open(path);