diff --git a/pentest_tool/src/main.rs b/pentest_tool/src/main.rs index 6a106b2..f2a4554 100644 --- a/pentest_tool/src/main.rs +++ b/pentest_tool/src/main.rs @@ -1,9 +1,13 @@ +use std::collections::HashMap; use std::env; use std::fs; +use std::fs::read_to_string; use std::io::Write; use std::path::PathBuf; use std::process; use std::str::FromStr; +use std::thread; +use std::time::Duration; use clearscreen::clear; use directories::UserDirs; use clearscreen; @@ -22,6 +26,12 @@ struct Project{ fn install(config_path: &PathBuf){ + let mut _terminal_commands = HashMap::from([ + ("konsole", "konsole -e !!!"), + ("gnome", "gnome-terminal -- bash !!!"), + ("xfce", "xfce4-terminal --execute '!!!'"), + ("alacritty", "alacritty -e !!!"), + ]); let mut config_folder_path: PathBuf = config_path.clone(); config_folder_path.pop(); let mut projects_conf_path = config_folder_path.clone(); @@ -31,11 +41,30 @@ fn install(config_path: &PathBuf){ let mut config_file = fs::File::create(config_path).expect("error creating file"); let mut projects_conf_file = fs::File::create(projects_conf_path).expect("error creating projects config file"); projects_conf_file.write_all(b"customer:name:notes:files:active:box_name\n").expect("error writing default project info"); + let mut terminal_response = String::new(); let mut notes_response = String::new(); let mut files_response = String::new(); let mut tools_response = String::new(); let mut template_name = String::new(); let mut have_template = String::new(); + println!("terminal you use? (example: konsole, xfce, gnome, etc)"); + std::io::stdin().read_line(&mut terminal_response).unwrap(); + let mut _terminal_command = String::new(); + if terminal_response.contains("konsole"){ + let mut response_buffer = String::new(); + println!("do you already have a custom profile setup?"); + println!("this is pretty specific to pyro's setup, I do some special sauce for my konsole stuff"); + std::io::stdin().read_line(&mut response_buffer).unwrap(); + if response_buffer.to_lowercase().contains("y"){ + let mut profile = String::new(); + println!("konsole profile name?"); + std::io::stdin().read_line(&mut profile).unwrap(); + _terminal_command = format!("konsole --profile {}", profile); + } + } + else{ + _terminal_command = _terminal_commands[terminal_response.trim_end()].to_owned(); + } println!("path to save project notes?"); std::io::stdin().read_line(&mut notes_response).unwrap(); println!("path to save project files?"); @@ -60,7 +89,7 @@ Do you have a distrobox set up to function as your template for all new projects let _list = process::Command::new("distrobox").arg("list").arg("--root").status(); println!("distrobox template name?"); std::io::stdin().read_line(&mut template_name).unwrap(); - let config_string = format!("Project_files:{}\nProject_notes:{}\ntools_folder:{}", files_response.trim_end(), notes_response.trim_end(), tools_response.trim_end()); + let config_string = format!("Project_files:{}\nProject_notes:{}\ntools_folder:{}\nterminal:{}", files_response.trim_end(), notes_response.trim_end(), tools_response.trim_end(), _terminal_command.trim_end()); config_file.write_all(config_string.as_bytes()).expect("error writing to config file"); let default_projectline = format!("default:default:{}:{}:yes:{}", ¬es_response.trim_end(), &files_response.trim_end(), &template_name.trim_end()); projects_conf_file.write_all(default_projectline.as_bytes()).expect("error writing default project line"); @@ -71,13 +100,15 @@ Do you have a distrobox set up to function as your template for all new projects } -fn get_projects(config_path: &mut PathBuf) -> Vec{ - config_path.pop(); - config_path.push("projects.conf"); +fn get_projects(config_path: &PathBuf) -> Vec{ + let mut mut_config_path = config_path.clone(); + mut_config_path.pop(); + mut_config_path.push("projects.conf"); let mut projects = Vec::new(); - let projects_string = fs::read_to_string(config_path).expect("error reading projects file"); + let projects_string = fs::read_to_string(mut_config_path).expect("error reading projects file"); let project_lines:Vec<&str> = projects_string.split("\n").collect(); let mut first = 0; + let mut already_active = false; for line in project_lines{ first = first + 1; if first != 1{ @@ -92,8 +123,11 @@ fn get_projects(config_path: &mut PathBuf) -> Vec{ let mut active = false; let boxname = settings[5].to_owned(); if settings[4] == "yes"{ - env::set_var("CURRENT_PROJECT_BOX", boxname.clone()); - active = true; + if already_active == false{ + env::set_var("CURRENT_PROJECT_BOX", boxname.clone()); + already_active = true; + active = true; + } } let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname}; println!("{} {} LOADED!", &new_project.customer, &new_project.project_name); @@ -138,6 +172,7 @@ fn switch_project(projects: &mut Vec){ fn save_projects(projects: &Vec, config_path: &PathBuf){ let mut save_file_path = config_path.clone(); + let mut active_set = false; save_file_path.pop(); save_file_path.push("projects.conf"); let mut save_file = fs::File::create(save_file_path).expect("error creating save_file"); @@ -146,7 +181,11 @@ fn save_projects(projects: &Vec, config_path: &PathBuf){ let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()}; let mut _outline = String::new(); if project.active{ - _outline = format!("{}yes:{}\n", default, project.boxname); + if active_set == false{ + _outline = format!("{}yes:{}\n", default, project.boxname); + active_set = true; + } + } else{ _outline = format!("{}no:{}\n", default, project.boxname); @@ -189,13 +228,7 @@ fn start_pentest(){ } } -fn new_project(projects: &mut Vec, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String){ - let mut new_id = 0; - for project in projects.clone(){ - if project.id > new_id{ - new_id = project.id + 1; - } - } +fn new_project(projects: &mut Vec, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, config_path: &PathBuf, new_id: i32){ let mut new_project_dir = project_dir.clone(); let mut new_note_dir = notes_dir.clone(); let mut existing_folders = String::new(); @@ -258,6 +291,7 @@ fn new_project(projects: &mut Vec, project_dir: &PathBuf, notes_dir: &P fs::create_dir_all(&new_project_dir).expect("error creating new files folder"); fs::create_dir_all(&new_note_dir).expect("error creating new notes folder"); } + thread::sleep(Duration::from_secs(2)); let box_name = format!("atarchbox_{}", customer_name); let mut box_name_path = new_project_dir.clone(); box_name_path.push("boxname"); @@ -272,9 +306,9 @@ fn new_project(projects: &mut Vec, project_dir: &PathBuf, notes_dir: &P .arg("--clone") .arg(boxtemplate) .arg("--volume") - .arg(toold_volume) + .arg(&toold_volume) .arg("--volume") - .arg(pentest_volume) + .arg(&pentest_volume) .arg("--name") .arg(&box_name) .status() @@ -299,10 +333,13 @@ fn new_project(projects: &mut Vec, project_dir: &PathBuf, notes_dir: &P } else{ println!("ooof did not start successfully try entering it yoruself"); + println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name); } } else{ println!("ooof distrobox did not work.... try creating it yourself"); + println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, &toold_volume, &pentest_volume, &box_name); + println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name); } let new_project = Project{customer: customer_name.trim_end().to_owned(), project_name: project_name.trim_end().to_owned(), @@ -313,6 +350,7 @@ fn new_project(projects: &mut Vec, project_dir: &PathBuf, notes_dir: &P boxname: box_name, }; projects.push(new_project); + save_projects(projects, config_path); } @@ -324,46 +362,52 @@ fn remove_project(projects: &mut Vec){ let mut project_to_remove = String::new(); println!("project to remove?"); std::io::stdin().read_line(&mut project_to_remove).unwrap(); - let mut project_to_keep = Vec::new(); - if project_to_remove.len() > 0{ - let remove_id: i32 = project_to_remove.trim_end().parse().unwrap(); - let mut project_set = false; - for project in projects.clone(){ - if project.id == remove_id{ - println!("will remove {} {}", project.customer, project.project_name); - project_set = true; - let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox"); - let distrobox_rm_status = process::Command::new("distrobox") - .arg("rm") - .arg("--root") - .arg("-f") - .arg(&project.boxname) - .status().expect("error calling distrobox"); - if distrobox_rm_status.success(){ - println!("Distrobox Removal Successful!!!"); + if project_to_remove.len() > 1{ + let mut project_to_keep = Vec::new(); + if project_to_remove.len() > 0{ + let remove_id: i32 = project_to_remove.trim_end().parse().unwrap(); + let mut project_set = false; + for project in projects.clone(){ + if project.id == remove_id{ + println!("will remove {} {}", project.customer, project.project_name); + project_set = true; + let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox"); + let distrobox_rm_status = process::Command::new("distrobox-rm") + .arg("--root") + .arg("-f") + .arg(&project.boxname) + .status().expect("error calling distrobox"); + if distrobox_rm_status.success(){ + println!("Distrobox Removal Successful!!!"); + } + else{ + println!("Distrobox Removal Failed, manual removal required!"); + } } - else{ - println!("Distrobox Removal Failed, manual removal required!"); + else { + println!("{} {} will be kept", project.customer, project.project_name); + project_to_keep.push(project); } } - else { - println!("{} {} will be kept", project.customer, project.project_name); - project_to_keep.push(project); + if project_set{ + projects.clear(); + projects.append(&mut project_to_keep); } - } - if project_set{ - projects.clear(); - projects.append(&mut project_to_keep); + else{ + println!("error no prjects found to remove") + } + } else{ - println!("error no prjects found to remove") + println!("we need user in put here dummy!!"); } - } else{ - println!("we need user in put here dummy!!"); + println!("we need input here dummy!"); } } + + fn open_in_dolphin(folder: &str, project: Project){ let mut to_open = PathBuf::new(); match folder{ @@ -438,8 +482,33 @@ fn print_report_information(project: Project){ -fn project_standalone_terminal(project: Project){ - process::Command::new("konsole").arg("--profile").arg("attack").arg(project.boxname).spawn().expect("error opeing konsole"); +fn project_standalone_terminal(project: Project, mut terminal: String){ + terminal = terminal.trim_end().to_owned(); + let mut profile = false; + if terminal.contains("profile"){ + profile = true; + } + let terminal_vec:Vec<&str> = terminal.split(" ").collect(); + let mut terminal_start = process::Command::new(terminal_vec[0]); + let mut first = true; + for arg in terminal_vec{ + if first == true{ + first = false; + } + else{ + terminal_start.arg(arg); + } + } + if profile == false { + terminal_start.arg(&project.boxname); + } + print!("{}", terminal); + let start = terminal_start.spawn(); + match start{ + Ok(_child) => println!("New Terminal Started, you can retun to the menu now!"), + Err(_error) => println!("error starting new terminanl, something may be wrong with the terminal part of your config!\nCheck ~/.conf/pyro_pentest_tool/conf for errors") + } + //process::Command::new("konsole").arg("--profile").arg("attack").arg(project.boxname).spawn().expect("error opeing konsole"); } @@ -473,6 +542,65 @@ fn gnerate_userpass(project: &Project){ } } +fn build_cmd_for_host_discovery(project: &Project){ + let mut cobalt_strike_response = String::new(); + let mut need_shell = false; + println!("will you be running this via cobalt strike? (do you need it to start with \"shell\"?"); + let input_result = std::io::stdin().read_line(&mut cobalt_strike_response); + if input_result.is_err(){ + println!("error getting user input... not really sure how you did this... just pressing enter would work..... wow"); + return; + } + if cobalt_strike_response.to_lowercase().contains("y"){ + need_shell = true; + } + let mut general_note_path = project.notes_folder.clone(); + general_note_path.push("general.md"); + println!("Reading from: {}", general_note_path.display()); + let mut ranges = Vec::new(); + let general_note_string = read_to_string(general_note_path); + let mut _note_string = String::new(); + match general_note_string{ + Err(error) => {println!("error reading file to string!! {}", error); return;}, + _=> _note_string = general_note_string.unwrap() + } + let lines: Vec<&str> = _note_string.split("\n").collect(); + for line in lines{ + if line.contains("|"){ + if line.contains("."){ + let ip = line.split("|").collect::>()[1]; + if ip .contains(","){ + let ips: Vec<&str> = ip.split(",").collect(); + for ip in ips{ + ranges.push(ip.trim_end().trim_start()); + } + } + else{ + ranges.push(ip.trim_end().trim_start()); + } + } + } + } + let mut _discovery_command = ""; + if need_shell{ + _discovery_command = "shell (for /L %a IN (1,1,254) DO ping /n 1 /w 3 !!!.%a) | find \"Reply\""; + } + else{ + _discovery_command = "(for /L %a IN (1,1,254) DO ping /n 1 /w 3 !!!.%a) | find \"Reply\""; + } + let mut final_command = String::new(); + for range in ranges{ + let mut network: Vec<&str> = range.split(".").collect(); + network.pop(); + let network_string = network.join("."); + let range_command = _discovery_command.replace("!!!", &network_string); + final_command.push_str(range_command.as_str()); + final_command.push_str(">> ping_only_replies.txt &"); + } + final_command.pop(); + println!("{}", final_command); +} + fn run_initial_enum(project: &Project){ let mut csv = String::new(); println!("path to the csv?"); @@ -486,9 +614,21 @@ fn run_initial_enum(project: &Project){ } } +fn next_project_id(config_path: &PathBuf) -> i32{ + let projects = get_projects(config_path); + let mut new_id = 0; + for project in projects.clone(){ + if project.id > new_id{ + new_id = project.id + 1; + } + } + return new_id; +} -fn main_menu(mut projects: Vec, config_path: &PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String){ + +fn main_menu(mut projects: Vec, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String){ let mut loopize = true; + let mut new_id = next_project_id(&config_path); loop { let active_project = get_active_project(&projects); let mut response = String::new(); @@ -560,13 +700,14 @@ Current Project: {} {} 12.) generate userpass file from your obsidian notes 13.) run pyro's initail enum script on a nessus csv for the current project 14.) Print Project Info For Report - 15.) Stop All Distroboxes - 16.) Quit Application + 15.) Build host discovery cmd command from scope in notes + 16.) Stop All Distroboxes + 17.) Quit Application \n", active_project.customer, active_project.project_name); std::io::stdin().read_line(&mut response).expect("error getting menu input"); clear().expect("error clearing screen"); match response.as_str().trim_end(){ - "1" => println!("\n{} {}", active_project.customer ,active_project.project_name), + "1" => println!("\nclient: {}\n\nproject: {}\n\nbox: {}\n\nproject files: {}\n\nproject notes: {}\n", active_project.customer ,active_project.project_name, active_project.boxname, active_project.files_folder.display(), active_project.notes_folder.display()), "2" => {println!("+++++++++++++++++++++"); for project in &projects{ println!("++{}|{}++",project.customer ,project.project_name)} @@ -574,17 +715,18 @@ Current Project: {} {} "3" => switch_project(&mut projects), "4" => start_pentest(), "5" => save_projects(&projects, &config_path), - "6" => new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate), + "6" => {new_id = new_id + 1; new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id)}, "7" => remove_project(&mut projects), - "8" => project_standalone_terminal(active_project.clone()), + "8" => project_standalone_terminal(active_project.clone(), terminal.clone()), "9" => project_inline_terminal(active_project.clone()), "10" => open_in_dolphin("files", active_project.clone()), "11" => open_in_dolphin("notes", active_project.clone()), "12" => gnerate_userpass(&active_project), "13" => run_initial_enum(&active_project), "14" => print_report_information(active_project.clone()), - "15" => stop_all_boxes(&projects), - "16" => {save_projects(&projects, &config_path); + "15" => build_cmd_for_host_discovery(&active_project), + "16" => stop_all_boxes(&projects), + "17" => {save_projects(&projects, &config_path); let mut stop = String::new(); println!("stop all boxes?\ny/n"); std::io::stdin().read_line(&mut stop).unwrap(); @@ -634,10 +776,11 @@ fn main() { let mut project_base_folder = PathBuf::new(); let mut project_base_notes = PathBuf::new(); let mut tools_folder = PathBuf::new(); - println!("config already generated\nloading config file...\n"); + let mut terminal_command = String::new(); + let mut box_template = String::new(); + println!("\nconfig already generated\nloading config file...\n"); let settings_string = fs::read_to_string(&config_path).expect("error reading config file"); let settings: Vec<&str> = settings_string.split("\n").collect(); - let mut box_template = String::new(); for line in settings{ if line.len() > 1{ let setting_vec: Vec<&str> = line.split(":").collect(); @@ -646,6 +789,7 @@ fn main() { "Project_notes" => project_base_notes.push(setting_vec[1].trim_end()), "tools_folder" => tools_folder.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(), _ => println!("error unknown setting: {}", setting_vec[0]) } } @@ -654,12 +798,13 @@ fn main() { Project Folders: {} Note Folders: {} Tools Folder: {} - distrobox template: {}\n -", project_base_folder.display(), project_base_notes.display(), tools_folder.display(), box_template); + distrobox template: {} + terminal_command: {}\n +", project_base_folder.display(), project_base_notes.display(), tools_folder.display(), box_template, terminal_command); println!("loading project configs..."); - let projects = get_projects(&mut config_path); + let projects = get_projects(&config_path); println!("Enter to start main menu"); let mut enter = String::new(); std::io::stdin().read_line(&mut enter).unwrap(); - main_menu(projects, &config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template); + main_menu(projects, config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template, terminal_command); }