25 Commits

Author SHA1 Message Date
Pyro57000
33450cb1ba ditto 2025-05-27 12:19:20 -05:00
Pyro57000
55a6faac2d added the ability to run dnstwist scans for
dns enumeration, and added the ability to modify
the tool's configuration.
2025-05-27 12:18:52 -05:00
Pyro57000
737bee37e7 added dns commands to the menu. 2025-05-20 11:52:46 -05:00
Pyro57000
76f153e981 added the default structure for vishing in the
start_pentest function.
2025-05-20 09:45:11 -05:00
Pyro57000
c4bda0022b added a few functions for dns enumeration
including a function that runs both the records
gathering command and the subdomain bruteforce
command and saves all the output to your notes

I also tweaked the gather contact parsing function
in order to save the output to the enumeration.md

This is important because the
print report information function actually works now!
it will read your enumeration notes and print the
data in a format that should paste into word
easily.
2025-05-19 16:57:53 -05:00
Pyro57000
aef65f3b03 added the command to build the nmap portscan
command instead of just running it.
I think running it is broken atm.
2025-05-16 16:16:07 -05:00
pyro57000
9d8154c7a1 added a function to update all your git tools. 2025-05-12 14:53:46 -05:00
pyro57000
4e38749c86 added a function to print the sharpersist
command to add a scheduled task!

also updated it so that it creates a backup
of your projects.conf file incase the working one
gets corrupted somehow.
2025-05-05 13:36:23 -05:00
pyro57000
0913703976 added some fucntion, note the portscan fucntion
is still borked... working on it.
2025-05-01 12:50:50 -05:00
pyro57000
fbd524ae7f added some functions, note portscanning is borked
still working on it.
2025-05-01 12:50:18 -05:00
pyro57000
dabca4c20a added more verbose help features. 2025-04-30 15:37:41 -05:00
pyro57000
7dec1cb0cb added the menu back, and added project specific
submenus that you can drop into!
2025-04-30 14:30:59 -05:00
pyro57000
a0b6065040 jsut comitting becasue rust analyzer brokey 2025-04-30 10:29:33 -05:00
pyro57000
f99e395241 fixed a bug where switching projects wouldn't
switch projects.
2025-04-30 09:59:50 -05:00
pyro57000
0cbe33357a added clear screen function to cli 2025-04-22 12:57:39 -05:00
pyro57000
4bd67a486f added project information to the cli prompt 2025-04-22 12:53:31 -05:00
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
15 changed files with 2444 additions and 331 deletions

View File

@@ -365,6 +365,18 @@ dependencies = [
"syn",
]
[[package]]
name = "dns-lookup"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5766087c2235fec47fafa4cfecc81e494ee679d0fd4a59887ea0919bfb0e4fc"
dependencies = [
"cfg-if",
"libc",
"socket2",
"windows-sys 0.48.0",
]
[[package]]
name = "either"
version = "1.13.0"
@@ -1241,11 +1253,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "pentest_tool"
version = "0.2.0"
version = "3.1.1"
dependencies = [
"chrono",
"clearscreen",
"directories",
"dns-lookup",
"fs_extra",
"futures-io 0.2.1",
"reqwest",

View File

@@ -1,12 +1,13 @@
[package]
name = "pentest_tool"
version = "0.2.0"
version = "3.1.1"
edition = "2021"
[dependencies]
chrono = "0.4.39"
clearscreen = "3.0.0"
directories = "5.0.1"
dns-lookup = "2.0.4"
fs_extra = "1.3.0"
futures-io = { version = "0.2.0-beta" }
reqwest = {version = "0.12.12", features = ["blocking", "json"]}

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;

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

@@ -0,0 +1,341 @@
use std::os::unix::thread;
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;
use crate::portscan_controls;
use crate::victim_commands;
use crate::enumeration;
use crate:: tool_controls;
use crate::configuration;
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!("Command: list projects\nAliases: lp, listp, list p\n\nThis command lists all projects currently tracked by the pentest_tool"); return;},
"switch project" | "swp" | "switch p" | "switchp" => {println!("Command: switch project\nAliases: swp, switch p, switchp\n\nThis command will switch the active project from the current one to a new on of your choosing. It will prompt you to make a selection."); return;},
"show active project" | "show active" | "sa" | "show a" => {println!("Command: show active project\nAliases: sa, show a\n\nThis command shows information about the currently active project. NOTE the most useful information is already displayed above the CLI prompt."); return;},
"create new project" | "cnp" | "new project" | "np" => {println!("Command: create new project\nAliases: cnp, new project, np\n\nThis command creates a new project and default note structure based on pyro's perferred note structure. It will prompt you for any needed information."); return;},
"save projects" | "sp" | "save" | "s" => {println!("Command: save projects\nAliases: sp save\n\nThis command saves all project information to the ~/.config/pyro_pentest_tool/projects.conf file"); return;},
"import project" | "ip" | "import" => {println!("Command: import project\nAliases: ip, import\n\nThis command will impot an existing project and set up a new distrobox for the project if it is a current project."); return;},
"remove project" | "rp" | "remove" | "rmp" => {println!("Command:remove project\nAliases:rp, remove, rmp\n\nThis command removes a project from the list of projects tracked by the pentest_tool, and will destroy its distrobox. It does not remove any directories used or created by the distrobox. Run this after the report is written."); return;},
"show upcoming projects" | "sup" | "show upcoming" => {println!("Command:show upcoming projects\nAliases:sup, show upcoming\n\nThis command shows a list of upcoming projects. Use this to verify which project you want to promote when the project enters the active phase."); return;},
"promote project" | "pp" | "promote" => {println!("Command:promote project\nAliases:pp (ha), promote\n\nThis command promotes an upcoming project to a current project. It will copy the folders that were created over to the current project space and set up a new distrobox for the project."); return;},
"new terminal" | "enter" | "enter terminal" | "nt" | "et" => {println!("Command:new terminal\nAliases:enter, enter terminal, nt, et\n\nThis command spawns a new terminal window in the active project's distrobox. Use this to interact with your project's distrobox."); return;},
"inline terminal" | "it" | "enter inline" | "ei" => {println!("Command:inline terminal\nAliases:it enter, inline, ei\n\nThis command spawns a terminal in this window using the current active project's distrobox"); return;},
"cobalt strike" | "cs" => {println!("Command:cobalt strike\nAliases:cs\n\nThis command opens cobalt strike in the active project's distrobox, and spins it off as a new thread to ensure it doesn't block the rest of this tools operation. NOTE the cobalt strike window will need to be closed before this tool exits sucessfully."); return;},
"recreate distrobox" | "rdb" | "ndb" | "new distrobox" => {println!("Command:recreate distrobox\nAliases:rdb, ndb, new distrobox\n\nThis command destroyes the existing distrobox for the currently active project, and clones a new one based on the current state of the template distrobox."); return;},
"generate userpass" | "userpass" | "gup" | "up" => {println!("Command:generate userpass\nAliases:userpass, gup, up\n\nThis command generates a userpass file based on the active project's notes. The file will be in the username:password format."); return;},
"inital enum" | "ie" | "enum" => {println!("Command:initial enum\nAliases:ie, enum\n\nThis command runs the initial enum script on a nessus csv and saves the output to the active project's notes in the host_notes.md file."); return;},
"build attack notes" | "ban" | "attack notes" | "hn" => {println!("Command:build attack notes\nAliases:ban, attack notes\n\nThis command builds the active project's attack note based on the active project's host notes (for external tests). It is expected that you'd run the initial enum command, then manually fill out the enumeration talbes with correct service names and ports."); return;},
"host discovery" | "build host discovery" | "hd" | "bhd" => {println!("Command:host discovery\nAliases:build host discovery, hd, bhd\n\nThis command prints the host discovery ping command for the active project, based on the scope table in the general.md notes file."); return;},
"cobaltstrike port scan" | "cs port scan" | "csps" => {println!("Command:port scan\nAliases:cs port scan, cobaltstrike port scan, csps, ps (tell your cat I said that)\n\nThis command prints the cobalt strike portscan command based on the active project's scope table in the general.md notes file"); return;},
"parse port scan" | "pps" | "parse scan" => {println!("Command:parse port scan\nAliases:pps, parse scan\n\nThis commmand parses a cobalt strike portscan TSV and saves interesting hoests to files to the active project's files folder. The host files are designated with the service that was detected that might be interesting. Use this to generate target lists for specific protocols."); return;},
"stop boxes" | "stop distroboxes" | "sdb" => {println!("Command:stop boxes\nAliases:stop distroboxes, sdb\n\nThis command stops all distroboxes for the tracked projects. Note if the distrobox isn't running you will see errors in the console, you can safely ignore these."); return;},
"password spray" | "pass spray" | "pas" => {println!("Command:password spray\nAliases:pass spray, pas\n\nThis command iterates through the password spray note file and print the command to perform the spray, waiting the proper observation window beteen commands. It prompts you to save if needed. NOTE this will block execution for the rest of the program until it is either finished, or you save and exit the password spray function. I'm working on making this better."); return;},
"bloodhound" | "bh" => {println!("Command:bloodhound\nAliases:bh\n\nThis command launches bloodhound in the active project's distrobox. It will automatically start neo4j before staring bloodhound."); return;},
"parse gather contacts" | "pgc" | "parse contacts" | "pc" => {println!("Command:parse gather contacts\nAliases:pgc, parse contacts, pc\n\nThis command parses output saved from the gather contacts burpsuite extension."); return;},
"prune distroboxes" | "pdb" | "prune" => {println!("Command:prune distroboxes\nAliases:pdb, prune\n\nthis command prunes distroboxes for all projects that are not being tracked by this tool (frees up system storage). This will start all the currently acvtive distorboxes to ensure they don't get pruned, and then will delete all the not-started distrobox volumes and resources."); return;},
"clear" | "clear screen" | "cls" => {println!("Command:clear\nAliases:clear screen, cls\n\nThis command clears the screen of command output."); return},
"exit" => {println!("Command:exit\nAliases:(none)\nThis command exits the pentest_tool, it will save all project infomation, and wait for all threads to re-join the main thread before exiting."); return;},
"settings" => {println!("\n\nThe settings file is located at ~/.config/pyro_pentest_tool/conf\n\nThe format is setting_name:setting_value.\n\nNeeded settings are\n project_files - the place to store current project files folders\n\n projtect_notes - the place to store current project notes\n\n tools_folder - the place to store custom tools like those downloaded from github\n\n upcoming_files - the place to store upcoming project files folders\n\n upcoming_notes - The place to store upcoming project note files\n\n box_template - the name of the distrobox you want to clone for project boxes\n\n terminal - the command you use to launch a terminal, while running a specific command: Ex: konsole -e \n\n cracking_rig - the user and host you use for a personal cracking rig in the openssh formating: Ex: pyro@cracking_rig or pyro@192.168.1.101 if you do not have a cracking rig the default is @n\n\n rockyou_location - the location on the cracking rig for the rockyou.txt file default is n\n\n rule_location - the location on the cracking rig for the one rule to rule them all file. Default is n\n\n pass_file - this is the location where you store your standard password spray file. If you do not have a custom one this tool provides one. The default is ~/.config/pyro_pentest_tool/passwordspary.md\n\n fingerprint - this is whether you want fingerprint authentication within your distroboxes, takes y/n\n\n vault_name - the name of your obsidian vault, default is notes\n\n"); return;},
"parse normal nmap file" | "pnnf" | "parse nmap" | "pn" => {println!("Command:parse normal nmap file\nAliases: pnnf, parse nmap, pn\n\nThis command parses the normal output of an nmap scan (like if you just tee'd or >'d it to a file) and outputs in host:port or int the coablt strike tsv format. It will attempt to find the file within the active project's files folder, and if it can't find the file it will prompt you for input.")},
"sharpersist command" | "spc" | "sharp scheduled task" | "sst" => {println!("Command: sharpersist command\nAliases: spc, sharp scheduled task, sst\n\nThis comand prints the commands to run to use sharpersist.exe to create a scheduled task that runs hourly called FRPersist.")},
"port scan" | "ps" | "nmap" | "nmap scan" | "ns" | "nm" => {println!("Command: port scan\nAliases: ps, nmap, nmap scan, ns, nm\n\nThis command runs an nmap scan against the scope in the active projects notes, and saves the output.")},
"show scope" | "ss" | "show s" | "s s" | "scope" => {println!("Command:show scope\nAliases:ss, show s, s s, scope\n\nThis command displays the current project's scope as just the hosts in the scope table in your notes.")},
"port scan command" | "psc" | "nmap command" | "nmc" => {println!("command:port scan command\nAliases:psc,nmap command, nmc\n\nThis command will print the nmap command to manually run a scan to the terminal so you can copy paste it.")},
"update git tools" | "ugt" | "update git" | "ug" => {println!("Command: update git tools\nAliases: update git, ugt, ug\n\nThis command attempts to update the git tools in your tools directory, it will attempt to update every directory as a git project. If the directory is not a git project it should just error out and continue to the next one.")},
"dns records" | "dr" => {println!("Command:dnsrecords\nAliases:dr\n\nThis command will run dns recon inside of your distrobox and save the results to your enumeration notes.")},
"brute force subdomains"| "bsd" | "gobuster dns" | "gd" => {println!("Command:brute force subdomains\nAliases:bsd,gobuster dns, gd\n\nthis command will run gobuster in the project's distrobox and save the results to your notes.")},
"dns enumeration" | "de" | "all dns stuff" | "ads" | "dns stuff" | "ds" => {println!("Command:dns enumeration\nAliases:de, all dns stuff, ads, dns stuff, de\n\nThis command will perform both dns record enumeration with dnsrecon, and subdomain enumeration using gobster inside of your distrobox and save the output to your notes.")},
"modify tool config" | "mtc" => {println!("Command: modify tool config\nAliases: mtc\n\nThis command lets you modify the tool's configuration.");}
_ => ()
}
}
println!("Welcom to Pyro's pentest command line!");
println!("the pentest_tool uses a configuration file to store your settings. This configuration file is located at ~/.config/pyro_pentest_tool/conf.\nYou can modify this file, but do so cautiously, incorrect formatting will cause this program to have a bruh moment.\nThe correct format is setting_name:setting_value\nExample:\nprojecT_files:/var/home/pyro/pentests/current");
println!("for help configuring the settings file run help settings");
println!("available commands: name | aliases | ...");
print!("
menu | main menu | mm
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
clear | clear screen | cls
parse nomral nmap file | pnnf | parse nmap | pn
show scope | ss | show s | s s | scope
sharpersist command | spc | sharp scheduled task
port scan | ps | nmap | nmap scan | ns | nm
port scan command | psc | nmap command | nmc
update git tools | ugt | update git | ug
dns records | dr
brute force subdomains| bsd | gobuster dns | gd
dns enumeration | de | all dns stuff | ads | dns stuff | ds
modify tool config | mtc
help | ? | -h
")
}
pub fn get_active_project(projects: &Vec<Project>) -> &Project{
let mut active_project = &projects[0];
for project in projects{
if project.active == true{
active_project = project
}
}
return active_project
}
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{
new_id = project.id + 1;
}
}
return new_id;
}
pub fn run_command(cmd: String,
mut projects: &mut 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 = next_project_id(&config_path);
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();
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); 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" => {portscan_controls::build_cmd_for_host_discovery(&active_project); return None;}
"host discovery" | "build host discovery" | "hd" | "bhd" => {portscan_controls::build_cmd_for_host_discovery(&active_project); return None},
"cobaltstrike port scan" | "cs port scan" | "csps" => {portscan_controls::build_cs_portscan_cmd(&active_project); return None},
"parse port scan" | "pps" | "parse scan" => {portscan_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},
"parse normal nmap file" | "pnnf" | "parse nmap" | "pn" => {portscan_controls::parse_normal_nmap_output(&active_project); return None;},
"show scope" | "ss" | "show s" | "s s" | "scope" => {let scope_res = info_controls::get_scope_entries(&active_project); if scope_res.is_some(){for host in scope_res.unwrap(){println!("{}", host)}}return None},
"update git tools" | "ugt" | "update git" | "ug" => {tool_controls::update_git_tools(tools_dir); return None},
"port scan" | "ps" | "nmap" | "nmap scan" | "ns" | "nm" => {portscan_controls::run_nmap_portscan(&active_project); return None;},
"port scan command" | "psc" | "nmap command" | "nmc" => {portscan_controls::build_nmap_command(&active_project); return None;}
"sharpersist command" | "spc" | "sharp scheduled task" | "sst" => {victim_commands::sharp_persist_command(&tools_dir); return None;},
"dns records" | "dr" => {let dns_handle = enumeration::run_dns_enumeration(&active_project, None, true); return dns_handle;},
"brute force subdomains"| "bsd" | "gobuster dns" | "gd" => {let gobuster_handle = enumeration::bruteforce_subs(&active_project, None,None, true); return gobuster_handle},
"dns enumeration" | "de" | "all dns stuff" | "ads" | "dns stuff" | "ds" => {let all_dns_handle = enumeration::do_all_dns_enumeration(&active_project); return all_dns_handle},
"dns squatting scan" | "dnstwist" | "dss" => {let twist_handle = enumeration::dns_squatting(&active_project, None, true); return twist_handle},
"print report information" | "pri" => {info_controls::print_report_information(&active_project); return None;},
"modify tool config" | "mtc" => {configuration::generate_tool_config(&config_path); return None;},
_ => {help(None); println!("\n\n unknown command."); return None;}
}
}
fn print_banner(banner: &str){
print!("{}", banner);
}
pub fn cli(interactive: bool,
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 threads = Vec::new();
if interactive{
let mut loopize = true;
let banner = "
,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,''''
,;;;::ccccc::::::ccc:;;;:ccccccclc::ccccccc::;;;;;;;;;;,,;;;;;;;;;;;;;;;,,,,,,,,,,,'''''''''',,,,,''
,;;:::ccc:cc:::ccc:::::::ccccclcccllccccllc::::::;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,''''''''...'',,,,'
,;;:::c::ccc::cc::::::::cclollllllolllllccccc::cc:::::;;;;;;;;;;;;;;;;;;,,,,,,,,,,'''''''''''..'',,,
,;::::::ccc::cc::::::ccloodollooooollllcccccc:llc::::::;;;;;;:;;;;;;;;;;;,,,,,,,,,,''''''''''''''',,
,;:::::c:::c::::ccccloddxxddxxddddodollllccclclcccccc:::::::::::::::;;;;;;;;,,,,,,,,,'''''''''''''',
;;:::::::c::c::clllodxxO0OKX0kkOkkxxxxxdooooolcccccccc:::::::cllc::::::::;;;;;,,,,,,,,,,'''''''''',,
;:::::c:cc::cclolclokO0KXNNX00KKK0O0KOxdxxdooccccclllccccccccdkdlcccccllcc::;;;;;;;;,,,,,,,,,,,',,,,
::::::cc::::coxdlllok00KNWNXXX0KXKOKNOkO0kddocccllllllccccclx0Kkodddoodddoollc::;;;;;;;;;,,,,,,,,,,,
:::::::c:::clkkodooxxkO0KX0xookKKkkKNKO0KkdoodolcllllollolldKNNXKKXKKKKKK0Okxdocc:cc:::;;;;;,,,,,,,,
::cc::cc::cldxllolodxxdoddc'.,okkxOXXOdxkxolkOdlllllllldkdokXNNNNNNNNX0kxollcc:::::cclc::;;;;;;,,,,,
:::::::cccldko:,.';cc:;:;....;clllOXOxxOkocoK0xooddollx0Odd0XNNNNNX0Oxdolcccc::;;;;;;:cllc:;;:;,,,,,
;;::c:::ccldkl;'...,''''....',;,';dxdkkdc;cONKxxOOOxddOXOdx0XXNNWNOdddxkOOOOkdllc:;,,,;cool:;;;;;,,;
,;;::;;::llco:,'..''..,.......''.';:ldl;,,:xXNOOXXX0xdkOOddkXNNWWWX00KXNNX0kxddddol:,''';lol:;;:;;,;
,,,;;;;;:coc;;'..;;. .,,;'.......':dxdc;ldc,l00xkXNKxodkkkkk0XNWWMWWWNXKOxdooolooool:;'..,lol::::;;;
',,,;;;;:cllc;,..',. ','. .....;odoo:;co:.'ldldOOx::x0KXX0kk0XNWWWXOxdoooollllllllcc:'..':lc:::;;;
',,,;;;;;:cccc:,. . ..;cccccc:,,''.',,:l:;;:oOXXKOOOkxOXNNNXOxddooooollllllllc,....:c:::;;;
''',,,;;;;;;;cll,.. .. .':lc:c:;,,......,,;:;;:cokkxxO00O0KXNNN0kxkkkxddoollllllll:'...':::::::
.''',,,,,,,,,;:c:,.. ..'. ..','',;;'........',,;:;:::cdxxxddkKXXXKKKKXXXXXX0kdoloolllol;....,;:::::
..'''',,'',,,;;:::;..... ............... .'.....,;,',:ldc;:ldOKKK00KNWWWNNXK0xoooodooooo:'...';;;:;;
....'''''',,;;::cll:,''...... . ..........'...,;;l:,,;oddkOOKNWWWWNX0kdodxxxxdddooc,...',;;;;,
......''''',;::cloodddol;. ...........',.;;,,',:cxdd0KXXKKKXKOkxxkkkxdddooc,...';;,,,,
........''',;:clloddxxdo:'. .. ...........''.'',;c:;cccodddk0KX0OOkxddddddo:...';;;;,,'
..........',;:cclodxxkxdl:,.. ... ......'....'..':c,..'.,c,,,.,cxkO00Okxdddddc'..';:;;;,,'
..........',;;:cloodxkkkdol:'. . ... ...... ......';c'.'...:;',;,'..,lxO00Oxxxo:'...,::;;,,,,
...........',;;:clodxkOOkxdol;. .. .. ... ....',::'.''.',.........'oxdxxxdl;...';::;;;,,''
............',;:clodxkkOOOxddo;. ...... ........',,',................';:clc;,...';::;;,,,'''
............',;:cldxkkOkkkxdddo;. ..... .........,'...........'''','.',,'''....,cc:;;,,'''..
.............';:cldxxkkkkxddddxl,. .... .;c;'...................',;;cc;'...';clolc:;,,'''...
............'';clodxkkkkkxddddddl' ... .:lc;'................. ....',,''';lxkxdlc:;,'''....
........',,;:;coddxkOOOOOkxxddddd:. ... ..,''.................. . ..;cdkkkkxoc:;,'''.....
......',;::cllodxkkOOOOOOkxxxddddc. ... ..,;,'................... .. .':odO0Okdl:;,'''......
.....',;:cloddxxkOOOOOOOkkxxdoooo;. .. ......................... .';cokOOxlc:;,''.......
....,;:clodxxkkOOOkO0OOOOxdlcc;;,...... .';,................. ...',:ldxxxdlc;,''.......
...,:clodooxkkkO0OxO00OOxo:;;,. ........ .''.......... .. .. ..,,,;:codxxdlc:;,'.......
'',;clodolokOkxkOkkO00Oko:;;;. ..... .. .,,........'. .. .. .. ..........;:codocclc:,,'......
___ __ __ ___ __ ___ __
| | |__ | / ` / \\ |\\/| |__ |__| /\\ / ` |__/ |__ |__)
|/\\| |___ |___ \\__, \\__/ | | |___ | | /~~\\ \\__, | \\ |___ | \\
__ ___ ___ __ __
/ _` |__ | |__) | | |\\ | | |\\ | / _`
\\__> |___ | | |/\\| | \\| | | \\| \\__>
";
print_banner(banner);
while loopize{
project_controls::save_projects(&projects, &config_path);
let active_project = get_active_project(&projects);
let current_information = format!("
Active Project: {}, {}
Project Status: {}
Files Folder: {}
Notes Folder: {}
Boxname: {}
Obsidian URI: {}
for help enter help or ?. for information about a specific command enter help (command)
", active_project.customer, active_project.project_name, active_project.stage, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, "coming soon");
let prompt = format!("\n{}:{}\nCommand?", active_project.customer, active_project.project_name);
let command = get_user_input(&prompt);
match command.as_str(){
"exit" => loopize = false,
"menu" | "main menu" | "mm" => {let menu_thread_option = menu::main_menu(&mut projects, 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 menu_thread_option.is_some(){for thread in menu_thread_option.unwrap(){threads.push(thread);}}},
"print banner" | "banner" => print_banner(banner),
"clear" | "clear screen" | "cls" => {clear().unwrap(); print_banner(banner);},
"list threads" | "threads" | "lst" => println!("There are {} threads still running.", threads.len()),
"info" => println!("{}", current_information),
_ => {let thread_option = run_command(command, &mut projects, 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())}},
}
}
project_controls::save_projects(&projects, &config_path);
if get_user_input("do you want to stop all the boxes?").contains("y"){
box_controls::stop_all_boxes(&projects);
}
}
if threads.len() > 0{
println!("closing threads...");
println!("note this will hang until all threads have completed");
println!("please make sure to close all spawned programs such as cobalt strike and bloodhound.");
for thread in threads{
let _ = thread.join();
}
}
}

View File

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

View File

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

View File

@@ -1,6 +1,9 @@
use std::collections::HashMap;
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;
@@ -15,6 +18,9 @@ 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_controls::get_projects;
use crate::Project;
pub fn run_initial_enum(project: &Project){
@@ -96,130 +102,77 @@ 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{
if line.contains("#"){
if !line.contains("##"){
current_host = line.split_whitespace().collect::<Vec<&str>>()[1].trim().to_owned();
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("## "){
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(":"){
for port in &mut ports{
if port.number == item.trim(){
if port.hosts.contains(&current_host){
port.hosts.push(current_host.clone());
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.service == service{
new = false;
let host_entry = format!("{} {}", host.clone(), port_number.clone());
port.hosts.push(host_entry);
}
is_new = false;
}
match new{
true => {let new_port = Port{service: service.clone(), hosts: vec![format!("{} {}", host.clone(), port_number.clone())]}; ports.push(new_port);},
false => ()
}
}
if is_new{
let new_port = Port{number: line.trim().to_owned(), hosts:vec![current_host.clone()]};
}
}
}
}
}
println!("{} parsed!", host);
}
for port in ports{
let output = format!("# {}\nHOSTS:\n", port.number);
for host in port.hosts{
// output.push_str("## {}");
}
}
}
pub 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");
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;
}
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::<Vec<&str>>()[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 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{
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.");
}
}
let mut _discovery_command = "";
_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 mut _range_command = String::new();
if need_shell{
_range_command = format!("{}{}","shell ", _discovery_command.replace("!!!", &network_string));
need_shell = false;
}
else{
_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);
}
pub fn generate_userpass(project: &Project){
@@ -259,69 +212,116 @@ pub fn open_in_dolphin(folder: &str, project: Project){
.spawn().expect("error opening dolphin");
}
pub fn print_report_information(project: Project){
let mut general_notes_path = project.notes_folder.clone();
let mut finding_notes_path = project.notes_folder.clone();
general_notes_path.push("general.md ");
finding_notes_path.push("findings.md ");
println!("general: {}\nfindings: {}", general_notes_path.display(), finding_notes_path.display());
let general_string = fs::read_to_string(general_notes_path).expect("error opening general notes");
let findings_string = fs::read_to_string(finding_notes_path).expect("error opening findings notes");
let general_lines: Vec<&str> = general_string.split("\n").collect();
let finding_lines: Vec<&str> = findings_string.split("\n").collect();
println!("Scope:");
for line in general_lines{
if line.contains("|"){
let split: Vec<&str> = line.split("|").collect();
println!("{}\t{}", split[0], split[2]);
pub fn print_report_information(project: &Project){
let scope = get_scope_entries(project);
println!("Project: {} {}", project.customer, project.project_name);
if scope.is_some(){
println!("SCOPE:");
for entry in scope.unwrap(){
println!("{}", entry);
}
println!("\n\n");
}
println!("Findings");
for line in finding_lines{
if line.contains("# "){
println!("{}", line);
let mut notes_path = project.notes_folder.clone();
notes_path.push("enumeration.md");
if notes_path.exists(){
let enumeration_read_res = fs::read_to_string(notes_path);
if enumeration_read_res.is_err(){
let error = enumeration_read_res.err().unwrap();
println!("error reading enumeration notes!");
println!("{}", error);
}
else if line.contains("- "){
println!("{}", line)
}
}
}
pub fn build_cs_portscan_cmd(project: &Project){
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::<Vec<&str>>()[1];
if ip.contains(","){
let ips: Vec<&str> = ip.split(",").collect();
for ip in ips{
ranges.push(ip.trim_end().trim_start());
else{
let enumeration_text = enumeration_read_res.unwrap();
let sections: Vec<&str> = enumeration_text.split("\n---\n").collect();
let mut records_dict = HashMap::new();
let mut subs_dict = HashMap::new();
let mut extrapolated_dict = HashMap::new();
for section in sections{
let mut domain_name = String::new();
let mut domain_records = Vec::new();
let mut subdomains = Vec::new();
let lines: Vec<&str> = section.split("\n").collect();
if section.contains("## DNS Records"){
for line in &lines{
if line.contains("####"){
domain_name = line.split_whitespace().collect::<Vec<&str>>()[1].to_owned();
}
if line.contains("|"){
let data: Vec<&str> = line.split("|").collect();
if data.len() == 5{
if !data.contains(&"Domain name") || !data.contains(&"----"){
domain_records.push(format!("{}\t{}\t{}", data[1], data[2], data[3]));
}
}
}
}
records_dict.insert(domain_name.to_owned(), domain_records);
}
if section.contains("Subdomain Enumeration"){
for line in &lines{
if line.contains("####"){
domain_name = line.split_whitespace().collect::<Vec<&str>>()[1].to_owned();
}
if line.contains("|"){
let data: Vec<&str> = line.split("|").collect();
if data.len() == 4{
subdomains.push(format!("{}\t{}", data[1], data[2]));
}
}
}
subs_dict.insert(domain_name.to_owned(), subdomains);
}
if section.contains("Email Enumeration"){
let section_parts: Vec<&str> = section.split("### ").collect();
for part in section_parts{
let mut domain_name = String::new();
let mut emails = Vec::new();
if part.contains("## "){
let part_lines: Vec<&str> = part.split("\n").collect();
for line in part_lines{
if line.contains("##"){
domain_name = line.split_whitespace().collect::<Vec<&str>>()[1].to_owned();
}
}
}
if part.contains("Extrapolated Emails"){
let part_lines: Vec<&str> = part.split("\n").collect();
for line in part_lines{
if line.contains("@"){
emails.push(line.to_owned());
}
}
}
extrapolated_dict.insert(domain_name, emails);
}
}
else{
ranges.push(ip.trim_end().trim_start());
}
println!("\nDNS RECORDS");
for domain in records_dict.keys(){
println!("{}", domain);
println!("total records:{}", &records_dict[domain].len());
for recrod in &records_dict[domain]{
println!("{}", recrod);
}
}
println!("\nSUB DOMAINS");
for domain in subs_dict.keys(){
println!("{}", domain);
println!("total subs:{}", &subs_dict[domain].len());
for sub in &subs_dict[domain]{
println!("{}", sub);
}
}
println!("\nEXTRAPOLATE EMAILS");
for domain in extrapolated_dict.keys(){
println!("{}", domain);
for email in &extrapolated_dict[domain]{
println!("{}", email);
}
}
}
}
let portscan_cmd = "portscan !!! 1-1024,1433,2222,3306,3389,5000-6000,8000,8080,8443 icmp 512";
let mut _range_command = String::new();
let combined_ranges = ranges.join(",");
let final_command = portscan_cmd.replace("!!!", &combined_ranges);
println!("{}", final_command);
}
fn find_file(dir: &PathBuf, file_name: &str) -> Option<String>{
@@ -776,3 +776,160 @@ 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("enumeration.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 mut write_success = true;
let note_wriet_res = write!(email_note_file, "# Email Enumeration\n");
if note_wriet_res.is_err(){
let error = note_wriet_res.err().unwrap();
println!("error writing to email notes file!");
println!("{}", error);
write_success = false;
}
if write_success{
write!(email_note_file, "## {}\n", &domain).unwrap();
write!(email_note_file, "### Extrapolated Emails\n").unwrap();
}
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!");
}
if write_success{
write!(email_note_file, "\n---\n").unwrap();
}
}
pub fn get_all_host_addresses(project: &Project){
println!("to do");
}
pub fn get_scope_entries(project: &Project) -> Option<Vec<String>>{
let mut general_path = project.notes_folder.clone();
general_path.push("general.md");
let genera_read_res = read_to_string(general_path);
if genera_read_res.is_err(){
let error = genera_read_res.err().unwrap();
println!("ooof error reading your general notes file!");
println!("{}", error);
return None;
}
let general_string = genera_read_res.unwrap();
let mut read_first_entry = false;
let general_lines: Vec<&str> = general_string.split("\n").collect();
let mut hosts = Vec::new();
for line in general_lines{
if line.contains("|"){
if !line.contains("--"){
if read_first_entry{
let data: Vec<&str> = line.split("|").collect();
let scope_entry = data[1].trim();
println!("{} found!", scope_entry);
hosts.push(scope_entry.to_owned());
}
else{
read_first_entry = true;
}
}
}
}
return Some(hosts);
}

View File

@@ -1,14 +1,14 @@
use std::collections::HashMap;
use std::env::home_dir;
use std::fs::{File, create_dir_all, remove_dir_all};
use std::io::Read;
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::Path, path::PathBuf};
use std::process;
use std::{process, thread};
use std::process::exit;
use directories::UserDirs;
@@ -29,13 +29,13 @@ pub fn install(config_path: &PathBuf){
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();
projects_conf_path.push("projects.");
let mut bell_file_path = config_folder_path.clone();
let del_on_fail = config_folder_path.clone();
projects_conf_path.push("projects.conf");
@@ -94,7 +94,7 @@ pub fn install(config_path: &PathBuf){
for name in distrobox_names{
if !name.contains("NAME"){
have_box = true;
println!("name")
println!("{}", name);
}
}
let mut template_box_name = String::new();
@@ -144,24 +144,24 @@ pub fn install(config_path: &PathBuf){
println!("ok free loader");
}
let fingerprint = get_user_input("will you be using fingerprint authentication for your distroboxes?").to_lowercase();
let terminal = String::new();
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];
}
}
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("");
}
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");
@@ -170,6 +170,11 @@ pub fn install(config_path: &PathBuf){
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:{}
@@ -182,9 +187,11 @@ cracking_rig:{}
rockyou_location:{}
rule_location:{}
pass_file:{}
fingerprint:{}"
, &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);
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...");
@@ -206,6 +213,7 @@ fingerprint:{}"
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());
@@ -225,7 +233,7 @@ fingerprint:{}"
println!("error creating password spray file");
exit(1);
}
let password_file = password_file_res.unwrap();
let mut password_file = password_file_res.unwrap();
let password_write_res = write!(password_file, "
- [ ] useraspass
- [ ] Seasonyear!
@@ -258,10 +266,11 @@ fingerprint:{}"
- [ ] Service!
- [ ] Serviceyear!
");
if password_file_res.is_err(){
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

@@ -2,7 +2,7 @@ use std::{io::stdin, path::PathBuf, process::Command};
use directories::UserDirs;
use reqwest::Response;
use std::process::exit;
use std::fs;
use std::fs::{self, File};
#[derive(Clone)]
pub struct Project{
@@ -17,11 +17,45 @@ pub struct Project{
}
mod install;
mod menu;
mod project_controls;
mod box_controls;
mod info_controls;
mod start_pentest;
mod cli;
mod menu;
mod portscan_controls;
mod victim_commands;
mod enumeration;
mod tool_controls;
mod configuration;
pub fn open_overwrite(path: &PathBuf) -> Option<File>{
let file_create_res = fs::OpenOptions::new().create(true).write(true).open(path);
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();
@@ -94,6 +128,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();
@@ -113,6 +148,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])
}
}
@@ -128,9 +164,7 @@ 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);
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);
let projects = project_controls::get_projects(&config_path, true);
let _continue = get_user_input("press enter to load command line interface.");
cli::cli(true, 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

@@ -1,57 +1,29 @@
use std::path::PathBuf;
use std::process::exit;
use chrono::Datelike;
use std::thread::JoinHandle;
use clearscreen::clear;
use clearscreen;
use chrono::Local;
use crate::get_user_input;
use crate::Project;
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);
let mut new_id = 0;
for project in projects.clone(){
if project.id > new_id{
new_id = project.id + 1;
}
}
return new_id;
}
fn get_active_project(projects: &Vec<Project>) -> &Project{
let mut active_project = &projects[0];
for project in projects{
if project.active == true{
active_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(projects: &mut 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 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 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)}
}
clear().expect("error clearing screen");
print!("
let banner = "
,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,''''
,;;;::ccccc::::::ccc:;;;:ccccccclc::ccccccc::;;;;;;;;;;,,;;;;;;;;;;;;;;;,,,,,,,,,,,'''''''''',,,,,''
,;;:::ccc:cc:::ccc:::::::ccccclcccllccccllc::::::;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,''''''''...'',,,,'
@@ -88,35 +60,24 @@ pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &
....,;:clodxxkkOOOkO0OOOOxdlcc;;,...... .';,................. ...',:ldxxxdlc;,''.......
...,:clodooxkkkO0OxO00OOxo:;;,. ........ .''.......... .. .. ..,,,;:codxxdlc:;,'.......
'',;clodolokOkxkOkkO00Oko:;;;. ..... .. .,,........'. .. .. .. ..........;:codocclc:,,'......
___ __ __ ___ __ ___ __
| | |__ | / ` / \\ |\\/| |__ |__| /\\ / ` |__/ |__ |__)
|/\\| |___ |___ \\__, \\__/ | | |___ | | /~~\\ \\__, | \\ |___ | \\
__ ___ ___ __ __
/ _` |__ | |__) | | |\\ | | |\\ | / _`
\\__> |___ | | |/\\| | \\| | | \\| \\__>
NOTE OPTION 18 WILL SAVE YOUR PROJECTS BEFORE QUITTING
base prject folder: {}
upcoming project folder: {}
Current Project: {} {}
Working Folder: {}
Notes Folder: {}
Box Name: {}
Terminal Command: {}
Current Season: {}
Year: {}
Main Menu:
";
while loopize {
let _enter_to_clear = get_user_input("press enter to display main menu.");
clear().expect("error clearing screen");
print!("
{}
___ ___ _ ___ ___
| \\/ | (_) | \\/ | _
| . . | __ _ _ _ __ | . . | ___ _ __ _ _(_)
| |\\/| |/ _` | | '_ \\ | |\\/| |/ _ \\ '_ \\| | | |
| | | | (_| | | | | | | | | | __/ | | | |_| |_
\\_| |_/\\__,_|_|_| |_| \\_| |_/\\___|_| |_|\\__,_(_)
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,71 +85,237 @@ 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)
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);
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());}},
"26" => {project_controls::save_projects(&projects, &config_path);
let mut stop = String::new();
println!("stop all boxes?\ny/n");
std::io::stdin().read_line(&mut stop).unwrap();
if stop.contains("y"){
box_controls::stop_all_boxes(&projects);
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.) Gather DNS Records
26.) Bruteforce Subdomains
27.) Do all DNS enumeration
28.) enter external only menu
29.) enter internal only menu
30.) exit menu
\n", banner);
match get_user_input("selection?").as_str(){
"1" => {let thread_option = cli::run_command("show active project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"2" => {let thread_option = cli::run_command("list projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"3" => {let thread_option = cli::run_command("switch project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"4" => {let thread_option = cli::run_command("create_new_project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"5" => {let thread_option = cli::run_command("save projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"6" => {let thread_option = cli::run_command("import project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"7" => {let thread_option = cli::run_command("remove project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"8" => {let thread_option = cli::run_command("show upcoming projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"9" => {let thread_option = cli::run_command("promote project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"10" => {let thread_option = cli::run_command("new terminal".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"11" => {let thread_option = cli::run_command("inline terminal".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"12" => {let thread_option = cli::run_command("cobalt strike".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"13" => {let thread_option = cli::run_command("recreate distrobox".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"14" => {let thread_option = cli::run_command("generate userpass".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"15" => {let thread_option = cli::run_command("initial enum".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"16" => {let thread_option = cli::run_command("build attack notes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"17" => {let thread_option = cli::run_command("host discovery".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"18" => {let thread_option = cli::run_command("port scan".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"19" => {let thread_option = cli::run_command("parse port scan".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"20" => {let thread_option = cli::run_command("stop boxes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"21" => {let thread_option = cli::run_command("password spray".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"22" => {let thread_option = cli::run_command("bloodhound".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"23" => {let thread_option = cli::run_command("parse gather contacts".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"24" => {let thread_option = cli::run_command("prune distroboxes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"25" => {let thread_option = cli::run_command("dns records".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"26" => {let thread_option = cli::run_command("brute force subdomains".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"27" => {let thread_option = cli::run_command("dns enumeration".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"28" => {let threads_option = external_menu(banner, projects, 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 threads_option.is_some(){for thread in threads_option.unwrap(){threads.push(thread)}}},
"29" => {let threads_option = internal_menu(banner, projects, 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 threads_option.is_some(){for thread in threads_option.unwrap(){threads.push(thread)}}},
"30" => loopize = false,
_ => println!("unknown selection, try again!"),
}
}
if threads.len() > 0{
return Some(threads);
}
else{
return None;
}
pub fn external_menu(
banner: &str,
projects: &mut 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 loopize = true;
let mut threads = Vec::new();
while loopize {
let _enter_to_clear = get_user_input("press enter to display external project menu.");
clear().expect("error clearing screen");
print!("
{}
_____ _ _ ___ ___
| ___| | | | | | \\/ | _
| |____ _| |_ ___ _ __ _ __ __ _| | | . . | ___ _ __ _ _(_)
| __\\ \\/ / __/ _ \\ '__| '_ \\ / _` | | | |\\/| |/ _ \\ '_ \\| | | |
| |___> <| || __/ | | | | | (_| | | | | | | __/ | | | |_| |_
\\____/_/\\_\\\\__\\___|_| |_| |_|\\__,_|_| \\_| |_/\\___|_| |_|\\__,_(_)
1 .) Show Active Project
2 .) List Projects
3 .) Switch Active Project
4 .) create new project with Pyro's default layout
5 .) Save Project Information
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
10.) Open A New Terminal in Current Active Project
11.) Open A Terminal In this windows for the current active project
12.) re-create the distrobox for the current active project
13.) generate userpass file from your obsidian notes
14.) run pyro's initail enum script on a nessus csv for the current project
15.) build external attack notes from host notes
16.) Stop All Distroboxes
17.) Password Spray (will print password to spray, and wait the obervation window time)
18.) Parse GatherContacts output file
19.) prune unused distroboxes (free up system storage)
20.) Gather DNS Records
21.) Brute force Subdomains
22.) Do all DNS Enumeration
23.) exit menu
\n", banner);
match get_user_input("selection?").as_str(){
"1" => {let thread_option = cli::run_command("show active project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"2" => {let thread_option = cli::run_command("list projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"3" => {let thread_option = cli::run_command("switch project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"4" => {let thread_option = cli::run_command("create_new_project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"5" => {let thread_option = cli::run_command("save projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"6" => {let thread_option = cli::run_command("import project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"7" => {let thread_option = cli::run_command("remove project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"8" => {let thread_option = cli::run_command("show upcoming projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"9" => {let thread_option = cli::run_command("promote project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"10" => {let thread_option = cli::run_command("new terminal".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"11" => {let thread_option = cli::run_command("inline terminal".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"12" => {let thread_option = cli::run_command("recreate distrobox".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"13" => {let thread_option = cli::run_command("generate userpass".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"14" => {let thread_option = cli::run_command("initial enum".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"15" => {let thread_option = cli::run_command("build attack notes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"26" => {let thread_option = cli::run_command("stop boxes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"17" => {let thread_option = cli::run_command("password spray".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"18" => {let thread_option = cli::run_command("parse gather contacts".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"19" => {let thread_option = cli::run_command("prune distroboxes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"20" => {let thread_option = cli::run_command("dns records".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"21" => {let thread_option = cli::run_command("brute force subdomains".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"22" => {let thread_option = cli::run_command("dns enumeration".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"23" => loopize = false,
_ => println!("unknown selection, try again!"),
}
}
if threads.len() > 0{
return Some(threads);
}
else{
return None;
}
}
pub fn internal_menu(
banner: &str,
projects: &mut 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 loopize = true;
let mut threads = Vec::new();
while loopize {
let _enter_to_clear = get_user_input("press enter to display internal project menu.");
clear().expect("error clearing screen");
print!("
{}
_____ _ _ ___ ___
|_ _| | | | | | \\/ | _
| | _ __ | |_ ___ _ __ _ __ __ _| | | . . | ___ _ __ _ _(_)
| || '_ \\| __/ _ \\ '__| '_ \\ / _` | | | |\\/| |/ _ \\ '_ \\| | | |
_| || | | | || __/ | | | | | (_| | | | | | | __/ | | | |_| |_
\\___/_| |_|\\__\\___|_| |_| |_|\\__,_|_| \\_| |_/\\___|_| |_|\\__,_(_)
1 .) Show Active Project
2 .) List Projects
3 .) Switch Active Project
4 .) create new project with Pyro's default layout
5 .) Save Project Information
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
10.) Open A New Terminal in Current Active Project
11.) Open A Terminal In this windows for the current active project
12.) open cobalt strike in the current project's distrobox
13.) re-create the distrobox for the current active project
14.) generate userpass file from your obsidian notes
15.) print host discvoery command for internal pingsweep
16.) print cobalt strike portscan command to include all in scope ranges
17) parse a cobalt strike portscan CSV
18.) Stop All Distroboxes
19.) Password Spray (will print password to spray, and wait the obervation window time)
20.) open bloodhound in the current project's distrobox
21.) prune unused distroboxes (free up system storage)
22.) exit menu
\n", banner);
match get_user_input("selection?").as_str(){
"1" => {let thread_option = cli::run_command("show active project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"2" => {let thread_option = cli::run_command("list projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"3" => {let thread_option = cli::run_command("switch project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"4" => {let thread_option = cli::run_command("create_new_project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"5" => {let thread_option = cli::run_command("save projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"6" => {let thread_option = cli::run_command("import project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"7" => {let thread_option = cli::run_command("remove project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"8" => {let thread_option = cli::run_command("show upcoming projects".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"9" => {let thread_option = cli::run_command("promote project".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"10" => {let thread_option = cli::run_command("new terminal".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"11" => {let thread_option = cli::run_command("inline terminal".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"12" => {let thread_option = cli::run_command("cobalt strike".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"13" => {let thread_option = cli::run_command("recreate distrobox".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"14" => {let thread_option = cli::run_command("generate userpass".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"15" => {let thread_option = cli::run_command("host discovery".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"16" => {let thread_option = cli::run_command("port scan".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"17" => {let thread_option = cli::run_command("parse port scan".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"18" => {let thread_option = cli::run_command("stop boxes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"19" => {let thread_option = cli::run_command("password spray".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"20" => {let thread_option = cli::run_command("bloodhound".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"21" => {let thread_option = cli::run_command("prune distroboxes".to_owned(), projects, config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.to_owned(), cracking_rig.to_owned(), rockyou.to_owned(), rule.to_owned(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.to_owned()); if thread_option.is_some(){threads.push(thread_option.unwrap());}},
"22" => loopize = false,
_ => println!("unknown selection, try again!"),
}
loopize = false},
_ => println!("uknonwn selection")
}
if loopize == false{
break
}
println!("\n\n\npress enter to return to the menu");
let mut enter = String::new();
std::io::stdin().read_line(&mut enter).unwrap();
}
println!("this will hang until all threads are finished.");
println!("make sure to close all programs opened with this menu, like cobalt strike or bloodhound.");
for thread in threads{
thread.join().unwrap();
}
}
if threads.len() > 0{
return Some(threads);
}
else{
return None;
}
}
}

View File

@@ -0,0 +1,745 @@
use std::fs::{self, OpenOptions};
use std::fs::{read_to_string, create_dir_all};
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use chrono::format::format;
use reqwest::blocking::get;
use walkdir::WalkDir;
use crate::get_user_input;
use crate::Project;
use crate::open_overwrite;
use crate::open_append;
use crate::info_controls;
pub fn parse_normal_nmap_output(project: &Project){
let mut found_file = false;
let mut found_working = false;
let mut file_to_parse = PathBuf::new();
let mut save_path = PathBuf::new();
let files_folder = project.files_folder.clone();
println!("scanning files folder for an nmap file...");
let walkdir_result = WalkDir::new(files_folder);
for entry_res in walkdir_result{
if entry_res.is_ok(){
let entry = entry_res.unwrap();
let entry_name = entry.path().display().to_string();
if entry_name.contains("nmap") || entry_name.contains("port scan") || entry_name.contains("proxychains_output"){
file_to_parse = entry.into_path();
}
else if entry.file_type().is_dir(){
if entry.file_name().to_ascii_lowercase().to_string_lossy().contains("working"){
save_path.push(entry.path());
found_working = true;
}
}
}
}
if !found_working{
save_path.push(&project.files_folder);
}
if file_to_parse.display().to_string().len() > 1{
println!("we found {}", file_to_parse.display());
let res = get_user_input("is the the file you want to parse?");
if res.to_lowercase().contains("y"){
found_file = true;
}
}
if !found_file{
println!("ooof the right file was not found.");
let file_prompt = get_user_input("please enter the full path to the file you want to parse.");
file_to_parse.clear();
file_to_parse.push(file_prompt);
}
let file_read_res = fs::read_to_string(file_to_parse);
if file_read_res.is_err(){
let error = file_read_res.err().unwrap();
println!("ooof error reading the file!");
println!("{}", error);
return;
}
let nmap_string = file_read_res.unwrap();
let sections: Vec<&str> = nmap_string.split("Nmap scan report for").collect();
let mut host_ports = Vec::new();
for section in sections{
let mut host = String::new();
for line in section.split("\n").collect::<Vec<&str>>(){
if line.contains("."){
if !line.contains("latency"){
host = line.trim().to_owned();
}
}
else{
if line.contains("open"){
let port = line.split_whitespace().collect::<Vec<&str>>()[0];
host_ports.push(format!("{}:{}", host, port));
}
}
}
}
println!("done parsing.");
if save_path.display().to_string().len() > 1{
save_path.push("parsed_namp.txt");
println!("default save location is {}", save_path.display());
if get_user_input("is this ok?").contains("n"){
let user_path = get_user_input("ok where would you like to save it instead?");
save_path.clear();
save_path.push(user_path);
}
}
else{
let user_path = get_user_input("where would you like to save the file?");
save_path.clear();
save_path.push(user_path);
}
let save_open_res = fs::OpenOptions::new().create(true).append(true).open(&save_path);
if save_open_res.is_err(){
let error = save_open_res.err().unwrap();
println!("oof error opening the save file!");
println!("{}", error);
if get_user_input("do you want to print the results to the console instead?").to_lowercase().contains("y"){
for host in &host_ports{
println!("{}", host);
}
}
return;
}
let mut host_port_file = save_open_res.unwrap();
save_path.pop();
save_path.push("parsed_nmap.tsv");
let tsv_open_res = fs::OpenOptions::new().create(true).append(true).open(save_path);
if tsv_open_res.is_err(){
let error = tsv_open_res.err().unwrap();
println!("error opening tsv file!");
println!("{}", error);
if get_user_input("do you want to print the results to the console instead?").to_lowercase().contains("y"){
for host in &host_ports{
println!("{}", host);
}
}
return;
}
let mut tsv_file = tsv_open_res.unwrap();
for host in &host_ports{
let outline = format!("{}\n", host);
let split_data: Vec<&str> = host.split(":").collect();
let ip = split_data[0];
let port_split: Vec<&str> = split_data[1].split("/").collect();
let port = port_split[0];
let proto = port_split[1];
let tsv_outline = format!("{}\t{}\t\t{}\n", ip, port, proto);
let host_port_write_res = write!(host_port_file, "{}", outline);
let tsv_write_res = write!(tsv_file, "{}", tsv_outline);
if host_port_write_res.is_err(){
println!("error writing data to file...");
}
if tsv_write_res.is_err(){
println!("error writing data to the tsv file...");
}
}
}
pub fn build_cs_portscan_cmd(project: &Project){
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::<Vec<&str>>()[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 portscan_cmd = "portscan !!! 1-1024,1433,2222,3306,3389,5000-6000,8000,8080,8443 icmp 512";
let mut _range_command = String::new();
let combined_ranges = ranges.join(",");
let final_command = portscan_cmd.replace("!!!", &combined_ranges);
println!("{}", final_command);
}
pub 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::<Vec<&str>>()[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 = "";
_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 mut _range_command = String::new();
if need_shell{
_range_command = format!("{}{}","shell ", _discovery_command.replace("!!!", &network_string));
need_shell = false;
}
else{
_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);
}
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.");
}
pub fn run_nmap_portscan(project: &Project){
let files_folder = project.files_folder.clone();
let notes_folder = project.notes_folder.clone();
let mut ports_to_scan = vec![String::from("80"), String::from("443"),
String::from("161"),
String::from("22"),
String::from("21"),
String::from("23"),
String::from("8080"),
String::from("8443"),
String::from("4433"),
String::from("135"),
String::from("445"),
String::from("3389"),
String::from("5985"),
String::from("1433"),
String::from("3306"),
String::from("2222"),];
let mut save_path = files_folder.clone();
let mut general_notes = notes_folder.clone();
general_notes.push("general.md");
println!("building targets from scope in general notes...");
let targets_res = info_controls::get_scope_entries(project);
if targets_res.is_none(){
return;
}
let mut targets = targets_res.unwrap();
println!("Got targets from scope!");
for target in &targets{
println!("{}", target);
}
if get_user_input("does this list look ok?").to_lowercase().contains("n"){
let mut modified_targets = targets.clone();
let mut targets_to_remove = Vec::new();
let mut targets_ready = false;
while !targets_ready{
println!("current target list:");
for target in &modified_targets{
if &targets_to_remove.contains(target) == &false{
println!("{}", target);
}
}
let response = get_user_input("\nc to continue as is\na to add a target to the list\nr to remove a target from the list\nf to start fresh with a blank list of targets");
match response.as_str(){
"c" => targets_ready = true,
"a" => {let new_target = get_user_input("target to add?"); let _ = &mut modified_targets.push(new_target);},
"r" => {let _ = targets_to_remove.push(get_user_input("target to remove?"));},
"f" => {let _ = &mut modified_targets.clear();}
_ => println!("unknown selection"),
}
}
for target in &targets{
println!("{}", target);
}
println!("\nwill be replace with\n");
for target in &modified_targets{
println!("{}", target);
}
if get_user_input("continue?").to_lowercase().contains("n"){
println!("ok exiting this function, feel free to try again...");
return;
}
targets = modified_targets;
}
println!("the standard ports I scan are:");
for port in &ports_to_scan{
println!("{}", port);
}
if get_user_input("is this ok?").to_lowercase().contains("n"){
let mut ports_ready = false;
ports_to_scan.clear();
while !ports_ready{
let response = get_user_input("enter a port to scan in the nmap format. For example 80-100 or 80,443 Enter END in all caps when you're done.");
match response.as_str(){
"END" => ports_ready = true,
_ => ports_to_scan.push(response),
}
}
}
let proxy = get_user_input("will you be using proxychains for this scan?").to_lowercase();
println!("sweet we have what we need!");
println!("building portscan command...");
let port_string = ports_to_scan.join(",");
let hosts_string = targets.join(" ");
let mut scan_results = String::new();
if proxy.contains("y"){
println!("running command, this may take a bit of time...");
let command_res = Command::new("distrobox")
.arg("enter")
.arg("--root")
.arg(project.boxname.to_owned())
.arg("--")
.arg("proxychains")
.arg("namp")
.arg("-sT")
.arg("-p")
.arg(port_string)
.arg(hosts_string)
.output();
if command_res.is_err(){
let error = command_res.err().unwrap();
println!("error running portscan command!");
println!("{}", error);
return;
}
let output = command_res.unwrap().stdout;
scan_results = String::from_utf8_lossy(&output).into_owned();
}
else{
let command_res = Command::new("distrobox")
.arg("enter")
.arg("--root")
.arg(project.boxname.to_owned())
.arg("--")
.arg("proxychains")
.arg("namp")
.arg("-sT")
.arg("-p")
.arg(port_string)
.arg(hosts_string)
.output();
if command_res.is_err(){
let error = command_res.err().unwrap();
println!("error running portscan command!");
println!("{}", error);
return;
}
let output = command_res.unwrap().stdout;
scan_results = String::from_utf8_lossy(&output).into_owned();
}
save_path.push("working/nmap_output.txt");
println!("going to save to {}", save_path.display());
if get_user_input("is that ok?").to_lowercase().contains("n"){
save_path.clear();
save_path.push(get_user_input("where do you want to save it then? (full path)"));
}
let save_file_res = OpenOptions::new().create(true).append(true).open(save_path);
if save_file_res.is_err(){
let error = save_file_res.err().unwrap();
println!("error opening save file!");
println!("{}", error);
if get_user_input("output results to console?").to_lowercase().contains("y"){
println!("{}", &scan_results);
}
return;
}
let mut save_file = save_file_res.unwrap();
let write_res = write!(save_file, "{}", scan_results);
if write_res.is_err(){
let error = write_res.err().unwrap();
println!("error writing results to file!");
println!("{}", error);
if get_user_input("print results to console instead?").to_lowercase().contains("y"){
println!("{}", scan_results);
}
}
}
pub fn build_nmap_command(project: &Project){
fn get_targets() -> Vec<String>{
let mut targets = Vec::new();
println!("please enter the ranges/ips to scan one per line, and enter END all caps when done.");
loop {
let response = get_user_input("ip or range to add?");
if response == "END".to_owned(){
break;
}
else{
targets.push(response);
}
}
return targets;
}
let targets_res = info_controls::get_scope_entries(project);
let mut targets = Vec::new();
let mut ports_to_scan = vec![String::from("80"), String::from("443"),
String::from("161"),
String::from("22"),
String::from("21"),
String::from("23"),
String::from("8080"),
String::from("8443"),
String::from("4433"),
String::from("135"),
String::from("445"),
String::from("3389"),
String::from("5985"),
String::from("1433"),
String::from("3306"),
String::from("2222"),];
let mut save_path = project.files_folder.clone();
if targets_res.is_none(){
println!("couldn't get target list from your notes!");
targets = get_targets();
}
else{
println!("got targets from the cope in notes!");
for target in targets_res.unwrap(){
targets.push(target);
}
}
for target in &targets{
println!("{}", target);
}
if get_user_input("is this ok?").to_lowercase().contains("n"){
println!("oooof ok, we'll have you recreate it manually.");
targets = get_targets();
}
println!("These are the ports we're going to scan.");
for port in &ports_to_scan{
println!("{}", port);
}
if get_user_input("is this ok?").to_lowercase().contains("n"){
println!("oof ok, rebuild it manually.");
println!("please enter the ports you want to scan, one per line, enter END in all caps when you're finished.");
ports_to_scan.clear();
loop{
let port = get_user_input("port to add?");
if port.contains("END"){
break;
}
else{
ports_to_scan.push(port);
}
}
}
println!("we are going to save the output to {}/working/nmap_output.txt", save_path.display());
if get_user_input("is this ok").to_lowercase().contains("n"){
println!("oof ok.");
save_path.clear();
save_path.push(get_user_input("full path to where you want to save it then?"));
}
else{
save_path.push("working/nmap_output.txt");
}
let ports_string = ports_to_scan.join(",");
let targets_string = targets.join(" ");
println!("\nYour portscan command is:");
if get_user_input("will you be using proxychains for this scan?").to_lowercase().contains("y"){
println!("\n\nproxychains nmap -sT -p {} {} -Pn | tee {}", ports_string, targets_string, save_path.display());
}
else{
println!("nmap -p {} {} -Pn | tee {}", ports_string, targets_string, save_path.display());
}
}

View File

@@ -9,11 +9,11 @@ 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;
pub fn switch_project(projects: &mut Vec<Project>){
pub fn
switch_project(projects: &mut Vec<Project>){
for project in projects.clone(){
if project.active == false{
println!("{} {}|{}", project.id, project.customer, project.project_name);
@@ -34,7 +34,7 @@ pub fn switch_project(projects: &mut Vec<Project>){
project.active = false;
}
else{
println!("error unknown project id")
println!("error unknown project id");
}
}
}
@@ -282,18 +282,27 @@ pub fn remove_project(projects: &mut Vec<Project>, config_path: &PathBuf){
}
else{
println!("we need user in put here dummy!!");
println!("no project selected! returning...");
}
}
else{
println!("we need input here dummy!");
println!("no project selected! returning...");
}
}
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");
let mut bkup_config_path = mut_config_path.clone();
bkup_config_path.pop();
bkup_config_path.push("projects.conf.bkup");
let bkup_result = fs::copy(&mut_config_path, &bkup_config_path);
if bkup_result.is_err(){
let error = bkup_result.err().unwrap();
println!("error backing up the projects.conf file!");
println!("error: {}", error);
}
let mut projects = Vec::new();
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();
@@ -327,7 +336,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};
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
if show{
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
}
projects.push(new_project);
}
}
@@ -445,3 +456,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!("++++++++++++++++++++")
}

View File

@@ -322,6 +322,91 @@ powerup.ps1/sharpup.exe notes.
}
fn vishing(project: &Project){
let mut notes_path = project.notes_folder.clone();
let mknote_folder_res = fs::create_dir_all(&notes_path);
if mknote_folder_res.is_err(){
let error = mknote_folder_res.err().unwrap();
println!("Error creating notes folder!");
println!("{}", error);
return;
}
notes_path.push("general.md");
let general_notes_res = create_note_file(&notes_path);
if general_notes_res.is_some(){
let mut general_notes = general_notes_res.unwrap();
write!(general_notes, "# Scope\n\n").unwrap();
write!(general_notes, "
Introductions
have they been vished before?
if yes ask what the purpose of that vishing was, gain a foothold, or other?
ask the purpose of this test, just see if we can get creds or testing a vetting process, or any specific goals for the engagement.
four main aspects
1. verbal confirmation and verification of information
2. run commands on the system they're on
3. go to a specific website
4. join a screen sharing session with us
pretexts:
default is third party it.
they have 2 dudes for helpdesk so this may not be the best pretext. Try to impersonate a specific helpdesk user. impersonate William sounds like our plan.
Vector -
ask for any questions, comments, or concerns.
").unwrap();
}
notes_path.pop();
notes_path.push("findings.md");
let findings_res = create_note_file(&notes_path);
if findings_res.is_some(){
let mut findings_file = findings_res.unwrap();
write!(findings_file, "# Findings to write up\n\n\n# Delivery Notes\n").unwrap();
}
notes_path.pop();
notes_path.push("pretext.md");
let pretext_res = create_note_file(&notes_path);
if pretext_res.is_some(){
let mut pretext_file = pretext_res.unwrap();
write!(pretext_file, "\n\n\n#Script").unwrap();
write!(pretext_file, "
Hello I'm [name] from [Find Local IT Shop]. We were brought in to help your normal IT guys with some of the menial tasks so they can focus on more import improvement projects. As part of this we're making sure our inventory management system is checking in correctly and up to date, this should only take a minute or two. Is now bad time to talk?
Great I just need to confirm that my inventory report here is accurate.
Are you currently running Windows 11?
can you confirm your user name is [metadata username]?
Your primary browser is firfox?
Oh thats strange it seems our report is wrong then... I don't think our program on your computer is checking in correctly... uhhh I want to make sure you're getting all the windows updates we need to be compliant.
Hold the windows key on your keyboard and press the r button. in the box that opens up type cmd.exe and press enter.
This will open a scary black box, but don't worry I'll walk you through what we need here, it'll be pretty easy.
In that box type systemifo all one word and press enter.
Scroll up through that output and find the section that talks about hotfixes, how many are installed?
That doesn't seem like the right number to me, can you read me the last 3 that are listed there?
yeah you're definitely not getting all of the windows updates. This is going to take a bit of troubleshooting to figure out. Would you mind hopping in a Zoom call with me and sharing your screen so I can check a few things? This should only take a couple of minutes.
(open up the services manager and scroll through it, check some program files folders, and run a few commands in cmd to act like I'm troubleshooting.)
Hmmm everything looks ok on this end. I'm going to do some troubleshooting on the server side and see if we can get to the bottom of this. I don't think we'll need anything else from you to fix this, but if that changes I'll let you know. Thank you for your time.
").unwrap();
}
notes_path.pop();
notes_path.push("calls.md");
create_note_file(&notes_path);
}
pub fn start_pentest(config_path: &PathBuf, projects: &mut Vec<Project>, id: i32, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, boxtemplate: &String, password_spray_file: &PathBuf) {
let mut project_files = upcoming_files.clone();
let mut project_notes = upcoming_notes.clone();
@@ -343,12 +428,15 @@ pub fn start_pentest(config_path: &PathBuf, projects: &mut Vec<Project>, id: i32
create_project_folder(&mut working, "delivery");
let project_boxname = format!("{}_{}", boxtemplate, customer_name);
let new_prject = Project{customer:customer_name.clone(), project_name:project_name.clone(), notes_folder:project_notes.clone(), files_folder:project_files.clone(),active:false, boxname:project_boxname.clone(),stage:"upcoming".to_owned(), id};
if project_name.contains("external"){
if project_name.to_lowercase().contains("external"){
external(password_spray_file, &new_prject);
}
else if project_name.contains("internal"){
else if project_name.to_lowercase().contains("internal"){
internal(password_spray_file, &new_prject);
}
else if project_name.to_lowercase().contains("vishing"){
vishing(&new_prject);
}
projects.push(new_prject);
project_controls::save_projects(projects, config_path);
println!("project created and saved to the projects config file!");

View File

@@ -0,0 +1,41 @@
use std::{env::set_current_dir, path::PathBuf};
use std::process::Command;
use walkdir::WalkDir;
pub fn update_git_tools(tools_dir: &PathBuf){
let mut folders = Vec::new();
for entry in WalkDir::new(tools_dir).max_depth(2){
let entry = entry.unwrap();
let path = entry.path();
if path.is_dir(){
folders.push(path.to_owned());
}
}
for folder in folders{
let cd_res = set_current_dir(&folder);
if cd_res.is_err(){
let error = cd_res.err().unwrap();
println!("error changing directory!");
println!("{}", error);
}
else{
let _cd = cd_res.unwrap();
let git_command_res = Command::new("git")
.arg("pull")
.arg("--autostash")
.status();
if git_command_res.is_err(){
let error = git_command_res.err().unwrap();
println!("error running git pull command!");
println!("{}", error);
}
else{
let git_command = git_command_res.unwrap();
if git_command.success(){
println!("successfully updated {}", folder.display());
}
}
}
}
}

View File

@@ -0,0 +1,32 @@
use std::path::PathBuf;
use walkdir::WalkDir;
use crate::{get_user_input, Project};
pub fn sharp_persist_command(tools_dir: &PathBuf){
let filename = "SharPersist.exe";
let mut binary_path = String::new();
for entry in WalkDir::new(tools_dir){
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() && path.file_name().unwrap() == filename{
binary_path = path.to_str().unwrap().to_string();
}
}
if get_user_input("will you be running this is cobalt strike?").to_lowercase().contains("y"){
let beacon_path = get_user_input("excellent! Please enter the path to your beacon file on the victim machine.");
println!("how will you run it?");
println!("1.) execute-assembly\n2.) inline-execute-assembly\n3.) from disk");
match get_user_input("selection?").as_str(){
"1" => println!("execute-assembly {} -t schtask -c \"{}\" -n FRPersist -m add -o hourly", binary_path, beacon_path),
"2" => println!("inlineExecute-Assembly --dotnetassembly {} --assemblyargs -t schtask -c \"{}\" -n FRPersist -m add -o hourly --etw --amsi", binary_path, beacon_path),
"3" => println!("upload {}\n\nrun .\\SharPersist.exe -t schtask -c \"{}\" -n FRPersist -m add -o hourly", binary_path, beacon_path),
_ => println!("unknown selection")
}
return;
}
let file_to_run = get_user_input("path to the file you want to run for persistence?");
println!("ok then, upload the following file to the machine");
println!("{}", binary_path);
println!("C:\\path\\to\\your\\sharpersist.exe -t schtask -c \"{}\" -n FRPersist -m add -o hourly", file_to_run);
return;
}