10 Commits

Author SHA1 Message Date
pyro57000
12e5ab38d2 bumped the version in the cargo.toml file 2025-04-22 12:46:23 -05:00
pyro57000
f2370e463d added help function to cli 2025-04-22 12:42:38 -05:00
pyro57000
92dd9766b8 refactored for CLI!!! 2025-04-22 12:10:45 -05:00
pyro57000
dbbae0eb4e added a function to parse your host notes and
generate the attack notes based off of them.
2025-04-16 17:28:39 -05:00
pyro57000
2346988e23 added an option to parse cs portscann output 2025-04-15 13:08:48 -05:00
pyro57000
5bfa645b3d added a url for the obsidian notes of the current
project, and to get the vault name from the user
at install.
2025-04-09 10:42:00 -05:00
pyro57000
012ba517ab added a function to info_controls that parses
GatherContacts output and prints them to the
console as well as saves them to both a text file
in the /pentest/working directory as well as your
notes in a password_enumeration.md file.
2025-04-08 12:48:07 -05:00
pyro57000
649dad5e79 chaged some working for the menu 2025-04-07 09:03:25 -05:00
pyro57000
2e839adccf Fixed the installer on Kali linux 2025-04-05 17:49:16 -05:00
pyro57000
fc316c2a71 Completely re-wrote the install function.
Trying to get this working on default kali.
2025-04-04 20:17:35 -05:00
9 changed files with 991 additions and 419 deletions

View File

@@ -1241,7 +1241,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "pentest_tool"
version = "0.2.0"
version = "3.1.1"
dependencies = [
"chrono",
"clearscreen",

View File

@@ -1,6 +1,6 @@
[package]
name = "pentest_tool"
version = "0.2.0"
version = "3.1.1"
edition = "2021"
[dependencies]

View File

@@ -43,6 +43,10 @@ pub fn project_standalone_terminal(project: Project, mut terminal: String){
if terminal.contains("profile"){
profile = true;
}
if terminal.contains("!!!"){
let terminal_launch_cmd = format!("distrobox enter --root {}", &project.boxname);
terminal = terminal.replace("!!!", &terminal_launch_cmd);
}
let terminal_vec:Vec<&str> = terminal.split(" ").collect();
let mut terminal_start = process::Command::new(terminal_vec[0]);
let mut first = true;

196
pentest_tool/src/cli.rs Normal file
View File

@@ -0,0 +1,196 @@
use std::path::PathBuf;
use std::process::exit;
use std::thread::JoinHandle;
use chrono::Datelike;
use clearscreen::clear;
use clearscreen;
use chrono::Local;
use crate::Project;
use crate::project_controls;
use crate::box_controls;
use crate::info_controls;
use crate::start_pentest;
use crate::get_user_input;
use crate::menu;
fn help(command: Option<String>){
if command.is_some(){
let help_cmd = command.unwrap();
match help_cmd.as_str(){
"list projects" | "lp" | "listp" | "list p" => {println!("list all projects"); return;},
"switch project" | "swp" | "switch p" | "switchp" => {println!("switch active project"); return;},
"show active project" | "show active" | "sa" | "show a" => {println!("show currently active project"); return;},
"create new project" | "cnp" | "new project" | "np" => {println!("create a new project and default note structure"); return;},
"save projects" | "sp" | "save" | "s" => {println!("save project information"); return;},
"import project" | "ip" | "import" => {println!("impot existing project"); return;},
"remove project" | "rp" | "remove" | "rmp" => {println!("remove project"); return;},
"show upcoming projects" | "sup" | "show upcoming" => {println!("show upcoming projects"); return;},
"promote project" | "pp" | "promote" => {println!("promote upcoming project to current project"); return;},
"new terminal" | "enter" | "enter terminal" | "nt" | "et" => {println!("spawn a new terminal window in the active project's distrobox"); return;},
"inline terminal" | "it" | "enter inline" | "ei" => {println!("spawn a terminal in this window using the current active project's distrobox"); return;},
"cobalt strike" | "cs" => {println!("open cobalt strike in the active project's distrobox"); return;},
"recreate distrobox" | "rdb" | "ndb" | "new distrobox" => {println!("recreate the active project's distrobox"); return;},
"generate userpass" | "userpass" | "gup" | "up" => {println!("generate userpass file based on the active project's notes"); return;},
"inital enum" | "ie" | "enum" => {println!("run the initial enum script on a nessus csv and save the output to the active project's notes"); return;},
"build attack notes" | "ban" | "attack notes" | "hn" => {println!("build the active project's attack note based on the active project's host notes (for external tests)"); return;},
"host discovery" | "build host discovery" | "hd" | "bhd" => {println!("print host discovery ping command for the active project, based on the scope table"); return;},
"port scan" | "cs port scan" | "cobaltstrike port scan" | "csps" | "ps" => {println!("print the cobalt strike portscan command based on the active project's scope table"); return;},
"parse port scan" | "pps" | "parse scan" => {println!("parse a cobalt strike portscan and save the files to the active project's files folder"); return;},
"stop boxes" | "stop distroboxes" | "sdb" => {println!("stop all distroboxes"); return;},
"password spray" | "pass spray" | "pas" => {println!("iterate through password spray note file and print the command to perform the spray, waiting the proper observation window beteen commands"); return;},
"bloodhound" | "bh" => {println!("launch bloodhound in the active project's distrobox"); return;},
"parse gather contacts" | "pgc" | "parse contacts" | "pc" => {println!("parse gather contacts output"); return;},
"prune distroboxes" | "pdb" | "prune" => {println!("prune distroboxes for all projects that are not being tracked by this tool (frees up system storage)"); return;},
_ => ()
}
}
println!("Welcom to Pyro's pentest command line!");
println!("available commands: name | aliases | ...");
print!("
list projects | lp | listp | list p
switch project | sp | switch p | switchp
show active project | show active | sa | show a
create new project | cnp | new project | np
save projects | sp | save | s
import project | ip | import
remove project | rp | remove | rmp
show upcoming project | sup | show upcoming
promote project | pp | promote
new terminal | enter | enter terminal | nt | et
inline terminal | it | enter inline | ei
cobalt strike | cs
recreate distrobox | rdb | ndb | new distrobox
generate userpass | userpass | gup | up
inital enum | ie | enum
host discovery | build host discovery | hd | bhd
port scan | cs port scan | cobaltstrike port scan | csps | ps
parse port scan | pps | parse scan
stop boxes | stop distroboxes | sdb
password spray | pass spray | pas
bloodhound | bh
parse gather contacts | pgc | parse contacts | pc
prune distroboxes | pdb | prune
help | ? | -h
")
}
pub fn run_command(cmd: String,
mut projects: Vec<Project>,
config_path: PathBuf,
base_files: &PathBuf,
base_notes: &PathBuf,
tools_dir: &PathBuf,
boxtemplate: String,
terminal: String,
cracking_rig: String,
rockyou: String,
rule: String,
upcoming_files: &PathBuf,
upcoming_notes: &PathBuf,
password_spray_file: &PathBuf,
fingerprint: bool,
vault_name: String) -> Option<JoinHandle<()>> {
let mut new_id = menu::next_project_id(&config_path);
let active_project = menu::get_active_project(&projects);
let mut notes_folder_string = format!("{}", &active_project.notes_folder.display());
let mut obsidian_folder_vec = PathBuf::new();
let mut reached_vault_folder = false;
for folder in notes_folder_string.split("/").collect::<Vec<&str>>(){
if !folder.contains(&vault_name){
reached_vault_folder = true;
obsidian_folder_vec.push(folder);
}
else{
if reached_vault_folder{
obsidian_folder_vec.push(folder);
}
}
}
let obsidian_uri = format!("obsidian://open?vault={}&file={}", vault_name, obsidian_folder_vec.display().to_string().replace("/", "%2F"));
let mut response = String::new();
let now = Local::now();
let month = now.month();
let year = now.year();
let mut season = String::new();
let mut lseason = String::new();
match month{
12 | 01 | 02 => {season = "Winter".to_owned(); lseason = "Fall".to_owned()},
03 | 04 | 05 => {season = "Spring".to_owned(); lseason = "Winter".to_owned()},
06 | 07 | 08 => {season = "Summer".to_owned(); lseason = "Spring".to_owned()},
09 | 10 | 11 => {season = "Fall".to_owned(); lseason = "Summer".to_owned()},
_ => {println!("error getting season! Check code..."); exit(1)}
}
if cmd.contains("help"){
if cmd.contains(" "){
let help_with = &cmd.split(" ").collect::<Vec<&str>>()[1].to_owned();
help(Some(help_with.to_owned()));
}
else{
help(None);
}
return None;
}
match cmd.as_str(){
"list projects" | "lp" | "listp" | "list p" => {project_controls::list_projects(&projects); return None},
"switch project" | "swp" | "switch p" | "switchp" => {project_controls::switch_project(&mut projects.clone()); return None},
"show active project" | "show active" | "sa" | "show a" => {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()); return None},
"create new project" | "cnp" | "new project" | "np" => {new_id = new_id + 1; start_pentest::start_pentest(&config_path, &mut projects, new_id, upcoming_files, upcoming_notes, &boxtemplate, password_spray_file); return None},
"save projects" | "sp" | "save" | "s" => {project_controls::save_projects(&projects, &config_path); return None},
"import project" | "ip" | "import" => {new_id = new_id + 1; project_controls::new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id, &upcoming_files, &upcoming_notes, fingerprint); return None},
"remove project" | "rp" | "remove" | "rmp" => {project_controls::remove_project(&mut projects, &config_path); return None},
"show upcoming projects" | "sup" | "show upcoming" => {project_controls::print_upcoming_projects(&projects); return None},
"promote project" | "pp" | "promote" => {project_controls::promote_project(&mut projects, &config_path, base_files, base_notes, tools_dir, &boxtemplate, fingerprint); return None},
"new terminal" | "enter" | "enter terminal" | "nt" | "et" => {box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()); return None},
"inline terminal" | "it" | "enter inline" | "ei" => {box_controls::project_inline_terminal(active_project.clone()); return None},
"cobalt strike" | "cs" => {let cs_thread = box_controls::launch_cobalt_strike(active_project.clone()); return cs_thread},
"recreate distrobox" | "rdb" | "ndb" | "new distrobox" => {box_controls::make_box(&active_project, &tools_dir, &boxtemplate, false, fingerprint); return None},
"generate userpass" | "userpass" | "gup" | "up" => {info_controls::generate_userpass(&active_project); return None},
"inital enum" | "ie" | "enum" => {info_controls::run_initial_enum(&active_project); return None},
"build attack notes" | "ban" | "attack notes" | "hn" => {info_controls::build_cmd_for_host_discovery(&active_project); return None;}
"host discovery" | "build host discovery" | "hd" | "bhd" => {info_controls::build_cmd_for_host_discovery(&active_project); return None},
"port scan" | "cs port scan" | "cobaltstrike port scan" | "csps" | "ps" => {info_controls::build_cs_portscan_cmd(&active_project); return None},
"parse port scan" | "pps" | "parse scan" => {info_controls::parse_csportscan(&active_project); return None},
"stop boxes" | "stop distroboxes" | "sdb" => {box_controls::stop_all_boxes(&projects); return None},
"password spray" | "pass spray" | "pas" => {info_controls::password_spray_help(&active_project, season, lseason, year, &tools_dir, &config_path); return None},
"bloodhound" | "bh" => {let bloodhound_handle = box_controls::launch_bloodhound_gui(active_project.clone()).unwrap(); return Some(bloodhound_handle);},
"parse gather contacts" | "pgc" | "parse contacts" | "pc" => {info_controls::partse_gathercontacts(&active_project); return None},
"prune distroboxes" | "pdb" | "prune" => {let prune_thread = box_controls::clean_unused_boxes(&projects, &boxtemplate); return prune_thread},
_ => {println!("unknown command."); return None;}
}
}
pub fn cli(interactive: bool,
projects: Vec<Project>,
config_path: PathBuf,
base_files: &PathBuf,
base_notes: &PathBuf,
tools_dir: &PathBuf,
boxtemplate: String,
terminal: String,
cracking_rig: String,
rockyou: String,
rule: String,
upcoming_files: &PathBuf,
upcoming_notes: &PathBuf,
password_spray_file: &PathBuf,
fingerprint: bool,
vault_name: String) -> Option<Vec<JoinHandle<()>>>{
let mut threads = Vec::new();
if interactive{
let mut loopize = true;
while loopize{
let command = get_user_input("command?");
match command.as_str(){
"exit" | "main menu" | "mm" | "menu" => loopize = false,
_ => {let thread_option = run_command(command, projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if thread_option.is_some(){threads.push(thread_option.unwrap())}},
}
}
}
if threads.len() > 0{
return Some(threads);
}
else {
return None;
}
}

View File

@@ -1,6 +1,10 @@
use std::collections::HashMap;
use std::fmt::write;
use std::fs;
use std::fs::create_dir_all;
use std::fs::read_to_string;
use std::fs::OpenOptions;
use std::hash::Hash;
use std::io::BufReader;
use std::io::Write;
use std::path::PathBuf;
@@ -10,11 +14,16 @@ use std::thread;
use std::time::Duration;
use std::io::stdin;
use std::thread::JoinHandle;
use chrono::format;
use fs_extra::file;
use reqwest::dns::Name;
use walkdir::WalkDir;
use clearscreen::clear;
use clearscreen;
use rodio::{Decoder, OutputStream, Sink};
use crate::get_user_input;
use crate::open_overwrite;
use crate::open_append;
use crate::Project;
pub fn run_initial_enum(project: &Project){
@@ -96,67 +105,75 @@ pub fn run_initial_enum(project: &Project){
}
pub fn build_external_attack_notes(project: &Project){
#[derive(Clone)]
struct Port{
number: String,
hosts: Vec<String>,
service: String,
hosts: Vec<String>
}
let mut ports: Vec<Port> = Vec::new();
let mut host_notes_path = project.notes_folder.clone();
let mut attack_notes_path = host_notes_path.clone();
host_notes_path.push("host_notes.md");
let mut attack_notes_path = project.notes_folder.clone();
attack_notes_path.push("attacks.md");
let host_notes_read_res = fs::read_to_string(host_notes_path);
if host_notes_read_res.is_err(){
let error = host_notes_read_res.err().unwrap();
println!("error reading host notes!");
println!("error reading host notes");
println!("{}", error);
return;
}
let host_notes = host_notes_read_res.unwrap();
let attack_open_res = fs::OpenOptions::new().append(true).create(true).open(attack_notes_path);
if attack_open_res.is_err(){
let error = attack_open_res.err().unwrap();
println!("error opening attack notes!");
println!("{}", error);
return;
}
let attack_notes = attack_open_res.unwrap();
for line in host_notes.split("\n").collect::<Vec<&str>>(){
let mut current_host = String::new();
if line.len() > 1{
let host_notes_string = host_notes_read_res.unwrap();
let host_parts: Vec<&str> = host_notes_string.split("---").collect();
let mut host = String::new();
for part in host_parts{
let lines: Vec<&str> = part.split("\n").collect();
for line in lines{
if line.contains("# "){
if !line.contains("## "){
current_host = line.split_whitespace().collect::<Vec<&str>>()[1].trim().to_owned();
host = line.split("# ").collect::<Vec<&str>>()[1].to_owned();
}
}
if line.contains("|"){
let table_data:Vec <&str> = line.split("|").collect();
for item in table_data{
let mut is_new = true;
if item.contains(":"){
if line.contains(":"){
let entries: Vec<&str> = line.split("|").collect();
let service = entries[2].trim().to_owned();
for entry in entries{
if entry.contains(":"){
let port_number = entry.trim().to_owned();
let mut new = true;
for port in &mut ports{
if port.number == item.trim(){
if port.hosts.contains(&current_host){
port.hosts.push(current_host.clone());
}
is_new = false;
if port.service == service{
new = false;
let host_entry = format!("{} {}", host.clone(), port_number.clone());
port.hosts.push(host_entry);
}
}
if is_new{
let new_port = Port{number: line.trim().to_owned(), hosts:vec![current_host.clone()]};
match new{
true => {let new_port = Port{service: service.clone(), hosts: vec![format!("{} {}", host.clone(), port_number.clone())]}; ports.push(new_port);},
false => ()
}
}
}
}
}
}
for port in ports{
let output = format!("# {}\nHOSTS:\n", port.number);
println!("{} parsed!", host);
}
println!("parsed host_notes.md, writing to attacks.md...");
let attack_open_res = open_append(&attack_notes_path);
if attack_open_res.is_none(){
println!("ooof error opening attack notes, returning...");
return;
}
let mut attack_file = attack_open_res.unwrap();
write!(attack_file, "\n---\n").expect("since we used the open options already this should never fail.");
for port in ports.clone(){
write!(attack_file, "# {}\n", port.service).expect("since we used the open options already this should never fail.");
write!(attack_file, "HOSTS:\n").expect("since we used the open options already this should never fail.");
for host in port.hosts{
// output.push_str("## {}");
write!(attack_file, "## {}\n\n", host).expect("since we used the open options already this should never fail.");
write!(attack_file, "\n---\n").expect("since we used the open options already this should never fail.");
}
}
}
@@ -776,3 +793,375 @@ pub fn get_mssql_column_names(project: &Project) -> Option<JoinHandle<()>>{
});
return Some(db_handle);
}
pub fn partse_gathercontacts(project: &Project){
fn format_names(names: Vec<&str>) -> HashMap<&str, Vec<String>>{
let mut formated_data = HashMap::new();
let mut flast = Vec::new();
let mut fdotlast = Vec::new();
let mut fdashlast = Vec::new();
let mut firstl = Vec::new();
let mut firstdotlast = Vec::new();
let mut firstlast = Vec::new();
let mut last_vec = Vec::new();
let mut first_vec = Vec::new();
for name in names{
let name_vec: Vec<&str> = name.split("|").collect();
if name_vec.len() == 2{
let first = name_vec[0];
let last = name_vec[1];
let first_chars: Vec<char> = first.chars().collect();
let last_chars: Vec<char> = last.chars().collect();
flast.push(format!("{}{}", &first_chars[0], &last));
fdotlast.push(format!("{}.{}", &first_chars[0], &last));
fdashlast.push(format!("{}-{}", &first, &last));
firstl.push(format!("{}{}", &first, &last_chars[0]));
firstdotlast.push(format!("{}.{}", &first, &last));
firstlast.push(format!("{}{}", &first, &last));
last_vec.push(format!("{}", &last));
first_vec.push(format!("{}", &first));
}
}
formated_data.insert("flast", flast);
formated_data.insert("fdotlast", fdotlast);
formated_data.insert("fdashlast", fdashlast);
formated_data.insert("firstl", firstl);
formated_data.insert("firstdotlast", firstdotlast);
formated_data.insert("firstlast", firstlast);
formated_data.insert("last", last_vec);
formated_data.insert("fisrt", first_vec);
return formated_data;
}
let gather_file = get_user_input("path to your gather contacts output?");
print!("
supported formats:
flast
f.last
f-last
firstl
first.last
firstlast
last
\n");
let format = get_user_input("format of usernames?");
let domain = get_user_input("domain name?");
let gather_source = fs::read_to_string(gather_file);
if gather_source.is_err(){
let error = gather_source.err().unwrap();
println!("error reading gather contacts output!");
println!("{}", error);
return;
}
let gather_source_string = gather_source.unwrap();
let gather_source_lines: Vec<&str> = gather_source_string.split("\n").collect();
let mut names = String::new();
for line in gather_source_lines{
if line.len() > 2{
let line_vec: Vec<&str> = line.split("\t").collect();
let first = line_vec[1].trim();
let last = line_vec[2].trim();
if first.len() > 1 && last.len() >1 {
let name = format!("{}|{}",first, last);
names = format!("{} {}", names, name.trim());
}
}
}
let users: Vec<&str> = names.split(" ").collect();
let data = format_names(users);
let mut email_text_path = project.files_folder.clone();
let mut email_note_path = project.notes_folder.clone();
email_text_path.push("working/extrapolated_emails.txt");
email_note_path.push("email_enum.md");
let email_text_res = OpenOptions::new().append(true).create(true).open(email_text_path);
if email_text_res.is_err(){
let error = email_text_res.err().unwrap();
println!("error opening email text file!");
println!("{}", error);
return;
}
let email_notes_res = OpenOptions::new().append(true).create(true).open(email_note_path);
if email_notes_res.is_err(){
let error = email_notes_res.err().unwrap();
println!("error opeing email notes file!");
println!("{}", error);
return;
}
let mut email_text_file = email_text_res.unwrap();
let mut email_note_file = email_notes_res.unwrap();
let note_wriet_res = write!(email_note_file, "# Extrapolated Emails: \n");
if note_wriet_res.is_err(){
let error = note_wriet_res.err().unwrap();
println!("error writing to email notes file!");
println!("{}", error);
}
println!("data gathered, printing emails and saving files...\n\n");
for email in &data[&format.to_lowercase().trim()]{
let outline = format!("{}@{}", email, domain);
println!("{}", &outline);
write!(email_note_file, "{}\n", outline).expect("error writing email notes file!");
write!(email_text_file, "{}\n", outline).expect("error writing email text file!");
}
}
pub fn parse_csportscan(project: &Project){
let mut tsv_path = project.files_folder.clone();
tsv_path.push("working/tsvs/services.tsv");
let mut outfile = tsv_path.clone();
outfile.pop();
outfile.pop();
let mut windows_hosts = Vec::new();
let mut ssh_hosts = Vec::new();
let mut ftp_hosts = Vec::new();
let mut rdp_hosts = Vec::new();
let mut dns_hosts = Vec::new();
let mut snmp_hosts = Vec::new();
let mut web_hosts = Vec::new();
let mut telnet_hosts = Vec::new();
let mut unknown_ports = Vec::new();
if !get_user_input("do you have the tsv saved in the project folder under working/tsvs/services.tsv?").to_lowercase().contains("y"){
tsv_path.clear();
tsv_path.push(get_user_input("ooof ok, please enter the full path to your tsv file."));
}
let tsv_read_res = read_to_string(tsv_path);
if tsv_read_res.is_err(){
let error = tsv_read_res.err().unwrap();
println!("ooof error reading tsv file!");
println!("{}", error);
return;
}
println!("tsv read, parsing lines...");
let tsv_string = tsv_read_res.unwrap();
let lines: Vec<&str> = tsv_string.split("\n").collect();
for line in lines{
let words: Vec<&str> = line.split("\t").collect();
if words.len() > 1{
let host = words[0].to_lowercase().to_owned();
let port = words[1].to_lowercase().to_owned();
let host_entry = format!("{}:{}", &host, &port);
match words[1]{
"135" => {if !windows_hosts.contains(&host){windows_hosts.push(host)}},
"445" => {if !windows_hosts.contains(&host){windows_hosts.push(host)}},
"22" => {if !ssh_hosts.contains(&host){ssh_hosts.push(host);}},
"21" => {if !ftp_hosts.contains(&host){ftp_hosts.push(host);}},
"23" => {if !telnet_hosts.contains(&host){telnet_hosts.push(host)}},
"3389" => {if !rdp_hosts.contains(&host){rdp_hosts.push(host);}},
"80" | "443" | "8080" | "8443" | "4433" | "8000" => {if !web_hosts.contains(&host_entry){web_hosts.push(host_entry);}},
"53" => {if !dns_hosts.contains(&host){dns_hosts.push(host);}},
"161" => {if !snmp_hosts.contains(&host){snmp_hosts.push(host);}},
_ => {
if words.len() == 3{
let banner = words[2].to_lowercase().to_owned();
if words[2].to_lowercase().contains("ssh"){
if !ssh_hosts.contains(&host_entry){
ssh_hosts.push(host_entry);
}
}
else if banner.contains("ftp"){
if !ftp_hosts.contains(&host_entry){
ftp_hosts.push(host_entry);
}
}
else if banner.contains("nginx") || banner.contains("apache"){
if !web_hosts.contains(&host_entry){
web_hosts.push(host_entry);
}
}
else{
continue;
}
}
else if words.len() == 2{
unknown_ports.push(host_entry);
}
}
}
}
}
println!("is {} where you want to save your files?", outfile.display());
if get_user_input("").to_lowercase().contains("n"){
outfile.clear();
outfile.push(get_user_input("ok, please enter the full path to the folder you want to save them to."));
}
print!("
{} Windows hosts found!
{} SSH hosts found!
{} FTP hosts found!
{} Telnet hosts found!
{} SNMP hosts found!
{} DNS hosts found!
{} RDP hosts found!
{} untagged hosts found!
", windows_hosts.len(), ssh_hosts.len(), ftp_hosts.len(), telnet_hosts.len(), snmp_hosts.len(), dns_hosts.len(), rdp_hosts.len(), unknown_ports.len());
println!("lines parsed! creating output files...");
outfile.push("windows_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut windows_file = file_option.unwrap();
for host in windows_hosts{
let write_res = write!(windows_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing windows_hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("ssh_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut ssh_file = file_option.unwrap();
for host in ssh_hosts{
let write_res = write!(ssh_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing ssh_hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("telnet_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut telnet_file = file_option.unwrap();
for host in telnet_hosts{
let write_res = write!(telnet_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing _hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("ftp_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut ftp_file = file_option.unwrap();
for host in ftp_hosts{
let write_res = write!(ftp_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing _hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("snmp_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut snmp_file = file_option.unwrap();
for host in snmp_hosts{
let write_res = write!(snmp_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing _hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("dns_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut dns_file = file_option.unwrap();
for host in dns_hosts{
let write_res = write!(dns_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing _hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("rdp_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut rdp_file = file_option.unwrap();
for host in rdp_hosts{
let write_res = write!(rdp_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing _hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
outfile.pop();
outfile.push("web_hosts.txt");
let file_option = open_overwrite(&outfile);
if file_option.is_some(){
let mut web_file = file_option.unwrap();
for host in web_hosts{
let write_res = write!(web_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("oooof error writing _hosts.txt!!");
println!("{}", error);
}
else{
write_res.unwrap();
}
}
}
println!("interesting ports have been written to... writing untagged port files...");
outfile.pop();
outfile.push("untagged ports");
if !outfile.exists(){
let untagged_res = create_dir_all(&outfile);
if untagged_res.is_err(){
let error = untagged_res.err().unwrap();
println!("ooof error creating untagged folder!");
println!("{}", error);
}
else{
untagged_res.unwrap();
}
}
for line in unknown_ports{
let line_vec:Vec<&str> = line.split(":").collect();
let host = line_vec[0].to_owned();
let port = line_vec[1].to_owned();
let file_name = format!("{}_hosts.txt", port);
outfile.push(file_name);
let write_file_opt = open_append(&outfile);
if write_file_opt.is_some(){
let mut write_file = write_file_opt.unwrap();
let write_res = write!(write_file, "{}\n", host);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("ooof error writing to file...");
println!("{}", error);
}
}
outfile.pop();
}
println!("DONE all files saved to {}", outfile.display());
println!("note if no hosts were found for a protocol their files will be empty.");
}

View File

@@ -1,231 +1,46 @@
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::Read;
use std::env::home_dir;
use std::fs::{File, create_dir_all, remove_dir_all};
use std::io::{read_to_string, Read};
use std::io::Write;
use std::io::stdin;
use std::io::copy;
use std::process::Command;
use std::time::Duration;
use reqwest::blocking::get;
use std::path::PathBuf;
use std::process;
use std::{path::Path, path::PathBuf};
use std::{process, thread};
use std::process::exit;
use directories::UserDirs;
use crate::get_user_input;
fn setup_folders(config_path: &PathBuf) -> (String, String, String, String, String, String, String, String, String){
let mut delete_for_cleanup = config_path.clone();
delete_for_cleanup.pop();
let mut failed = false;
let mut new_files_folder = String::new();
let mut new_notes_folder = String::new();
let mut upcomming_files_folder = String::new();
let mut upcomming_notes_folder = String::new();
let mut tools_folder = String::new();
let mut cracking_rig = String::new();
let mut cracking_user = String::new();
let mut rockyou = String::new();
let mut rule = String::new();
while new_files_folder.is_empty() || new_notes_folder.is_empty() || tools_folder.is_empty(){
if new_files_folder.is_empty(){
println!("path to save active project files?");
match stdin().read_line(&mut new_files_folder){
Ok(_r) => (),
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
}
}
if new_notes_folder.is_empty(){
println!("path to save active project notes?");
match stdin().read_line(&mut new_notes_folder){
Ok(_r) => (),
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
}
}
if tools_folder.is_empty(){
println!("path to custom tools (like github tools and what not)");
match stdin().read_line(&mut tools_folder){
Ok(_r) => (),
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
}
}
if upcomming_files_folder.is_empty(){
println!("path to save upcomming project files?");
match stdin().read_line(&mut upcomming_files_folder){
Ok(_r) => (),
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
}
}
if upcomming_notes_folder.is_empty(){
println!("path to save upcomming project notes?");
match stdin().read_line(&mut upcomming_notes_folder){
Ok(_r) => (),
Err(_e) => println!("we need input here dummy... We will reprompt on the next loop...")
}
}
if cracking_rig.is_empty(){
let mut have_rig = String::new();
println!("do you have a separate computer that you can ssh into to crack passwords on?");
match stdin().read_line(&mut have_rig){
Ok(_r) => (),
Err(_e) => println!("we need input here dummy, try again...")
}
have_rig = have_rig.to_lowercase();
if have_rig.contains("y"){
println!("excellent! Whats the IP or hostname?");
loop{
match stdin().read_line(&mut cracking_rig){
Ok(_r) => break,
Err(_e) => println!("we need input here dummy, try again...")
}
}
println!("user to ssh as for the cracking rig?");
loop{
match stdin().read_line(&mut cracking_user){
Ok(_r) => break,
Err(_e) => println!("we need input here dummy, try again...")
}
}
println!("Path to rockyou.txt on the cracking rig?");
loop{
match stdin().read_line(&mut rockyou){
Ok(_r) => break,
Err(_e) => println!("we need input here dummyu try again...")
}
}
println!("Path to one rule to rule them all on the cracking rig?");
loop{
match stdin().read_line(&mut rule){
Ok(_r) => break,
Err(_e) => println!("we need input here dummyu try again...")
}
}
}
else if have_rig.contains("n"){
println!("ooof ok freeloader");
cracking_rig = "n".to_owned();
rule = "n".to_owned();
rockyou = "n".to_owned();
}
}
}
new_files_folder = new_files_folder.trim_end().to_owned();
new_notes_folder = new_notes_folder.trim_end().to_owned();
upcomming_files_folder = upcomming_files_folder.trim_end().to_owned();
upcomming_notes_folder = upcomming_notes_folder.trim_end().to_owned();
tools_folder = tools_folder.trim_end().to_owned();
cracking_rig = cracking_rig.trim_end().to_owned();
cracking_user = cracking_user.trim_end().to_owned();
let new_files_path = PathBuf::from(&new_files_folder.trim_end());
let new_notes_path = PathBuf::from(&new_notes_folder.trim_end());
let upcomming_files_path = PathBuf::from(&upcomming_files_folder.trim_end());
let upcomming_notes_path = PathBuf::from(&upcomming_notes_folder.trim_end());
let tools_path = PathBuf::from(&tools_folder.trim_end());
if new_files_path.exists() == false{
println!("active project file folder does not exist, creating...");
match fs::create_dir_all(&new_files_folder){
Ok(_r) => (),
Err(e) => {println!("Error creating active project files Folder!: {}", e);failed = true;}
}
}
if new_notes_path.exists() == false{
println!("active project notes folder does not exist creating...");
match fs::create_dir_all(new_notes_path){
Ok(_r) => (),
Err(e) => {println!("Error creating active project notes Folder!: {}", e);failed = true;}
}
}
if tools_path.exists() == false{
println!("tools folder does not exist creating...");
match fs::create_dir_all(tools_path){
Ok(_r) => (),
Err(e) => {println!("Error creating tools Folder!: {}", e);failed = true;}
}
}
if upcomming_files_path.exists() == false{
println!("upcomming project files folder does not exist creating...");
match fs::create_dir_all(upcomming_files_path){
Ok(_r) => (),
Err(e) => {println!("Error creating upcomming project files Folder!: {}", e);failed = true;}
}
}
if upcomming_notes_path.exists() == false{
println!("upcomming project notes folder does not exist creating...");
match fs::create_dir_all(upcomming_notes_path){
Ok(_r) => (),
Err(e) => {println!("Error creating upcomming project notes Folder!: {}", e);failed = true;}
}
}
if failed{
println!("install failed, cleaning up files...");
match fs::remove_dir_all(&delete_for_cleanup){
Ok(_r) => println!("cleanup successfull, please correct previously reported errors and rerun"),
Err(e) => println!("cleanup failed!: {}\nManually delete the following folder and retry\n{}", e, delete_for_cleanup.display())
}
exit(1);
}
return (new_files_folder, new_notes_folder, tools_folder, upcomming_files_folder, upcomming_notes_folder, cracking_rig, cracking_user, rockyou, rule);
}
fn configure_distrobox(){
let user_dirs_result = UserDirs::new();
let mut success = false;
let mut dbrcpath = PathBuf::new();
if user_dirs_result.is_some(){
let home = user_dirs_result.unwrap().home_dir().to_path_buf();
dbrcpath.push(home);
dbrcpath.push(".distroboxrc");
let box_config_string = String::from("container_always_pull=\"0\"\ncontainer_generate_entry=1\ncontainer_manager=\"podman\"\ncontainer_name_default=\"ubuntu\"\ncontainer_image_default=\"ghcr.io/ublue-os/ubuntu-toolbox:latest\"\nnon_interactive=\"1\"\nxhost +si:localuser:$USER >/dev/null\nexport PIPEWIRE_RUNTIME_DIR=/dev/null\nexport PATH=$PATH:$HOME/.local/bin\n");
let dbrc_file_res = fs::OpenOptions::new().write(true).create(true).open(dbrcpath);
if dbrc_file_res.is_err(){
let error = dbrc_file_res.err().unwrap();
println!("error opening distroboxrc file!");
println!("{}", error);
}
else{
let mut dibrc_file = dbrc_file_res.unwrap();
let dbrc_write_res = write!(dibrc_file, "{}",box_config_string);
if dbrc_write_res.is_err(){
println!("error writing config to distroboxrc file!");
println!("{}", dbrc_write_res.err().unwrap());
}
else{
let _dbrc_write = dbrc_write_res.unwrap();
success = true;
}
}
}
if success == false{
println!("Error getting user dirs!");
println!("distrobox config failed, please follow the following instructions...");
print!("
copy the distrobox config file to your home folder with the name .distroboxrc
cp /usr/etc/distrobox/distrobox.conf ~/.distroboxrc
Then edit the file to change the line container_always_pull=\"1\" to container_always_pull=\"0\"
");
}
}
pub fn install(config_path: &PathBuf){
let mut _terminal_commands = HashMap::from([
("konsole", "konsole -e !!!"),
("kde", "konsole -e !!!"),
("plasma", "konsole -e !!!"),
("gnome", "gnome-terminal -- bash !!!"),
("xfce", "xfce4-terminal --execute '!!!'"),
("alacritty", "alacritty -e !!!"),
]);
let mut folder_creation = true;
let current_projects = PathBuf::from(get_user_input("path to store your active projects?"));
let current_notes = PathBuf::from(get_user_input("path to store your active project notes?"));
let upcoming_projects = PathBuf::from(get_user_input("path to store your upcomming projects?"));
let upcoming_notes = PathBuf::from(get_user_input("path to store your upcomming project notes?"));
let tools = PathBuf::from(get_user_input("path where you store your custom tools (like from github and places)?"));
let mut vault_name = String::new();
let folders = vec![&current_projects, &current_notes, &upcoming_projects, &upcoming_notes, &tools];
let mut config_folder_path: PathBuf = config_path.clone();
config_folder_path.pop();
let mut password_path = config_folder_path.clone();
password_path.push("password_spray.md");
let mut projects_conf_path = config_folder_path.clone();
let mut bell_file_path = config_folder_path.clone();
let del_on_fail = config_folder_path.clone();
projects_conf_path.push("projects.conf");
fs::create_dir_all(&config_folder_path).expect("error creating config dir");
create_dir_all(&config_folder_path).expect("error creating config dir");
bell_file_path.push("bell.mp3");
let bell_sound_url = "https://github.com/Pyro57000/pentest_tool/raw/refs/heads/main/resources/bell.mp3";
let response = get(bell_sound_url).unwrap();
@@ -233,101 +48,194 @@ pub fn install(config_path: &PathBuf){
let mut bell_file = File::create(bell_file_path).unwrap();
copy(&mut response.take(response_length), &mut bell_file).unwrap();
println!("bell notification tone sucessfully downloaded!");
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:stage\n").expect("error writing default project info");
let mut terminal_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);
println!("creating new folders if needed...");
for folder in &folders{
if !Path::exists(folder){
let create_res = create_dir_all(folder);
if create_res.is_err(){
let error = create_res.err().unwrap();
println!("error creating folder {}", folder.display());
println!("{}", error);
println!("you'll need to create this manually after the install is done!");
folder_creation = false;
}
}
}
let tool_volume = format!("{}:/tools:rw", &tools.display());
println!("sweet, now let's get some distrobox stuff out of the way!");
let distrobox_run_res = Command::new("distrobox").arg("list").arg("--root").output();
if distrobox_run_res.is_err(){
let error = distrobox_run_res.err().unwrap();
println!("Distrobox file was not found!");
println!("This usually means that distrobox is not installed.");
println!("please install distrobox, if you're on kali run `sudo apt install distrobox`");
println!("{}", error);
println!("this project heavily relies on distrobox, as its primarily a distrobox mangement tool.");
println!("cleaning up up configuration folders, please install distrobox and re-run this program.");
let cleanup = remove_dir_all(&del_on_fail);
if cleanup.is_err(){
println!("error cleaning up configuration folder!");
println!("please manually delete {} before re-running this install.", &del_on_fail.display());
exit(1);
}
cleanup.unwrap();
exit(1);
}
let distrobox_output = distrobox_run_res.unwrap().stdout;
let distrobox_string = String::from_utf8_lossy(&distrobox_output);
let mut distrobox_names = Vec::new();
let distrobox_output_lines: Vec<&str> = distrobox_string.split("\n").collect();
for line in distrobox_output_lines{
if line.len() > 1{
let name = line.split(" | ").collect::<Vec<&str>>()[1];
distrobox_names.push(name.to_owned());
}
}
let mut have_box = false;
for name in distrobox_names{
if !name.contains("NAME"){
have_box = true;
println!("{}", name);
}
}
let mut template_box_name = String::new();
if have_box{
template_box_name = get_user_input("Name of the distrobox you want to use as a template?");
}
else{
_terminal_command = _terminal_commands[terminal_response.trim_end()].to_owned();
}
let (files_response, notes_response, tools_response, project_folder_path, project_note_path, cracking_rig, cracking_user, rockyou, rule) = setup_folders(&config_path);
print!("
This tool is mainly to handle distrobox creation and usage.
It's expecting you to have a distrobox that you will use as a template.
Do you have a distrobox set up to function as your template for all new projects?
");
std::io::stdin().read_line(&mut have_template).unwrap();
if have_template.contains("n"){
println!("ooof buddy, should have had that already... no worries, we'll make one now.");
let new_boxname = get_user_input("name for your template box? (for exmaple I use atarchbox cause its my attacking archbox ;-)");
println!("please review the following link to select an image to use for your distrobox");
println!("https://distrobox.it/compatibility/#containers-distros");
let image_name = get_user_input("which image would you like to use?");
let tools_volume =format!("{}:/tools:rw", &tools_response);
let distrobox_create_res = Command::new("distrobox")
println!("no exiting distroboxes created!");
println!("let's make one!");
template_box_name = get_user_input("name of the distrobox you want to create?");
println!("review images listed here: https://distrobox.it/compatibility/#containers-distros");
let box_image = get_user_input("image you want to base the template box on?");
let template_box_create_res = Command::new("distrobox")
.arg("create")
.arg("--root")
.arg("--name")
.arg(new_boxname)
.arg("--init")
.arg("--image")
.arg(image_name)
.arg(&box_image)
.arg("--name")
.arg(&template_box_name)
.arg("--init")
.arg("--volume")
.arg(tools_volume)
.arg("--additional-packages")
.arg("systemd")
.arg("--")
.arg("exit")
.arg(&tool_volume)
.status();
if distrobox_create_res.is_err(){
let error = distrobox_create_res.err().unwrap();
println!("ooof we ran into a problem creating your distrobox....");
if template_box_create_res.is_err(){
let error = template_box_create_res.err().unwrap();
println!("error creating template box!");
println!("{}", error);
println!("you'll have to make it manually, but remember the name you want to use for the next step.");
println!("\n\n\nplese create it yourself with the following command.");
println!("\n\ndistrobox create --root --image {}, --name {}, --init --volume {}", &box_image, &template_box_name, &tool_volume);
}
else{
distrobox_create_res.unwrap();
println!("nice, we created a distrobox, remeber the name of your box for the next step!");
template_box_create_res.unwrap();
}
}
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 mut set_fprint = String::from("no");
let fprint_answer = get_user_input("do you want to use fingerprint authentication inside the distroboxes?").to_lowercase();
if fprint_answer.contains("y"){
set_fprint = "yes".to_owned();
let mut cracking_rig = String::from("nobody@nothing");
let mut rockyou = String::from("n/a");
let mut 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);
}
let config_string = format!("Project_files:{}\nProject_notes:{}\ntools_folder:{}\nupcoming_files:{}\nupcoming_notes:{}\nbox_template:{}\nterminal:{}\ncracking_rig:{}@{}\nrockyou_location:{}\nrule_location:{}\nfingerprint:{}", files_response.trim_end(), notes_response.trim_end(), tools_response.trim_end(), &project_folder_path.trim_end(), &project_note_path.trim_end(), template_name.trim_end(), _terminal_command.trim_end(), cracking_user.trim_ascii_end(), cracking_rig.trim_end(), rockyou.trim_end(), rule.trim_end(), set_fprint);
config_file.write_all(config_string.as_bytes()).expect("error writing to config file");
let default_projectline = format!("default:default:{}:{}:yes:{}:current", &notes_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");
println!("active project folders: {}", &files_response);
println!("upcomming project folders: {}", &project_folder_path);
println!("active project notes: {}", &notes_response);
println!("upcomming prjoect notes: {}", &project_note_path);
println!("tools folder: {}", &tools_response);
println!("distrobox template: {}", &template_name);
println!("terminal command: {}", &_terminal_command);
println!("config file generated and saved to {}\n", config_path.display());
let config_path = &config_folder_path.clone();
let mut install_path = config_path.clone();
let mut password_spray_template_path = install_path.clone();
install_path.push("new_projects.conf");
password_spray_template_path.push("passwordspray.md");
let pass_file_config_line = format!("\npass_file:{}", password_spray_template_path.display());
config_file.write_all(pass_file_config_line.as_bytes()).expect("error writing password spray setting to config file");
let mut passpray_file = fs::File::create(password_spray_template_path).expect("error creating passwordspray file");
write!(passpray_file, "
else{
println!("ok free loader");
}
let fingerprint = get_user_input("will you be using fingerprint authentication for your distroboxes?").to_lowercase();
let mut terminal = String::new();
for desktop in _terminal_commands.keys(){
println!("{}", desktop);
}
let desktop_response = get_user_input("do you use any of these desktops?").to_lowercase();
if desktop_response.contains("y"){
let default_response = get_user_input("do you use the default terminal for your desktop?").to_lowercase();
if default_response.contains("y"){
let de = get_user_input("which desktop do you use?");
terminal = _terminal_commands[&de.as_str()].to_owned();
}
}
else{
println!("OK, then please enter the command you'd use to launch a new terminal and run a command inside of it, replacing the command with three !s");
println!("for example for konsole you'd enter");
println!("konsole -e !!!");
terminal = get_user_input("");
}
if terminal.contains("konsole"){
println!("do you use a specific profile for your attack boxes?");
println!("this is pretty specific to Pyro's setup, so you probably don't");
if get_user_input("").to_lowercase().contains("y"){
let profile_name = get_user_input("what is the name of your profile?");
terminal = format!("konsole --profile {}", profile_name);
}
}
println!("many of the fuctions of this tool assume you're using obsidian or some other markdown editor for note taking");
let obsidian_used = get_user_input("do you use obsidian for your notes?");
if obsidian_used.to_lowercase().contains("y"){
vault_name = get_user_input("the name of the vault you're going to use?");
}
let configuration_string = 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:{}"
, &current_projects.display(), &current_notes.display(), &tools.display(), &upcoming_projects.display(), &upcoming_notes.display(), &template_box_name, &terminal, cracking_rig, rockyou, rule, &password_path.display(), fingerprint, &vault_name);
println!("cool everything, all folders and settings have been entered, now let's save this to a config file...");
thread::sleep(Duration::from_secs(3));
let mut config_file_res = File::create_new(config_path);
if config_file_res.is_err(){
println!("ooof error creating configuration file...");
println!("try creating it manually.");
println!("copy the following configuration and save it to {}", config_path.display());
print!("{}\n", configuration_string);
exit(1);
}
let mut config_file = config_file_res.unwrap();
let config_write_res =write!(config_file, "{}", &configuration_string);
if config_write_res.is_err(){
println!("error writing configuration string to the configuration file!");
println!(" try creating it manually.");
println!("copy the following configuration and save it to {}", &configuration_string);
exit(1);
}
config_write_res.unwrap();
println!("nice the configuration file was written correctly!");
println!("creating project configuration file, and poplulating it with the default project...");
let project_conf_res = File::create_new(&projects_conf_path);
if project_conf_res.is_err(){
let error = project_conf_res.err().unwrap();
println!("ooof error creating the projects configuration file.");
println!("try creating it manually!");
println!("copy the following configuration and save it to {}", &projects_conf_path.display());
println!("customer:name:notes:files:active:time:box_name:stage");
println!("default:default:{}:{}:yes:{}:current", &current_notes.display(), &current_projects.display(), &template_box_name);
exit(1);
}
let mut project_conf_file = project_conf_res.unwrap();
let project_write_res = write!(project_conf_file, "customer:name:notes:files:active:time:box_name:stage\ndefault:default:{}:{}:yes:{}:current", &current_notes.display(), &current_projects.display(), &template_box_name);
if project_write_res.is_err(){
println!("error writing project config file.");
exit(1);
}
project_write_res.unwrap();
let password_file_res = File::create_new(password_path);
if password_file_res.is_err(){
println!("error creating password spray file");
exit(1);
}
let mut password_file = password_file_res.unwrap();
let password_write_res = write!(password_file, "
- [ ] useraspass
- [ ] Seasonyear!
- [ ] Service123!
@@ -357,7 +265,13 @@ Do you have a distrobox set up to function as your template for all new projects
- [ ] P@55w0rd
- [ ] Service
- [ ] Service!
- [ ] Serviceyear!").expect("error writing password spray template");
configure_distrobox();
std::process::exit(0);
- [ ] Serviceyear!
");
if password_write_res.is_err(){
println!("error writing password file");
exit(1);
}
password_write_res.unwrap();
println!("install completed successfully!");
println!("re-run this to launch!");
}

View File

@@ -1,7 +1,8 @@
use std::{io::stdin, path::PathBuf};
use std::{io::stdin, path::PathBuf, process::Command};
use directories::UserDirs;
use reqwest::Response;
use std::fs;
use std::process::exit;
use std::fs::{self, File};
#[derive(Clone)]
pub struct Project{
@@ -21,6 +22,35 @@ mod project_controls;
mod box_controls;
mod info_controls;
mod start_pentest;
mod cli;
pub fn open_overwrite(path: &PathBuf) -> Option<File>{
let file_create_res = fs::OpenOptions::new().create(true).write(true).open(path);
if file_create_res.is_err(){
let error = file_create_res.err().unwrap();
println!("error opening {} file!", path.display());
println!("{}", error);
return None;
}
else {
let file = file_create_res.unwrap();
return Some(file);
}
}
pub fn open_append(path: &PathBuf) -> Option<File>{
let file_create_res = fs::OpenOptions::new().create(true).append(true).open(path);
if file_create_res.is_err(){
let error = file_create_res.err().unwrap();
println!("error opening {} file!", path.display());
println!("{}", error);
return None;
}
else {
let file = file_create_res.unwrap();
return Some(file);
}
}
pub fn get_user_input(prompt: &str) -> String{
let mut response = String::new();
@@ -60,8 +90,23 @@ fn main() {
⠀⠀⠀⠀⢿⡉⠳⡟⣸⠃⠀⠀⠀⠘⢷⣌⠉⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠙⢦⣴⠏⠀⠀⠀⠀⠀⠀⠉⠳⠶⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
");
let user_dirs = UserDirs::new().expect("error getting user directories");
let mut config_path = user_dirs.home_dir().to_path_buf();
let mut config_path = PathBuf::new();
let user_dirs_res = UserDirs::new();
if user_dirs_res.is_none(){
println!("oof couldn't get the config directory the right way, falling back to the stpuid way...");
let get_home_res = Command::new("echo").arg("$HOME").output();
if get_home_res.is_err(){
println!("ooof the stupid way didn't work... this is a bruh moment, gotta fix your environment variabls!!!");
exit(1);
}
let get_home_output = get_home_res.unwrap().stdout;
let home_string = String::from_utf8_lossy(&get_home_output);
config_path.push(home_string.trim());
}
else{
let user_dirs = user_dirs_res.unwrap();
config_path.push(user_dirs.home_dir());
}
config_path.push(".config/pyro_pentest_tool/conf");
if config_path.as_path().exists() == false{
install::install(&config_path);
@@ -78,6 +123,7 @@ fn main() {
let mut upcoming_notes = PathBuf::new();
let mut pass_spray_file = PathBuf::new();
let mut fingerprint = false;
let mut vault_name = 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();
@@ -97,6 +143,7 @@ fn main() {
"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])
}
}
@@ -112,9 +159,9 @@ fn main() {
upcoming project notes: {}
", &project_base_folder.display(), &project_base_notes.display(), &tools_folder.display(), box_template, terminal_command, cracking_rig, &upcoming_files.display(), &upcoming_notes.display());
println!("loading project configs...");
let projects = project_controls::get_projects(&config_path);
let projects = project_controls::get_projects(&config_path, true);
println!("Enter to start main menu");
let mut enter = String::new();
std::io::stdin().read_line(&mut enter).unwrap();
menu::main_menu(projects, config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template, terminal_command, cracking_rig, rockyou, rule, &upcoming_files, &upcoming_notes, &pass_spray_file, fingerprint);
menu::main_menu(projects, config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template, terminal_command, cracking_rig, rockyou, rule, &upcoming_files, &upcoming_notes, &pass_spray_file, fingerprint, vault_name);
}

View File

@@ -9,9 +9,10 @@ use crate::project_controls;
use crate::box_controls;
use crate::info_controls;
use crate::start_pentest;
use crate::cli;
fn next_project_id(config_path: &PathBuf) -> i32{
let projects = project_controls::get_projects(config_path);
pub fn next_project_id(config_path: &PathBuf) -> i32{
let projects = project_controls::get_projects(config_path, false);
let mut new_id = 0;
for project in projects.clone(){
if project.id > new_id{
@@ -21,7 +22,7 @@ fn next_project_id(config_path: &PathBuf) -> i32{
return new_id;
}
fn get_active_project(projects: &Vec<Project>) -> &Project{
pub fn get_active_project(projects: &Vec<Project>) -> &Project{
let mut active_project = &projects[0];
for project in projects{
if project.active == true{
@@ -31,12 +32,27 @@ fn get_active_project(projects: &Vec<Project>) -> &Project{
return active_project
}
pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String, cracking_rig: String, rockyou: String, rule: String, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, password_spray_file: &PathBuf, fingerprint: bool){
pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String, cracking_rig: String, rockyou: String, rule: String, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, password_spray_file: &PathBuf, fingerprint: bool, vault_name: String){
let mut loopize = true;
let mut new_id = next_project_id(&config_path);
let mut threads = Vec::new();
loop {
let active_project = get_active_project(&projects);
let mut notes_folder_string = format!("{}", &active_project.notes_folder.display());
let mut obsidian_folder_vec = PathBuf::new();
let mut reached_vault_folder = false;
for folder in notes_folder_string.split("/").collect::<Vec<&str>>(){
if !folder.contains(&vault_name){
reached_vault_folder = true;
obsidian_folder_vec.push(folder);
}
else{
if reached_vault_folder{
obsidian_folder_vec.push(folder);
}
}
}
let obsidian_uri = format!("obsidian://open?vault={}&file={}", vault_name, obsidian_folder_vec.display().to_string().replace("/", "%2F"));
let mut response = String::new();
let now = Local::now();
let month = now.month();
@@ -98,25 +114,26 @@ pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &
NOTE OPTION 18 WILL SAVE YOUR PROJECTS BEFORE QUITTING
NOTE OPTION 29 WILL SAVE YOUR PROJECTS BEFORE QUITTING
base prject folder: {}
upcoming project folder: {}
Current Project: {} {}
Working Folder: {}
Notes Folder: {}
Obsidian_uri: {}
Box Name: {}
Terminal Command: {}
Current Season: {}
Year: {}
General Notes: {}
Main Menu:
1 .) Show Active Project
2 .) List Projects
3 .) Switch Active Project
4 .) create new project with Pyro's default tool
4 .) create new project with Pyro's default layout
5 .) Save Project Information
6 .) Import New Project - and setup new Distrobox
6 .) Import New Project to Current projects list - and setup new Distrobox
7 .) Remove Project
8 .) Print upcoming projects
9. ) promote project from upcoming to current
@@ -124,51 +141,48 @@ Year: {}
11.) Open A Terminal In this windows for the current active project
12.) open current project's cobalt strike
13.) re-create the distrobox for the current active project
14.) Open Project Files Folder In Dolphin
15.) Open Project Notes Folder In Dolphin
16.) generate userpass file from your obsidian notes
17.) run pyro's initail enum script on a nessus csv for the current project
18.) Print Project Info For Report
19.) Build host discovery cmd command from scope in notes
20.) build portscan command from scope in notes
21.) Stop All Distroboxes
22.) Password Spray (will print password to spray, and wait the obervation window time)
23.) crack password hashes on your cracking rig
24.) Launch bloodhound with the current project's distrobox
25.) prune unused distroboxes (free up system storage)
14.) generate userpass file from your obsidian notes
15.) run pyro's initail enum script on a nessus csv for the current project
16.) build external attack notes from host notes
17.) Build host discovery cmd command from scope in notes
18.) build portscan command from scope in notes
19.) parse a cs portscan services.tsv file
20.) Stop All Distroboxes
21.) Password Spray (will print password to spray, and wait the obervation window time)
22.) Launch bloodhound with the current project's distrobox
23.) Parse GatherContacts output file
24.) prune unused distroboxes (free up system storage)
25.) enter cli
26.) Quit Application
\n",&base_files.display(), &upcoming_files.display(), active_project.customer, active_project.project_name, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, terminal, season, year);
\n",&base_files.display(), &upcoming_files.display(), active_project.customer, active_project.project_name, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, terminal, season, year, &obsidian_uri);
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!("\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!("++Customer: {}|Project name: {}|Stage: {}++",project.customer ,project.project_name, project.stage)}
println!("++++++++++++++++++++")},
"3" => project_controls::switch_project(&mut projects),
"4" => {new_id = new_id + 1; start_pentest::start_pentest(&config_path, &mut projects, new_id, upcoming_files, upcoming_notes, &boxtemplate, password_spray_file)},
"5" => project_controls::save_projects(&projects, &config_path),
"6" => {new_id = new_id + 1; project_controls::new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id, &upcoming_files, &upcoming_notes, fingerprint)},
"7" => project_controls::remove_project(&mut projects, &config_path),
"8" => project_controls::print_upcoming_projects(&projects),
"9" => project_controls::promote_project(&mut projects, &config_path, base_files, base_notes, tools_dir, &boxtemplate, fingerprint),
"10" => box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()),
"11" => box_controls::project_inline_terminal(active_project.clone()),
"12" => {let cs_thread = box_controls::launch_cobalt_strike(active_project.clone()); if cs_thread.is_some(){threads.push(cs_thread.unwrap());}},
"13" => box_controls::make_box(&active_project, &tools_dir, &boxtemplate, false, fingerprint),
"14" => info_controls::open_in_dolphin("files", active_project.clone()),
"15" => info_controls::open_in_dolphin("notes", active_project.clone()),
"16" => info_controls::generate_userpass(&active_project),
"17" => info_controls::run_initial_enum(&active_project),
"18" => info_controls::print_report_information(active_project.clone()),
"19" => info_controls::build_cmd_for_host_discovery(&active_project),
"20" => info_controls::build_cs_portscan_cmd(&active_project),
"21" => box_controls::stop_all_boxes(&projects),
"22" => info_controls::password_spray_help(&active_project, season, lseason, year, &tools_dir, &config_path),
"23" => info_controls::crack_hashes(&cracking_rig, &active_project, &terminal, &rockyou, &rule),
"24" => {let bloodhound_handle = box_controls::launch_bloodhound_gui(active_project.clone()).unwrap(); threads.push(bloodhound_handle);},
"25" => {let prune_thread = box_controls::clean_unused_boxes(&projects, &boxtemplate); if prune_thread.is_some(){threads.push(prune_thread.unwrap());}},
"1" => {let cli_thread_option = cli::run_command(String::from("show active project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"2" => {let cli_thread_option = cli::run_command(String::from("list projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"3" => {let cli_thread_option = cli::run_command(String::from("switch project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"4" => {let cli_thread_option = cli::run_command(String::from("new project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"5" => {let cli_thread_option = cli::run_command(String::from("save projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"6" => {let cli_thread_option = cli::run_command(String::from("import projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"7" => {let cli_thread_option = cli::run_command(String::from("remove project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"8" => {let cli_thread_option = cli::run_command(String::from("show upcoming projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"9" => {let cli_thread_option = cli::run_command(String::from("promote project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"10" => {let cli_thread_option = cli::run_command(String::from("new terminal"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"11" => {let cli_thread_option = cli::run_command(String::from("inline terminal"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"12" => {let cli_thread_option = cli::run_command(String::from("cobalt strike"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"13" => {let cli_thread_option = cli::run_command(String::from("recreate distrobox"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"14" => {let cli_thread_option = cli::run_command(String::from("generate userpass"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"15" => {let cli_thread_option = cli::run_command(String::from("initail enum"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"16" => {let cli_thread_option = cli::run_command(String::from("build attack notes"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"17" => {let cli_thread_option = cli::run_command(String::from("host discovery"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"18" => {let cli_thread_option = cli::run_command(String::from("port scan"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"19" => {let cli_thread_option = cli::run_command(String::from("parse port scan"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"20" => {let cli_thread_option = cli::run_command(String::from("stop boxes"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"21" => {let cli_thread_option = cli::run_command(String::from("password spray"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"22" => {let cli_thread_option = cli::run_command(String::from("bloodhound"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"23" => {let cli_thread_option = cli::run_command(String::from("parse gather contacts"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"24" => {let cli_thread_option = cli::run_command(String::from("prun distroboxes"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"25" => {let cli_threads_option = cli::cli(true, projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_threads_option.is_some(){for thread in cli_threads_option.unwrap(){threads.push(thread);}}},
"26" => {project_controls::save_projects(&projects, &config_path);
let mut stop = String::new();
println!("stop all boxes?\ny/n");

View File

@@ -9,7 +9,6 @@ use std::thread;
use std::time::Duration;
use std::str::FromStr;
use crate::get_user_input;
use fs_extra::file;
use crate::Project;
use crate::box_controls::make_box;
@@ -290,7 +289,7 @@ pub fn remove_project(projects: &mut Vec<Project>, config_path: &PathBuf){
}
}
pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{
pub fn get_projects(config_path: &PathBuf, show: bool) -> Vec<Project>{
let mut mut_config_path = config_path.clone();
mut_config_path.pop();
mut_config_path.push("projects.conf");
@@ -327,7 +326,9 @@ pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{
}
let project_stage = settings[6].to_owned();
let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname, stage: project_stage};
if show{
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
}
projects.push(new_project);
}
}
@@ -445,3 +446,10 @@ pub fn promote_project(projects: &mut Vec<Project>, config_path: &PathBuf, proje
projects.append(&mut projects_to_save);
save_projects(&projects_to_save, config_path);
}
pub fn list_projects(projects: &Vec<Project>){
println!("+++++++++++++++++++++");
for project in projects{
println!("++Customer: {}|Project name: {}|Stage: {}++",project.customer ,project.project_name, project.stage)}
println!("++++++++++++++++++++")
}