Refactored the code to be split

into different modules
instead of one giant .rs file
this should make it more organized
This commit is contained in:
pyro57000
2024-12-18 11:56:20 -06:00
parent 6d7c1d2e97
commit c58f455809
378 changed files with 5106 additions and 808 deletions

View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@@ -192,7 +192,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]] [[package]]
name = "pentest_tool" name = "pentest_tool"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"clearscreen", "clearscreen",
"directories", "directories",

View File

@@ -1,7 +1,6 @@
[package] [package]
name = "pentest_tool" name = "pentest_tool"
version = "0.1.0" version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -0,0 +1,65 @@
use std::process;
use crate::Project;
pub fn stop_all_boxes(projects: &Vec<Project>){
let mut problem_childs: Vec<Project> = Vec::new();
let mut all_done = true;
for project in projects{
let stopped = process::Command::new("distrobox")
.arg("stop")
.arg("--root")
.arg(&project.boxname)
.status().expect("error spawing distrobox");
if stopped.success(){
println!("{} sucessfully stopped!", &project.boxname);
}
else{
println!("{} not stopped!!!!!!!", &project.boxname);
all_done = false;
problem_childs.push(project.clone());
}
}
if all_done{
println!("All boxes stopped GO US YAAAAA WE DID IT");
}
else{
println!("OOOOOOOF some boxes didn't stop yo, that's cringe");
println!("here are the problem childs, you may need to stop them manually");
for child in problem_childs{
println!("{}",child.boxname);
}
}
}
pub fn project_standalone_terminal(project: Project, mut terminal: String){
terminal = terminal.trim_end().to_owned();
let mut profile = false;
if terminal.contains("profile"){
profile = true;
}
let terminal_vec:Vec<&str> = terminal.split(" ").collect();
let mut terminal_start = process::Command::new(terminal_vec[0]);
let mut first = true;
for arg in terminal_vec{
if first == true{
first = false;
}
else{
terminal_start.arg(arg);
}
}
if profile == false {
terminal_start.arg(&project.boxname);
}
print!("{}", terminal);
let start = terminal_start.spawn();
match start{
Ok(_child) => println!("New Terminal Started, you can retun to the menu now!"),
Err(_error) => println!("error starting new terminanl, something may be wrong with the terminal part of your config!\nCheck ~/.conf/pyro_pentest_tool/conf for errors")
}
//process::Command::new("konsole").arg("--profile").arg("attack").arg(project.boxname).spawn().expect("error opeing konsole");
}
pub fn project_inline_terminal(project: Project){
process::Command::new("distrobox").arg("enter").arg("--root").arg(project.boxname).arg("--").arg("script").arg("-a").arg("-B").arg("/pentest/working/terminal.log").status().expect("error opeing konsole");
}

View File

@@ -0,0 +1,146 @@
use std::fs;
use std::fs::read_to_string;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use crate::Project;
pub fn run_initial_enum(project: &Project){
let mut csv = String::new();
println!("path to the csv?");
std::io::stdin().read_line(&mut csv).unwrap();
let status = process::Command::new("initial_recon").arg(&csv).arg(&project.customer).arg(&project.project_name).status().expect("error running initial_recon program");
if status.success(){
println!("execllent! hosts should be imported to {}/host_notes.md", &project.notes_folder.display());
}
else{
println!("ooof something went wrong, host notes may not have saved correctly!");
}
}
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 generate_userpass(project: &Project){
let mut outlines = Vec::new();
let mut notes_file = project.notes_folder.clone();
notes_file.push("l00t/creds.md");
let loot_string = fs::read_to_string(notes_file).expect("error reading creds note");
let clear_text = loot_string.split("# hashed").collect::<Vec<&str>>()[0];
let clear_text_table = clear_text.split("| ----------------------------------- | ------------- | ----------------------------- |").collect::<Vec<&str>>()[1];
let table_vec: Vec<&str> = clear_text_table.split("\n").collect();
for line in table_vec{
if line.len() > 1{
let split_line: Vec<&str> = line.split("|").collect();
let user = split_line[2].trim_end().trim_start();
let password = split_line[3].trim_end().trim_start();
let outline = format!("{}:{}\n", user, password);
outlines.push(outline);
}
}
let mut out_file_path = project.files_folder.clone();
out_file_path.push("working/userpass_fromnotes.txt");
let mut out_file = fs::File::create(out_file_path).expect("error creating userpass file");
for line in outlines{
out_file.write_all(line.as_bytes()).expect("error writing to userpass file");
}
}
pub fn open_in_dolphin(folder: &str, project: Project){
let mut to_open = PathBuf::new();
match folder{
"notes" => to_open.push(project.notes_folder),
"files" => to_open.push(project.files_folder),
_ => println!("unknown entry... this should literally be impossible... how.... how tf did you.... what")
}
process::Command::new("dolphin")
.arg(to_open)
.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]);
}
}
println!("Findings");
for line in finding_lines{
if line.contains("# "){
println!("{}", line);
}
else if line.contains("- "){
println!("{}", line)
}
}
}

130
pentest_tool/src/install.rs Normal file
View File

@@ -0,0 +1,130 @@
use std::collections::HashMap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process;
pub fn install(config_path: &PathBuf){
let mut _terminal_commands = HashMap::from([
("konsole", "konsole -e !!!"),
("gnome", "gnome-terminal -- bash !!!"),
("xfce", "xfce4-terminal --execute '!!!'"),
("alacritty", "alacritty -e !!!"),
]);
let mut config_folder_path: PathBuf = config_path.clone();
config_folder_path.pop();
let mut projects_conf_path = config_folder_path.clone();
let del_on_fail = config_folder_path.clone();
projects_conf_path.push("projects.conf");
fs::create_dir_all(&config_folder_path).expect("error creating config dir");
let mut config_file = fs::File::create(config_path).expect("error creating file");
let mut projects_conf_file = fs::File::create(projects_conf_path).expect("error creating projects config file");
projects_conf_file.write_all(b"customer:name:notes:files:active:box_name\n").expect("error writing default project info");
let mut terminal_response = String::new();
let mut notes_response = String::new();
let mut files_response = String::new();
let mut tools_response = String::new();
let mut template_name = String::new();
let mut have_template = String::new();
println!("terminal you use? (example: konsole, xfce, gnome, etc)");
std::io::stdin().read_line(&mut terminal_response).unwrap();
let mut _terminal_command = String::new();
if terminal_response.contains("konsole"){
let mut response_buffer = String::new();
println!("do you already have a custom profile setup?");
println!("this is pretty specific to pyro's setup, I do some special sauce for my konsole stuff");
std::io::stdin().read_line(&mut response_buffer).unwrap();
if response_buffer.to_lowercase().contains("y"){
let mut profile = String::new();
println!("konsole profile name?");
std::io::stdin().read_line(&mut profile).unwrap();
_terminal_command = format!("konsole --profile {}", profile);
}
}
else{
_terminal_command = _terminal_commands[terminal_response.trim_end()].to_owned();
}
println!("path to save project notes?");
std::io::stdin().read_line(&mut notes_response).unwrap();
println!("path to save project files?");
std::io::stdin().read_line(&mut files_response).unwrap();
println!("path to folder with your custom tools?");
std::io::stdin().read_line(&mut tools_response).unwrap();
print!("
This tool is mainly to handle distrobox creation and usage.
It's expecting you to have a distrobox that you will use as a template.
Do you have a distrobox set up to function as your template for all new projects?
");
std::io::stdin().read_line(&mut have_template).unwrap();
if have_template.contains("n"){
println!("please set up a distrobox with root as a template and re-run this tool");
println!("example distrobox setup command:");
println!("distrobox create --root --image archlinux --name template");
println!("then enter that distrobox and install all the tools you want and do what ever setup you need");
println!("and re-run this tool.");
process::Command::new("rm").arg(del_on_fail).spawn().expect("ERROR deleting config folder, please manually clean up");
std::process::exit(1);
}
let _list = process::Command::new("distrobox").arg("list").arg("--root").status();
println!("distrobox template name?");
std::io::stdin().read_line(&mut template_name).unwrap();
let config_string = format!("Project_files:{}\nProject_notes:{}\ntools_folder:{}\nterminal:{}", files_response.trim_end(), notes_response.trim_end(), tools_response.trim_end(), _terminal_command.trim_end());
config_file.write_all(config_string.as_bytes()).expect("error writing to config file");
let default_projectline = format!("default:default:{}:{}:yes:{}", &notes_response.trim_end(), &files_response.trim_end(), &template_name.trim_end());
projects_conf_file.write_all(default_projectline.as_bytes()).expect("error writing default project line");
println!("config file generated and saved to {}\n", config_path.display());
println!("please rerun the program");
let config_path = &config_folder_path.clone();
let mut install_path = config_path.clone();
let mut password_spray_template_path = install_path.clone();
install_path.push("new_projects.conf");
password_spray_template_path.push("passwordspray.md");
let password_spray_template_path = install_path.clone();
let mut conf_file = fs::File::create(install_path).expect("error creating config file");
let mut project_folder_path = String::new();
let mut porject_note_path = String::new();
println!("path to the project folders directory?");
std::io::stdin().read_line(&mut project_folder_path).expect("error reading project folder from stdin");
println!("path to the project notes directory");
std::io::stdin().read_line(&mut porject_note_path).expect("error reading project note folder form stdin");
write!(conf_file, "project_folder_path:{}
project_notes_path:{}
", project_folder_path.trim_end(), porject_note_path.trim_end()).expect("error writing config file");
let mut passpray_file = fs::File::create(password_spray_template_path).expect("error creating passwordspray file");
write!(passpray_file, "
- [ ] useraspass
- [ ] Seasonyear!
- [ ] Service123!
- [ ] admin
- [ ] Admin
- [ ] Admin123!
- [ ] admin123
- [ ] admin1
- [ ] 1234567
- [ ] Seasonyear
- [ ] seasonyear!
- [ ] seasonyear
- [ ] COMPANYYEAR!
- [ ] COMPANYYEAR
- [ ] November2024!
- [ ] September2024!
- [ ] October2024!
- [ ] COMPANYfoundingyear!
- [ ] COMPANYfoundingyear
- [ ] COMPANYstreetnumber!
- [ ] COMPANYstreetnumber
- [ ] Password
- [ ] P@ssw0rd
- [ ] Password1!
- [ ] Password123!
- [ ] Passwordyear!
- [ ] P@55w0rd
- [ ] Service
- [ ] Service!
- [ ] Serviceyear!").expect("error writing password spray template");
std::process::exit(0);
}

View File

@@ -1,809 +1,24 @@
use std::collections::HashMap;
use std::env;
use std::fs;
use std::fs::read_to_string;
use std::io::stdin;
use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::process;
use std::str::FromStr;
use std::thread;
use std::time::Duration;
use clearscreen::clear;
use directories::UserDirs; use directories::UserDirs;
use clearscreen; use std::fs;
#[derive(Clone)] #[derive(Clone)]
struct Project{ pub struct Project{
customer: String, pub customer: String,
project_name: String, pub project_name: String,
notes_folder: PathBuf, pub notes_folder: PathBuf,
files_folder: PathBuf, pub files_folder: PathBuf,
active: bool, pub active: bool,
boxname: String, pub boxname: String,
id: i32, pub id: i32,
} }
mod install;
mod menu;
fn install(config_path: &PathBuf){ mod project_controls;
let mut _terminal_commands = HashMap::from([ mod box_controls;
("konsole", "konsole -e !!!"), mod info_controls;
("gnome", "gnome-terminal -- bash !!!"), mod start_pentest;
("xfce", "xfce4-terminal --execute '!!!'"),
("alacritty", "alacritty -e !!!"),
]);
let mut config_folder_path: PathBuf = config_path.clone();
config_folder_path.pop();
let mut projects_conf_path = config_folder_path.clone();
let del_on_fail = config_folder_path.clone();
projects_conf_path.push("projects.conf");
fs::create_dir_all(config_folder_path).expect("error creating config dir");
let mut config_file = fs::File::create(config_path).expect("error creating file");
let mut projects_conf_file = fs::File::create(projects_conf_path).expect("error creating projects config file");
projects_conf_file.write_all(b"customer:name:notes:files:active:box_name\n").expect("error writing default project info");
let mut terminal_response = String::new();
let mut notes_response = String::new();
let mut files_response = String::new();
let mut tools_response = String::new();
let mut template_name = String::new();
let mut have_template = String::new();
println!("terminal you use? (example: konsole, xfce, gnome, etc)");
std::io::stdin().read_line(&mut terminal_response).unwrap();
let mut _terminal_command = String::new();
if terminal_response.contains("konsole"){
let mut response_buffer = String::new();
println!("do you already have a custom profile setup?");
println!("this is pretty specific to pyro's setup, I do some special sauce for my konsole stuff");
std::io::stdin().read_line(&mut response_buffer).unwrap();
if response_buffer.to_lowercase().contains("y"){
let mut profile = String::new();
println!("konsole profile name?");
std::io::stdin().read_line(&mut profile).unwrap();
_terminal_command = format!("konsole --profile {}", profile);
}
}
else{
_terminal_command = _terminal_commands[terminal_response.trim_end()].to_owned();
}
println!("path to save project notes?");
std::io::stdin().read_line(&mut notes_response).unwrap();
println!("path to save project files?");
std::io::stdin().read_line(&mut files_response).unwrap();
println!("path to folder with your custom tools?");
std::io::stdin().read_line(&mut tools_response).unwrap();
print!("
This tool is mainly to handle distrobox creation and usage.
It's expecting you to have a distrobox that you will use as a template.
Do you have a distrobox set up to function as your template for all new projects?
");
std::io::stdin().read_line(&mut have_template).unwrap();
if have_template.contains("n"){
println!("please set up a distrobox with root as a template and re-run this tool");
println!("example distrobox setup command:");
println!("distrobox create --root --image archlinux --name template");
println!("then enter that distrobox and install all the tools you want and do what ever setup you need");
println!("and re-run this tool.");
process::Command::new("rm").arg(del_on_fail).spawn().expect("ERROR deleting config folder, please manually clean up");
std::process::exit(1);
}
let _list = process::Command::new("distrobox").arg("list").arg("--root").status();
println!("distrobox template name?");
std::io::stdin().read_line(&mut template_name).unwrap();
let config_string = format!("Project_files:{}\nProject_notes:{}\ntools_folder:{}\nterminal:{}", files_response.trim_end(), notes_response.trim_end(), tools_response.trim_end(), _terminal_command.trim_end());
config_file.write_all(config_string.as_bytes()).expect("error writing to config file");
let default_projectline = format!("default:default:{}:{}:yes:{}", &notes_response.trim_end(), &files_response.trim_end(), &template_name.trim_end());
projects_conf_file.write_all(default_projectline.as_bytes()).expect("error writing default project line");
println!("config file generated and saved to {}\n", config_path.display());
println!("please make sure to install distrobox:\nhttps://github.com/89luca89/distrobox\n\nthis will require either docker or podman as well.\n\n");
println!("please rerun the program");
std::process::exit(1);
}
fn get_projects(config_path: &PathBuf) -> Vec<Project>{
let mut mut_config_path = config_path.clone();
mut_config_path.pop();
mut_config_path.push("projects.conf");
let mut projects = Vec::new();
let projects_string = fs::read_to_string(mut_config_path).expect("error reading projects file");
let project_lines:Vec<&str> = projects_string.split("\n").collect();
let mut first = 0;
let mut already_active = false;
for line in project_lines{
first = first + 1;
if first != 1{
if line.len() > 1{
let settings: Vec<&str> = line.split(":").collect();
let customer = settings[0].to_owned();
let project = settings[1].to_owned();
let notes_string = settings[2].to_owned();
let folder_string = settings[3].to_owned();
let notes_folder = PathBuf::from_str(&notes_string.trim_end()).expect("error reading notes string");
let project_folder = PathBuf::from_str(&folder_string.trim_end()).expect("error reading folding sering");
let mut active = false;
let boxname = settings[5].to_owned();
if settings[4] == "yes"{
if already_active == false{
env::set_var("CURRENT_PROJECT_BOX", boxname.clone());
already_active = true;
active = true;
}
}
let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname};
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
projects.push(new_project);
}
}
}
return projects
}
fn switch_project(projects: &mut Vec<Project>){
for project in projects.clone(){
if project.active == false{
println!("{} {}|{}", project.id, project.customer, project.project_name);
}
}
println!("\nnew project selection?\n");
let mut response = String::new();
std::io::stdin().read_line(&mut response).unwrap();
if response.len() > 1{
let new_id:i32 = response.trim_end().parse().expect("error converting to i32");
for project in projects{
if project.id == new_id{
project.active = true;
println!("project found switching to {} {}", project.customer, project.project_name);
env::set_var("CURRENT_PROJECT_BOX", project.boxname.clone());
}
else if project.id != new_id{
project.active = false;
}
else{
println!("error unknown project id")
}
}
}
else{
println!("error we need user input here dummy!");
}
}
fn save_projects(projects: &Vec<Project>, config_path: &PathBuf){
let mut save_file_path = config_path.clone();
let mut active_set = false;
save_file_path.pop();
save_file_path.push("projects.conf");
let mut save_file = fs::File::create(save_file_path).expect("error creating save_file");
save_file.write_all(b"customer:name:notes:files:active:time:box_name\n").expect("error writing first line to file");
for project in projects{
let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()};
let mut _outline = String::new();
if project.active{
if active_set == false{
_outline = format!("{}yes:{}\n", default, project.boxname);
active_set = true;
}
}
else{
_outline = format!("{}no:{}\n", default, project.boxname);
}
save_file.write_all(_outline.as_bytes()).expect("error writing outline");
}
}
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
}
fn start_pentest(){
let mut customer_name = String::new();
let mut project_name = String::new();
let mut scope = String::new();
println!("Customer name?");
std::io::stdin().read_line(&mut customer_name).unwrap();
println!("Project name?");
std::io::stdin().read_line(&mut project_name).unwrap();
println!("path to scope?");
std::io::stdin().read_line(&mut scope).unwrap();
scope.pop();
project_name.pop();
customer_name.pop();
let status = process::Command::new("start_pentest")
.arg(scope)
.arg(customer_name)
.arg(project_name)
.status().expect("error spawning start_pentest");
if status.success() == false{
println!("error please cleanup and re-run manually");
}
}
fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, config_path: &PathBuf, new_id: i32){
let mut new_project_dir = project_dir.clone();
let mut new_note_dir = notes_dir.clone();
let mut existing_folders = String::new();
let mut customer_name = String::new();
let mut project_name = String::new();
println!("do you have an existing notes and folder structure to copy over?\ny/n");
std::io::stdin().read_line(&mut existing_folders).unwrap();
let mut customer_name = customer_name.trim_end().to_owned();
let mut project_name = project_name.trim_end().to_owned();
if existing_folders.contains("y") || existing_folders.contains("Y"){
println!("NOTE THIS WILL OVERWRITE CUSTOMER NAME AND PROJECT NAME WITH THE 2nd TO LAST AND LAST FOLDER NAMES IN THE PATH YOU'RE COPYING RESPECTIVELY");
let mut files_to_copy = String::new();
let mut notes_to_copy = String::new();
println!("path to project folder folder to copy:");
std::io::stdin().read_line(&mut files_to_copy).unwrap();
println!("path to notes folder to copy:");
std::io::stdin().read_line(&mut notes_to_copy).unwrap();
//to get rid of the new line chars
files_to_copy.pop();
notes_to_copy.pop();
println!("files to copy: {}", files_to_copy);
println!("notes to copy: {}", notes_to_copy);
println!("files destination: {}", new_project_dir.display());
println!("notes destination: {}", new_note_dir.display());
let folder_move_success = process::Command::new("mv")
.arg("-i")
.arg(&files_to_copy)
.arg(new_project_dir.display().to_string())
.status().expect("unable to call the system mv command");
let note_move_success = process::Command::new("mv")
.arg("-i")
.arg(&notes_to_copy)
.arg(new_note_dir.display().to_string())
.status().expect("unable to call the system mv command");
if folder_move_success.success(){
println!("we copied the project folder correctly!!");
}
else{
println!("failed to copy the project folder, try to move it manually!");
}
if note_move_success.success(){
println!("we copied the notes folder correctly!!");
}
else{
println!("failed to copy the notes folder, try to move it manually!");
}
// this lovely set of code takes the folder you gave to copy and tries to find the customername and project name based on directory names
// this solves a case where the entered customer name or project name does not match the files copied
let copied_files = PathBuf::from(&files_to_copy);
customer_name = copied_files.file_name().unwrap().to_str().unwrap().to_owned();
new_project_dir.push(&customer_name);
new_note_dir.push(&customer_name);
match fs::read_dir(&new_project_dir){
Ok(entries) => {
for entry in entries{
match entry {
Ok(entry) => {
let entry_path = entry.path();
if entry_path.is_dir(){
if let Some(dir_name) = entry_path.file_name(){
if let Some(dir_name_str) = dir_name.to_str(){
if dir_name_str.contains("pentest"){
project_name = dir_name_str.to_owned();
println!("pentest folder found! assuming projectname...");
new_project_dir.push(&project_name);
new_note_dir.push(&project_name);
}
}
}
}
}
Err(e) => eprintln!("error reading entry name: {}", e)
}
}
}
Err(e) => eprintln!("Error reading directory entries: {}", e)
}
let mut customer_name_response = String::new();
let mut project_name_response = String::new();
println!("Customer_name: {}", &customer_name);
println!("Is this correct?");
stdin().read_line(&mut customer_name_response).unwrap();
println!("Project_name: {}", &project_name);
println!("Is this corrrect?");
stdin().read_line(&mut project_name_response).unwrap();
if customer_name_response.contains(|c: char| c == 'n' || c=='N') || project_name_response.contains(|c: char| c == 'n' || c=='N'){
println!("oops sorry about that, tried to guess based on the second to last and last folder names");
if customer_name_response.contains(|c: char| c == 'n' || c =='N'){
let mut name_response = String::new();
println!("what is the correct customer name?");
stdin().read_line(&mut name_response).unwrap();
name_response.pop();
customer_name = name_response.to_owned();
}
if project_name_response.contains(|c: char| c == 'n' || c == 'N'){
let mut project_response = String::new();
println!("what is the correct project name?");
stdin().read_line(&mut project_response).unwrap();
project_response.pop();
project_name = project_response.to_owned();
}
}
}
else{
println!("customer name?");
std::io::stdin().read_line(&mut customer_name).unwrap();
println!("project name?");
std::io::stdin().read_line(&mut project_name).unwrap();
// to remove newline characters
customer_name.pop();
project_name.pop();
new_project_dir.push(&customer_name);
new_note_dir.push(&customer_name);
new_project_dir.push(&project_name);
new_note_dir.push(&project_name);
fs::create_dir_all(&new_project_dir).expect("error creating new files folder");
fs::create_dir_all(&new_note_dir).expect("error creating new notes folder");
}
thread::sleep(Duration::from_secs(2));
let box_name = format!("atarchbox_{}", customer_name);
let mut box_name_path = new_project_dir.clone();
box_name_path.push("boxname");
let mut box_name_file = fs::File::create(box_name_path).expect("Error creating box name file");
box_name_file.write_all(&box_name.as_bytes()).expect("error writing boxname to box file");
let pentest_volume = format!("{}:/pentest:rw", new_project_dir.display());
let toold_volume = format!("{}:/tools:rw", tools_dir.display());
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
let distrobox_result = process::Command::new("distrobox")
.arg("create")
.arg("--root")
.arg("--clone")
.arg(boxtemplate)
.arg("--volume")
.arg(&toold_volume)
.arg("--volume")
.arg(&pentest_volume)
.arg("--name")
.arg(&box_name)
.status()
.expect("error getting distrobox status");
if distrobox_result.success(){
println!("we made a distrobox oh boy!");
let distrobox_start_result = process::Command::new("distrobox")
.arg("enter")
.arg("--root")
.arg(&box_name)
.arg("--")
.arg("sudo")
.arg("-s")
.arg("ln")
.arg("-sf")
.arg("/pentest/boxname")
.arg("/etc/boxname")
.status()
.expect("error getting response from distrobox start");
if distrobox_start_result.success(){
println!("distrobox was started as well!!!! good job me!");
}
else{
println!("ooof did not start successfully try entering it yoruself");
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
}
}
else{
println!("ooof distrobox did not work.... try creating it yourself");
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, &toold_volume, &pentest_volume, &box_name);
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
}
let new_project = Project{customer: customer_name.trim_end().to_owned(),
project_name: project_name.trim_end().to_owned(),
notes_folder: new_note_dir,
files_folder:new_project_dir,
active: false,
id: new_id,
boxname: box_name,
};
projects.push(new_project);
save_projects(projects, config_path);
}
fn remove_project(projects: &mut Vec<Project>, config_path: &PathBuf){
for project in projects.clone(){
println!("{} {} {}", project.id, project.customer, project.project_name);
}
let mut project_to_remove = String::new();
println!("project to remove?");
std::io::stdin().read_line(&mut project_to_remove).unwrap();
if project_to_remove.len() > 1{
let mut project_to_keep = Vec::new();
if project_to_remove.len() > 0{
let remove_id: i32 = project_to_remove.trim_end().parse().unwrap();
let mut project_set = false;
for project in projects.clone(){
if project.id == remove_id{
println!("will remove {} {}", project.customer, project.project_name);
project_set = true;
let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox");
let distrobox_rm_status = process::Command::new("distrobox-rm")
.arg("--root")
.arg("-f")
.arg(&project.boxname)
.status().expect("error calling distrobox");
if distrobox_rm_status.success(){
println!("Distrobox Removal Successful!!!");
}
else{
println!("Distrobox Removal Failed, manual removal required!");
}
}
else {
println!("{} {} will be kept", project.customer, project.project_name);
project_to_keep.push(project);
}
}
if project_set{
projects.clear();
projects.append(&mut project_to_keep);
save_projects(&projects, config_path);
}
else{
println!("error no prjects found to remove")
}
}
else{
println!("we need user in put here dummy!!");
}
}
else{
println!("we need input here dummy!");
}
}
fn open_in_dolphin(folder: &str, project: Project){
let mut to_open = PathBuf::new();
match folder{
"notes" => to_open.push(project.notes_folder),
"files" => to_open.push(project.files_folder),
_ => println!("unknown entry... this should literally be impossible... how.... how tf did you.... what")
}
process::Command::new("dolphin")
.arg(to_open)
.spawn().expect("error opening dolphin");
}
fn stop_all_boxes(projects: &Vec<Project>){
let mut problem_childs: Vec<Project> = Vec::new();
let mut all_done = true;
for project in projects{
let stopped = process::Command::new("distrobox")
.arg("stop")
.arg("--root")
.arg(&project.boxname)
.status().expect("error spawing distrobox");
if stopped.success(){
println!("{} sucessfully stopped!", &project.boxname);
}
else{
println!("{} not stopped!!!!!!!", &project.boxname);
all_done = false;
problem_childs.push(project.clone());
}
}
if all_done{
println!("All boxes stopped GO US YAAAAA WE DID IT");
}
else{
println!("OOOOOOOF some boxes didn't stop yo, that's cringe");
println!("here are the problem childs, you may need to stop them manually");
for child in problem_childs{
println!("{}",child.boxname);
}
}
}
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]);
}
}
println!("Findings");
for line in finding_lines{
if line.contains("# "){
println!("{}", line);
}
else if line.contains("- "){
println!("{}", line)
}
}
}
fn project_standalone_terminal(project: Project, mut terminal: String){
terminal = terminal.trim_end().to_owned();
let mut profile = false;
if terminal.contains("profile"){
profile = true;
}
let terminal_vec:Vec<&str> = terminal.split(" ").collect();
let mut terminal_start = process::Command::new(terminal_vec[0]);
let mut first = true;
for arg in terminal_vec{
if first == true{
first = false;
}
else{
terminal_start.arg(arg);
}
}
if profile == false {
terminal_start.arg(&project.boxname);
}
print!("{}", terminal);
let start = terminal_start.spawn();
match start{
Ok(_child) => println!("New Terminal Started, you can retun to the menu now!"),
Err(_error) => println!("error starting new terminanl, something may be wrong with the terminal part of your config!\nCheck ~/.conf/pyro_pentest_tool/conf for errors")
}
//process::Command::new("konsole").arg("--profile").arg("attack").arg(project.boxname).spawn().expect("error opeing konsole");
}
fn project_inline_terminal(project: Project){
process::Command::new("distrobox").arg("enter").arg("--root").arg(project.boxname).arg("--").arg("script").arg("-a").arg("-B").arg("/pentest/working/terminal.log").status().expect("error opeing konsole");
}
fn gnerate_userpass(project: &Project){
let mut outlines = Vec::new();
let mut notes_file = project.notes_folder.clone();
notes_file.push("l00t/creds.md");
let loot_string = fs::read_to_string(notes_file).expect("error reading creds note");
let clear_text = loot_string.split("# hashed").collect::<Vec<&str>>()[0];
let clear_text_table = clear_text.split("| ----------------------------------- | ------------- | ----------------------------- |").collect::<Vec<&str>>()[1];
let table_vec: Vec<&str> = clear_text_table.split("\n").collect();
for line in table_vec{
if line.len() > 1{
let split_line: Vec<&str> = line.split("|").collect();
let user = split_line[2].trim_end().trim_start();
let password = split_line[3].trim_end().trim_start();
let outline = format!("{}:{}\n", user, password);
outlines.push(outline);
}
}
let mut out_file_path = project.files_folder.clone();
out_file_path.push("working/userpass_fromnotes.txt");
let mut out_file = fs::File::create(out_file_path).expect("error creating userpass file");
for line in outlines{
out_file.write_all(line.as_bytes()).expect("error writing to userpass file");
}
}
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);
}
fn run_initial_enum(project: &Project){
let mut csv = String::new();
println!("path to the csv?");
std::io::stdin().read_line(&mut csv).unwrap();
let status = process::Command::new("initial_recon").arg(&csv).arg(&project.customer).arg(&project.project_name).status().expect("error running initial_recon program");
if status.success(){
println!("execllent! hosts should be imported to {}/host_notes.md", &project.notes_folder.display());
}
else{
println!("ooof something went wrong, host notes may not have saved correctly!");
}
}
fn next_project_id(config_path: &PathBuf) -> i32{
let projects = get_projects(config_path);
let mut new_id = 0;
for project in projects.clone(){
if project.id > new_id{
new_id = project.id + 1;
}
}
return new_id;
}
fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String){
let mut loopize = true;
let mut new_id = next_project_id(&config_path);
loop {
let active_project = get_active_project(&projects);
let mut response = String::new();
clear().expect("error clearing screen");
print!("
,,,;;::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:,,'......
___ __ __ ___ __ ___ __
| | |__ | / ` / \\ |\\/| |__ |__| /\\ / ` |__/ |__ |__)
|/\\| |___ |___ \\__, \\__/ | | |___ | | /~~\\ \\__, | \\ |___ | \\
__ ___ ___ __ __
/ _` |__ | |__) | | |\\ | | |\\ | / _`
\\__> |___ | | |/\\| | \\| | | \\| \\__>
NOTE SAVE PROJECT INFO BEFORE STOPPING THE APPLICATION, OR HOUR TRACKIGN WON'T BE ACCURATE
NOTE OPTION 10 WILL SAVE YOUR PROJECTS BEFORE QUITTING
Current Project: {} {}
Main Menu:
1 .) Show Active Project
2 .) List Projects
3 .) Switch Active Project
4 .) create new project with Pyro's default tool
5 .) Save Project Information
6 .) Import New Project - and setup new Distrobox
7 .) Remove Project
8 .) Open A New Terminal in Current Active Project
9 .) Open A Terminal In this windows for the current active project
10.) Open Project Files Folder In Dolphin
11.) Open Project Notes Folder In Dolphin
12.) generate userpass file from your obsidian notes
13.) run pyro's initail enum script on a nessus csv for the current project
14.) Print Project Info For Report
15.) Build host discovery cmd command from scope in notes
16.) Stop All Distroboxes
17.) Quit Application
\n", active_project.customer, active_project.project_name);
std::io::stdin().read_line(&mut response).expect("error getting menu input");
clear().expect("error clearing screen");
match response.as_str().trim_end(){
"1" => println!("\nclient: {}\n\nproject: {}\n\nbox: {}\n\nproject files: {}\n\nproject notes: {}\n", active_project.customer ,active_project.project_name, active_project.boxname, active_project.files_folder.display(), active_project.notes_folder.display()),
"2" => {println!("+++++++++++++++++++++");
for project in &projects{
println!("++{}|{}++",project.customer ,project.project_name)}
println!("++++++++++++++++++++")},
"3" => switch_project(&mut projects),
"4" => start_pentest(),
"5" => save_projects(&projects, &config_path),
"6" => {new_id = new_id + 1; new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id)},
"7" => remove_project(&mut projects, &config_path),
"8" => project_standalone_terminal(active_project.clone(), terminal.clone()),
"9" => project_inline_terminal(active_project.clone()),
"10" => open_in_dolphin("files", active_project.clone()),
"11" => open_in_dolphin("notes", active_project.clone()),
"12" => gnerate_userpass(&active_project),
"13" => run_initial_enum(&active_project),
"14" => print_report_information(active_project.clone()),
"15" => build_cmd_for_host_discovery(&active_project),
"16" => stop_all_boxes(&projects),
"17" => {save_projects(&projects, &config_path);
let mut stop = String::new();
println!("stop all boxes?\ny/n");
std::io::stdin().read_line(&mut stop).unwrap();
if stop.contains("y"){
stop_all_boxes(&projects);
}
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();
}
}
fn main() { fn main() {
@@ -831,7 +46,7 @@ fn main() {
let mut config_path = user_dirs.home_dir().to_path_buf(); let mut config_path = user_dirs.home_dir().to_path_buf();
config_path.push(".config/pyro_pentest_tool/conf"); config_path.push(".config/pyro_pentest_tool/conf");
if config_path.as_path().exists() == false{ if config_path.as_path().exists() == false{
install(&config_path); install::install(&config_path);
} }
let mut project_base_folder = PathBuf::new(); let mut project_base_folder = PathBuf::new();
let mut project_base_notes = PathBuf::new(); let mut project_base_notes = PathBuf::new();
@@ -862,9 +77,9 @@ fn main() {
terminal_command: {}\n terminal_command: {}\n
", project_base_folder.display(), project_base_notes.display(), tools_folder.display(), box_template, terminal_command); ", project_base_folder.display(), project_base_notes.display(), tools_folder.display(), box_template, terminal_command);
println!("loading project configs..."); println!("loading project configs...");
let projects = get_projects(&config_path); let projects = project_controls::get_projects(&config_path);
println!("Enter to start main menu"); println!("Enter to start main menu");
let mut enter = String::new(); let mut enter = String::new();
std::io::stdin().read_line(&mut enter).unwrap(); std::io::stdin().read_line(&mut enter).unwrap();
main_menu(projects, config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template, terminal_command); menu::main_menu(projects, config_path, &project_base_folder, &project_base_notes, &tools_folder, box_template, terminal_command);
} }

148
pentest_tool/src/menu.rs Normal file
View File

@@ -0,0 +1,148 @@
use std::path::PathBuf;
use clearscreen::clear;
use clearscreen;
use crate::Project;
use crate::project_controls;
use crate::box_controls;
use crate::info_controls;
use crate::start_pentest;
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){
let mut loopize = true;
let mut new_id = next_project_id(&config_path);
loop {
let active_project = get_active_project(&projects);
let mut response = String::new();
clear().expect("error clearing screen");
print!("
,,,;;::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:,,'......
___ __ __ ___ __ ___ __
| | |__ | / ` / \\ |\\/| |__ |__| /\\ / ` |__/ |__ |__)
|/\\| |___ |___ \\__, \\__/ | | |___ | | /~~\\ \\__, | \\ |___ | \\
__ ___ ___ __ __
/ _` |__ | |__) | | |\\ | | |\\ | / _`
\\__> |___ | | |/\\| | \\| | | \\| \\__>
NOTE SAVE PROJECT INFO BEFORE STOPPING THE APPLICATION, OR HOUR TRACKIGN WON'T BE ACCURATE
NOTE OPTION 10 WILL SAVE YOUR PROJECTS BEFORE QUITTING
Current Project: {} {}
Main Menu:
1 .) Show Active Project
2 .) List Projects
3 .) Switch Active Project
4 .) create new project with Pyro's default tool
5 .) Save Project Information
6 .) Import New Project - and setup new Distrobox
7 .) Remove Project
8 .) Open A New Terminal in Current Active Project
9 .) Open A Terminal In this windows for the current active project
10.) Open Project Files Folder In Dolphin
11.) Open Project Notes Folder In Dolphin
12.) generate userpass file from your obsidian notes
13.) run pyro's initail enum script on a nessus csv for the current project
14.) Print Project Info For Report
15.) Build host discovery cmd command from scope in notes
16.) Stop All Distroboxes
17.) Quit Application
\n", active_project.customer, active_project.project_name);
std::io::stdin().read_line(&mut response).expect("error getting menu input");
clear().expect("error clearing screen");
match response.as_str().trim_end(){
"1" => println!("\nclient: {}\n\nproject: {}\n\nbox: {}\n\nproject files: {}\n\nproject notes: {}\n", active_project.customer ,active_project.project_name, active_project.boxname, active_project.files_folder.display(), active_project.notes_folder.display()),
"2" => {println!("+++++++++++++++++++++");
for project in &projects{
println!("++{}|{}++",project.customer ,project.project_name)}
println!("++++++++++++++++++++")},
"3" => project_controls::switch_project(&mut projects),
"4" => start_pentest::start_pentest(&config_path),
"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)},
"7" => project_controls::remove_project(&mut projects, &config_path),
"8" => box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()),
"9" => box_controls::project_inline_terminal(active_project.clone()),
"10" => info_controls::open_in_dolphin("files", active_project.clone()),
"11" => info_controls::open_in_dolphin("notes", active_project.clone()),
"12" => info_controls::generate_userpass(&active_project),
"13" => info_controls::run_initial_enum(&active_project),
"14" =>info_controls::print_report_information(active_project.clone()),
"15" => info_controls::build_cmd_for_host_discovery(&active_project),
"16" => box_controls::stop_all_boxes(&projects),
"17" => {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);
}
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();
}
}

View File

@@ -0,0 +1,339 @@
use std::env;
use std::fs;
use std::io::stdin;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use std::thread;
use std::time::Duration;
use std::str::FromStr;
use crate::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);
}
}
println!("\nnew project selection?\n");
let mut response = String::new();
std::io::stdin().read_line(&mut response).unwrap();
if response.len() > 1{
let new_id:i32 = response.trim_end().parse().expect("error converting to i32");
for project in projects{
if project.id == new_id{
project.active = true;
println!("project found switching to {} {}", project.customer, project.project_name);
env::set_var("CURRENT_PROJECT_BOX", project.boxname.clone());
}
else if project.id != new_id{
project.active = false;
}
else{
println!("error unknown project id")
}
}
}
else{
println!("error we need user input here dummy!");
}
}
pub fn save_projects(projects: &Vec<Project>, config_path: &PathBuf){
let mut save_file_path = config_path.clone();
let mut active_set = false;
save_file_path.pop();
save_file_path.push("projects.conf");
let mut save_file = fs::File::create(save_file_path).expect("error creating save_file");
save_file.write_all(b"customer:name:notes:files:active:time:box_name\n").expect("error writing first line to file");
for project in projects{
let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()};
let mut _outline = String::new();
if project.active{
if active_set == false{
_outline = format!("{}yes:{}\n", default, project.boxname);
active_set = true;
}
}
else{
_outline = format!("{}no:{}\n", default, project.boxname);
}
save_file.write_all(_outline.as_bytes()).expect("error writing outline");
}
}
pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, config_path: &PathBuf, new_id: i32){
let mut new_project_dir = project_dir.clone();
let mut new_note_dir = notes_dir.clone();
let mut existing_folders = String::new();
let mut customer_name = String::new();
let mut project_name = String::new();
println!("do you have an existing notes and folder structure to copy over?\ny/n");
std::io::stdin().read_line(&mut existing_folders).unwrap();
let mut customer_name = customer_name.trim_end().to_owned();
let mut project_name = project_name.trim_end().to_owned();
if existing_folders.contains("y") || existing_folders.contains("Y"){
println!("NOTE THIS WILL OVERWRITE CUSTOMER NAME AND PROJECT NAME WITH THE 2nd TO LAST AND LAST FOLDER NAMES IN THE PATH YOU'RE COPYING RESPECTIVELY");
let mut files_to_copy = String::new();
let mut notes_to_copy = String::new();
println!("path to project folder folder to copy:");
std::io::stdin().read_line(&mut files_to_copy).unwrap();
println!("path to notes folder to copy:");
std::io::stdin().read_line(&mut notes_to_copy).unwrap();
//to get rid of the new line chars
files_to_copy.pop();
notes_to_copy.pop();
println!("files to copy: {}", files_to_copy);
println!("notes to copy: {}", notes_to_copy);
println!("files destination: {}", new_project_dir.display());
println!("notes destination: {}", new_note_dir.display());
let folder_move_success = process::Command::new("mv")
.arg("-i")
.arg(&files_to_copy)
.arg(new_project_dir.display().to_string())
.status().expect("unable to call the system mv command");
let note_move_success = process::Command::new("mv")
.arg("-i")
.arg(&notes_to_copy)
.arg(new_note_dir.display().to_string())
.status().expect("unable to call the system mv command");
if folder_move_success.success(){
println!("we copied the project folder correctly!!");
}
else{
println!("failed to copy the project folder, try to move it manually!");
}
if note_move_success.success(){
println!("we copied the notes folder correctly!!");
}
else{
println!("failed to copy the notes folder, try to move it manually!");
}
// this lovely set of code takes the folder you gave to copy and tries to find the customername and project name based on directory names
// this solves a case where the entered customer name or project name does not match the files copied
let copied_files = PathBuf::from(&files_to_copy);
customer_name = copied_files.file_name().unwrap().to_str().unwrap().to_owned();
new_project_dir.push(&customer_name);
new_note_dir.push(&customer_name);
match fs::read_dir(&new_project_dir){
Ok(entries) => {
for entry in entries{
match entry {
Ok(entry) => {
let entry_path = entry.path();
if entry_path.is_dir(){
if let Some(dir_name) = entry_path.file_name(){
if let Some(dir_name_str) = dir_name.to_str(){
if dir_name_str.contains("pentest"){
project_name = dir_name_str.to_owned();
println!("pentest folder found! assuming projectname...");
new_project_dir.push(&project_name);
new_note_dir.push(&project_name);
}
}
}
}
}
Err(e) => eprintln!("error reading entry name: {}", e)
}
}
}
Err(e) => eprintln!("Error reading directory entries: {}", e)
}
let mut customer_name_response = String::new();
let mut project_name_response = String::new();
println!("Customer_name: {}", &customer_name);
println!("Is this correct?");
stdin().read_line(&mut customer_name_response).unwrap();
println!("Project_name: {}", &project_name);
println!("Is this corrrect?");
stdin().read_line(&mut project_name_response).unwrap();
if customer_name_response.contains(|c: char| c == 'n' || c=='N') || project_name_response.contains(|c: char| c == 'n' || c=='N'){
println!("oops sorry about that, tried to guess based on the second to last and last folder names");
if customer_name_response.contains(|c: char| c == 'n' || c =='N'){
let mut name_response = String::new();
println!("what is the correct customer name?");
stdin().read_line(&mut name_response).unwrap();
name_response.pop();
customer_name = name_response.to_owned();
}
if project_name_response.contains(|c: char| c == 'n' || c == 'N'){
let mut project_response = String::new();
println!("what is the correct project name?");
stdin().read_line(&mut project_response).unwrap();
project_response.pop();
project_name = project_response.to_owned();
}
}
}
else{
println!("customer name?");
std::io::stdin().read_line(&mut customer_name).unwrap();
println!("project name?");
std::io::stdin().read_line(&mut project_name).unwrap();
// to remove newline characters
customer_name.pop();
project_name.pop();
new_project_dir.push(&customer_name);
new_note_dir.push(&customer_name);
new_project_dir.push(&project_name);
new_note_dir.push(&project_name);
fs::create_dir_all(&new_project_dir).expect("error creating new files folder");
fs::create_dir_all(&new_note_dir).expect("error creating new notes folder");
}
thread::sleep(Duration::from_secs(2));
let box_name = format!("atarchbox_{}", customer_name);
let mut box_name_path = new_project_dir.clone();
box_name_path.push("boxname");
let mut box_name_file = fs::File::create(box_name_path).expect("Error creating box name file");
box_name_file.write_all(&box_name.as_bytes()).expect("error writing boxname to box file");
let pentest_volume = format!("{}:/pentest:rw", new_project_dir.display());
let toold_volume = format!("{}:/tools:rw", tools_dir.display());
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
let distrobox_result = process::Command::new("distrobox")
.arg("create")
.arg("--root")
.arg("--clone")
.arg(boxtemplate)
.arg("--volume")
.arg(&toold_volume)
.arg("--volume")
.arg(&pentest_volume)
.arg("--name")
.arg(&box_name)
.status()
.expect("error getting distrobox status");
if distrobox_result.success(){
println!("we made a distrobox oh boy!");
let distrobox_start_result = process::Command::new("distrobox")
.arg("enter")
.arg("--root")
.arg(&box_name)
.arg("--")
.arg("sudo")
.arg("-s")
.arg("ln")
.arg("-sf")
.arg("/pentest/boxname")
.arg("/etc/boxname")
.status()
.expect("error getting response from distrobox start");
if distrobox_start_result.success(){
println!("distrobox was started as well!!!! good job me!");
}
else{
println!("ooof did not start successfully try entering it yoruself");
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
}
}
else{
println!("ooof distrobox did not work.... try creating it yourself");
println!("distrobox create --root --clone {} --volume {} --volume {} --name {}", boxtemplate, &toold_volume, &pentest_volume, &box_name);
println!("distrobox enter --rrot {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
}
let new_project = Project{customer: customer_name.trim_end().to_owned(),
project_name: project_name.trim_end().to_owned(),
notes_folder: new_note_dir,
files_folder:new_project_dir,
active: false,
id: new_id,
boxname: box_name,
};
projects.push(new_project);
save_projects(projects, config_path);
}
pub fn remove_project(projects: &mut Vec<Project>, config_path: &PathBuf){
for project in projects.clone(){
println!("{} {} {}", project.id, project.customer, project.project_name);
}
let mut project_to_remove = String::new();
println!("project to remove?");
std::io::stdin().read_line(&mut project_to_remove).unwrap();
if project_to_remove.len() > 1{
let mut project_to_keep = Vec::new();
if project_to_remove.len() > 0{
let remove_id: i32 = project_to_remove.trim_end().parse().unwrap();
let mut project_set = false;
for project in projects.clone(){
if project.id == remove_id{
println!("will remove {} {}", project.customer, project.project_name);
project_set = true;
let _distrobox_stop_status = process::Command::new("distrobox").arg("stop").arg("--root").arg(&project.boxname).status().expect("error stopping distrobox");
let distrobox_rm_status = process::Command::new("distrobox-rm")
.arg("--root")
.arg("-f")
.arg(&project.boxname)
.status().expect("error calling distrobox");
if distrobox_rm_status.success(){
println!("Distrobox Removal Successful!!!");
}
else{
println!("Distrobox Removal Failed, manual removal required!");
}
}
else {
println!("{} {} will be kept", project.customer, project.project_name);
project_to_keep.push(project);
}
}
if project_set{
projects.clear();
projects.append(&mut project_to_keep);
save_projects(&projects, config_path);
}
else{
println!("error no prjects found to remove")
}
}
else{
println!("we need user in put here dummy!!");
}
}
else{
println!("we need input here dummy!");
}
}
pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{
let mut mut_config_path = config_path.clone();
mut_config_path.pop();
mut_config_path.push("projects.conf");
let mut projects = Vec::new();
let projects_string = fs::read_to_string(mut_config_path).expect("error reading projects file");
let project_lines:Vec<&str> = projects_string.split("\n").collect();
let mut first = 0;
let mut already_active = false;
for line in project_lines{
first = first + 1;
if first != 1{
if line.len() > 1{
let settings: Vec<&str> = line.split(":").collect();
let customer = settings[0].to_owned();
let project = settings[1].to_owned();
let notes_string = settings[2].to_owned();
let folder_string = settings[3].to_owned();
let notes_folder = PathBuf::from_str(&notes_string.trim_end()).expect("error reading notes string");
let project_folder = PathBuf::from_str(&folder_string.trim_end()).expect("error reading folding sering");
let mut active = false;
let boxname = settings[5].to_owned();
if settings[4] == "yes"{
if already_active == false{
env::set_var("CURRENT_PROJECT_BOX", boxname.clone());
already_active = true;
active = true;
}
}
let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname};
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
projects.push(new_project);
}
}
}
return projects
}

View File

@@ -0,0 +1,313 @@
use std::fs;
use std::io::stdin;
use std::io::Write;
use std::path::PathBuf;
fn external(project_folder_path: String,comapny_name: &String, project_name: &String, passtemp: PathBuf){
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file");
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file");
let mut host_notes = fs::File::create(format!("{}/host_notes.md", &project_folder_path)).expect("error creating host notes file");
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file");
// for tagging
let year = project_name.split("_").collect::<Vec<&str>>()[1];
let project_type = "External";
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file");
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing tags on attack notes");
writeln!(&mut host_notes, "##{} #{} #{} #host_notes", comapny_name, project_type, year).expect("error writing tag lin in host notes");
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tag line on findings");
writeln!(&mut general_notes, "# Scope").expect("error writing to general notes file");
writeln!(&mut general_notes, "\n| IP | Third Party | Approval |").expect("error writing to general notes file");
writeln!(&mut general_notes, "| -- | ----------- | -------- |").expect("error writing to general notes file");
writeln!(&mut general_notes, "# PPC").expect("failed to write general notes");
write!(&mut general_notes, "
Planning call notes:
* methodolgy
* whole month testing window
* start with a vuln scan in nessus pro
* pentesting execution standard framework
* info gathering
* recon
* exlpoitation
* reporting
* primary objective
* reasonable and expected protections are in place
* see if we can get access to the internal network
* if we do get inside
* reach out to the contact and see what they'd want us to know
* questions to ask
* custom objectives
*
* testing main website
* password attacks
* password sprays 3-12 hours
* lock out policy -
## Enumeration in progress
### DNS Bruteforcing
| domain name | IP | inscope? |
| ----------- | -- | -------- |
# Attack Surface Enumeration
| IP | host notes | needs? |
| -- | ---------- | ------ |\n").expect("faile to write pentest notes");
// set up the basics for our attack notes
write!(&mut attack_notes,"
# Directory Bruteforcing
- [ ] example.com
----
# Login attacks
## examle.com/login
- [ ] stuffed
- [ ] sprayed
- [ ] bruteforced
- [ ] default
----
# MSOLspray.py
passwords tried:
* password\n
" ).expect("failed to write attack notes template");
let new_spray_path = format!("{}/passwordspray.md", &project_folder_path);
fs::copy(passtemp,new_spray_path).unwrap();
}
fn internal(project_folder_path: String, comapny_name: &String, project_name: &String, passtemp: PathBuf){
let loot_folder = format!("{}/l00t", project_folder_path);
fs::create_dir_all(&loot_folder).expect("error creating loot directory");
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file");
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file");
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file");
let mut systeminfo = fs::File::create(format!("{}/systeminfo", &project_folder_path)).expect("error creating systeminfo note file");
let mut netsta = fs::File::create(format!("{}/netstat", &project_folder_path)).expect("error creating netstat file");
let mut creds_notes = fs::File::create(format!("{}/creds.md", &loot_folder)).expect("error creating creds note");
let mut todo_notes = fs::File::create(format!("{}/todo.md", &project_folder_path)).expect("error creating todo notes");
let mut cleanup_notes = fs::File::create(format!("{}/cleanup.md", &project_folder_path)).expect("error creating cleanup notes");
let mut dump_notes = fs::File::create(format!("{}/dumps.md", &loot_folder)).expect("error creating password spray notes");
let mut enum_notes = fs::File::create(format!("{}/initial_enum.md", &project_folder_path)).expect("error creating password spray notes");
let enum_obsidian_path = format!("Hack_Notes/pentest_notes/upcomming/{customer}//initial_enum.md", customer = comapny_name);
// for tagging notes
let oyear = project_name.split("_").collect::<Vec<&str>>()[0];
let year = format!("year-{}", oyear);
let project_type = "Internal";
writeln!(&mut creds_notes, "#{} #{} #{} #l00t #creds", comapny_name, project_type, year).expect("error writing creds notes");
writeln!(&mut dump_notes, "#{} #{} #{} #l00t #dumps", comapny_name, project_type, year).expect("error writing creds notes");
writeln!(&mut cleanup_notes, "#{} #{} #{} #cleanup", comapny_name, project_type, year).expect("error writing to cleanup notes");
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file");
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing attack note tags");
writeln!(&mut todo_notes, "#{} #{} #{} #todo", comapny_name, project_type, year).expect("error writing tag line on todo");
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tags line on findings");
writeln!(&mut systeminfo, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tag line for system info");
writeln!(&mut systeminfo, "#{} #{} #{} #Password_sprays", comapny_name, project_type, year).expect("error writing tag line for password spraying");
writeln!(&mut netsta, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tagline in the netstat file");
writeln!(&mut enum_notes, "#{} #{} #{} #enum", comapny_name, project_type, year).expect("error writing tagline in the netstat file");
writeln!(&mut creds_notes, "# CREDS").expect("error writing creds notes");
writeln!(&mut creds_notes, "\n| System | username | password |").expect("error writing creds notes");
writeln!(&mut creds_notes, "| ------ | -------- | -------- |").expect("error writing creds notes");
writeln!(&mut creds_notes, "\n\n").expect("error writing creds notes");
writeln!(&mut creds_notes, "# HASHES\n\n").expect("error writing creds notes");
writeln!(&mut creds_notes, "| TYPE | USER | HASH |").expect("error writing creds notes");
writeln!(&mut creds_notes, "| ---- | ---- | ---- |").expect("error writing creds notes");
writeln!(&mut cleanup_notes, "- [ ] Breach machine C-temp-fr").expect("error writing to cleanup notes");
writeln!(&mut cleanup_notes, "- [ ] (continue to add as needed").expect("error writing ot cleanup notes");
writeln!(&mut general_notes, "# Scope\n").expect("error writing to general notes file");
writeln!(&mut general_notes, "PASTE SCOPE FROM EXCELL HERE (THE EXCEL TO MARKDOWN TABLE PLUGIN WILL FORMAT FOR YOU").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "# SAM\n\n").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "## system name\n").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "```\n\n").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "# LSASS\n\n").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "## system name\n").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail");
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail");
write!(&mut general_notes, "
On the call:
Introductions
Let them know that their primary contact will be the PM and there should be
Go over general attack strategy/procedure.
We will get a beacon payload by the time the test starts
The beacon payload should be executed on a domain joined windows system.
If the system is not domain joined/no domain - let Seth know as this modifies the standard beacon
Select a user based on a department/role that they would like tested (Marketing, Sales, HR, IT)
This can be a test system with a cloned user, but then we don't get keylogging or screen grabs
The beacon is created using Cobalt Strike and communicates over HTTPS
Since Cobalt Strike is very well signatured, remind them that they may need to add an exclusion in antivirus and/or web filter
We will look at local privilege escalation, conduct portscans, password sprays, targeted vulnerability scanning (NOT NESSUS), lateral movement opportunities, and escalating to DOMAIN ADMIN privilege.
Ask if they want a focus on any particular assets. for example, an old time logging system, or remote access system.
Confirm On Prem AD vs NoAD or Azure AD
Ask if they have any questions or concerns
Do they have a specific contact
Email any follow-up items from the call to the PM
").expect("error writing PPC text");
write!(&mut attack_notes,"
# current dat (ex: 7/5)
Got Persistence via (schtasks, bat schtasks, startup folder)
echo WHOAMI > initialenum.txt && echo ``` >> initialenum.txt && whoami /all >> initialenum.txt && echo ``` >> initialenum.txt && echo IPCONFIG >> initialenum.txt && echo ``` >> initialenum.txt && ipconfig /all >> initialenum.txt && echo ``` >> initialenum.txt && echo NETSTAT -ANO >> initialenum.txt && echo ``` >> initialenum.txt && netstat -ano >> initialenum.txt && echo ``` >> initialenum.txt && echo NET ACCOUNTS (LOCAL) >> initialenum.txt && echo ``` >> initialenum.txt && net accounts >> initialenum.txt && echo ``` >> initialenum.txt && echo NET ACCOUNTS (DOMAIN) >> initialenum.txt && echo ``` >> initialenum.txt && net accounts /domain >> initialenum.txt && echo ``` >> initialenum.txt && echo NET LOCALGROUP ADMINISTRATORS >> initialenum.txt && echo ``` >> initialenum.txt && net localgroup administrators >> initialenum.txt && echo ``` >> initialenum.txt && echo NET SHARE >> initialenum.txt && echo ``` >> initialenum.txt && net share >> initialenum.txt && echo ``` >> initialenum.txt && echo NET USE >> initialenum.txt && echo ``` >> initialenum.txt && net use >> initialenum.txt && echo ``` >> initialenum.txt && echo SYSTEMINFO >> initialenum.txt && echo ``` >> initialenum.txt && systeminfo >> initialenum.txt
whoami /all
![[{enum}#WHOAMI]]
ipconfig /all
![[{enum}#IPCONFIG]]
netstat -ano
[[{enum}#NETSTAT]]
net accounts
![[{enum}#NET ACCOUNTS]]
net accounts /domain
![[{enum}#NET ACCOUNTS DOMAIN]]
net localgroup administrators
![[{enum}#LOCAL ADMINS]]
Net group \"domain admins\" /domain
![[{enum}#DOMAIN ADMINS]]
net share
![[{enum}#NET SHARE]]
net use
![[{enum}#NET USE]]
systeminfo
[[{enum}#SYSTEMINFO]]
dsregcmd
[[{enum}#DSREGCMD]]
powerup.ps1/sharpup.exe notes.
", enum = enum_obsidian_path).expect("error writing to attack notes for internal tests");
write!(&mut finding_notes, "
# normal findings
# data exfil
## [Sarting Username]
").expect("error writing to findings notes on internal");
write!(&mut todo_notes, "
- [ ] local checks
- [ ] find shares
- [ ] snaffle
- [ ] bloodhound
- [ ] admin or RDP?
- [ ] certify
- [ ] portscan
- [ ] sql stuff
- [ ] passwords in AD Descriptions?
- [ ] password spray
").expect("error writing todo list");
write!(&mut netsta,"
```
```").expect("error writing code block to system info");
write!(&mut systeminfo,"
```
```").expect("error writing code block to system info");
let new_pass_path = format!("{}/passwordspray.md", &project_folder_path);
println!("{} | {}", passtemp.display(), new_pass_path);
fs::copy(passtemp, new_pass_path).unwrap();
}
pub fn start_pentest(config_path: &PathBuf) {
let mut pentest_notes = String::new();
let mut project_files = String::new();
let mut company_name = String::new();
let mut project_name = String::new();
let mut config_file_path_buf = config_path.clone();
let mut passpray_path = config_file_path_buf.clone();
passpray_path.push("passwordspray.md");
config_file_path_buf.push("new_projects.conf");
let config_string = fs::read_to_string(config_file_path_buf).expect("error reading ");
if config_string.contains("folder_path") && config_string.contains("notes_path"){
let config_string_vec: Vec<&str> = config_string.split("\n").collect();
for line in config_string_vec{
if line.contains("project_folder_path"){
let line_vec: Vec<&str> = line.split(":").collect();
project_files = line_vec[1].to_owned();
}
else if line.contains("project_notes_path"){
let line_vec: Vec<&str> = line.split(":").collect();
pentest_notes = line_vec[1].to_owned();
}
}
}
println!("Project files path: {}\nProject Notes path: {}", project_files, pentest_notes);
println!("Comapny Name?");
std::io::stdin().read_line(&mut company_name);
println!("project Name?");
stdin().read_line(&mut project_name);
//remove new lines from input
company_name.trim_end();
project_name.trim_end();
let project_folder_path = format!("{}/{}/{}", pentest_notes, company_name,project_name);
println!("setting folder creation paths...");
let project_files_folder_path = format!("{}/{}/{}", project_files, company_name, project_name);
let working_folder = format!("{}/working", &project_files_folder_path);
let writing_folder = format!("{}/writing", &project_files_folder_path);
let screeenshot_folder = format!("{}/screenshots",&writing_folder);
let delivery_folder = format!("{}/delivery", &project_files_folder_path);
// make the folders for this project's notes and files
println!("creating directory structure for notes and file folders...");
fs::create_dir_all(&project_folder_path).expect("Error creating project folder");
fs::create_dir_all(&project_files_folder_path).expect("Error creating project file folder");
fs::create_dir_all(&working_folder).expect("error creating working directory");
fs::create_dir_all(&writing_folder).expect("Error creating writing direcotry");
fs::create_dir(&screeenshot_folder).expect("error creating screenshots folder");
fs::create_dir_all(&delivery_folder).expect("Error creating delivery direcotry");
if project_name.contains("internal"){
println!("internal pentest type detected, auto populating notes with internal layout...");
internal(project_folder_path,&company_name, &project_name, passpray_path);
}
else if project_name.contains("external") {
println!("external pentest type detected, auto populating notes with external layout...");
external(project_folder_path, &company_name, &project_name, passpray_path);
}
else if project_name.contains("webapp") {
println!("not implemented yet sorry");
println!("default file folder structure used, and empty notes folder created...")
}
else{
println!("unknown project type detected, default folder strucutre and empty note folder created...");
print!("
Known project types:
Internal Penetration Test
External Penetartion Test
If this test is actually one of these types please include the type in the project name parameter, example: 2023_internal_pentest.
If this test is a common test and you would like a default note structure implemented in this script let Kevin \"Kage\" Gunter know and supply an example markdown note sheet.");
}
}

View File

@@ -1 +1 @@
{"rustc_fingerprint":12601758400278646363,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.79.0 (129f3b996 2024-06-10)\nbinary: rustc\ncommit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081\ncommit-date: 2024-06-10\nhost: x86_64-unknown-linux-gnu\nrelease: 1.79.0\nLLVM version: 18.1.7\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/pyro/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}} {"rustc_fingerprint":1960306743998270933,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/pyro/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.83.0 (90b35a623 2024-11-26)\nbinary: rustc\ncommit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf\ncommit-date: 2024-11-26\nhost: x86_64-unknown-linux-gnu\nrelease: 1.83.0\nLLVM version: 19.1.1\n","stderr":""}},"successes":{}}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
05e6a2536daa107a

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"std\"]","declared_features":"[\"arbitrary\", \"bytemuck\", \"compiler_builtins\", \"core\", \"example_generated\", \"rustc-dep-of-std\", \"serde\", \"std\"]","target":14463131919016566876,"profile":10243973527296709326,"path":9228158316637899548,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-778b466868486432/dep-lib-bitflags","checksum":false}}],"rustflags":[],"metadata":14564035643000669268,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
388f42111244902a

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"default\"]","declared_features":"[\"compiler_builtins\", \"core\", \"default\", \"example_generated\", \"rustc-dep-of-std\"]","target":202096439108023897,"profile":10243973527296709326,"path":3297157276231387091,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-796ee5e059da5bcc/dep-lib-bitflags","checksum":false}}],"rustflags":[],"metadata":14564035643000669268,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
4564aaca188960b7

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[\"compiler_builtins\", \"core\", \"rustc-dep-of-std\"]","target":11601024444410784892,"profile":10243973527296709326,"path":11251423349894544871,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/cfg-if-f1126d5e99956cbe/dep-lib-cfg_if","checksum":false}}],"rustflags":[],"metadata":8462187951337715540,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
dabc9fe5ca9c63f4

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[\"windows-console\"]","target":16510214328398099570,"profile":10243973527296709326,"path":14967873048789862483,"deps":[[6165314194305105601,"thiserror",false,14456543346191666976],[6583558668148823975,"which",false,11162537753682719875],[6670304167515094581,"terminfo",false,13222487086128244100],[17995977118843992204,"nix",false,3197397263473614650]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/clearscreen-1c48c433255f9c28/dep-lib-clearscreen","checksum":false}}],"rustflags":[],"metadata":3954388147124695588,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
62dadf8571ff6215

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[\"windows-console\"]","target":16510214328398099570,"profile":10243973527296709326,"path":14967873048789862483,"deps":[[6165314194305105601,"thiserror",false,14456543346191666976],[6583558668148823975,"which",false,11162537753682719875],[6670304167515094581,"terminfo",false,2744511574786726040],[17995977118843992204,"nix",false,3197397263473614650]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/clearscreen-345b6824d4b33831/dep-lib-clearscreen","checksum":false}}],"rustflags":[],"metadata":3954388147124695588,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
67d9407881be5aee

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":6431201985272143883,"profile":10243973527296709326,"path":14901037407568701745,"deps":[[8374856912967190420,"dirs_sys",false,467828751267860915]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/directories-cedee198e6a671c8/dep-lib-directories","checksum":false}}],"rustflags":[],"metadata":931290570756584624,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
bd9e7e9ba848bf6d

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":2202548160250307783,"profile":10243973527296709326,"path":5780857034169534110,"deps":[[3220473298903565236,"dirs_sys",false,14246505222629087773]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/dirs-0ed43f970d02ea56/dep-lib-dirs","checksum":false}}],"rustflags":[],"metadata":2541453624792457215,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
b3110947c50f7e06

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":18042856654396396435,"profile":10243973527296709326,"path":10062251932320054921,"deps":[[2402594958175656394,"option_ext",false,10360775055501092009],[7333356460339158070,"libc",false,4642729928300125779]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/dirs-sys-15f825f9fb3a7df6/dep-lib-dirs_sys","checksum":false}}],"rustflags":[],"metadata":9863373507860298850,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
1dda8dcd04c1b5c5

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":18042856654396396435,"profile":10243973527296709326,"path":120409245313347269,"deps":[[7333356460339158070,"libc",false,4642729928300125779]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/dirs-sys-cb014b0511c9b654/dep-lib-dirs_sys","checksum":false}}],"rustflags":[],"metadata":9863373507860298850,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
532812355c1dcada

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"default\", \"use_std\"]","declared_features":"[\"default\", \"serde\", \"use_std\"]","target":10829531579163655734,"profile":10243973527296709326,"path":13684765491506208335,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/either-11160f7901da87fc/dep-lib-either","checksum":false}}],"rustflags":[],"metadata":15700307601938671422,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
190bf29085f55d42

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"std\"]","target":10602123296753431656,"profile":10243973527296709326,"path":1171307554580070994,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/fnv-43483d1b823043ea/dep-lib-fnv","checksum":false}}],"rustflags":[],"metadata":17205452474433819084,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
93ddf862321a9b6a

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":3508794390613860859,"profile":10243973527296709326,"path":2586856713099344709,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/fs_extra-d141ac97b9a17a1e/dep-lib-fs_extra","checksum":false}}],"rustflags":[],"metadata":6278385800500818621,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
a7ce9ad5654b8606

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":13562696179710165918,"profile":16100742205268768141,"path":3109148676127408193,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/home-fb004de7e6b358ca/dep-lib-home","checksum":false}}],"rustflags":[],"metadata":17120348937331362501,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"default\", \"extra_traits\", \"std\"]","declared_features":"[\"align\", \"const-extern-fn\", \"default\", \"extra_traits\", \"rustc-dep-of-std\", \"rustc-std-workspace-core\", \"std\", \"use_std\"]","target":6423576478976419116,"profile":13232757476167777671,"path":12691612159246123571,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/libc-009a28365efb6f3a/dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"metadata":14998826085014762512,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
535e6784454a6e40

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"default\", \"extra_traits\", \"std\"]","declared_features":"[\"align\", \"const-extern-fn\", \"default\", \"extra_traits\", \"rustc-dep-of-std\", \"rustc-std-workspace-core\", \"std\", \"use_std\"]","target":4880141883626693381,"profile":10243973527296709326,"path":3258588435642682967,"deps":[[7333356460339158070,"build_script_build",false,12939263799633012627]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/libc-772aad0dd4f18c09/dep-lib-libc","checksum":false}}],"rustflags":[],"metadata":14998826085014762512,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[7333356460339158070,"build_script_build",false,12694920042654472050]],"local":[{"RerunIfChanged":{"output":"debug/build/libc-e9cb25cc5dd09304/output","paths":["build.rs"]}}],"rustflags":[],"metadata":0,"config":0,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
2547bb47afae807f

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"elf\", \"errno\", \"general\", \"ioctl\", \"no_std\"]","declared_features":"[\"compiler_builtins\", \"core\", \"default\", \"elf\", \"errno\", \"general\", \"if_ether\", \"io_uring\", \"ioctl\", \"mempolicy\", \"net\", \"netlink\", \"no_std\", \"prctl\", \"rustc-dep-of-std\", \"std\", \"system\", \"xdp\"]","target":4821762226960737088,"profile":10243973527296709326,"path":1711252193695186347,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/linux-raw-sys-a86e311bf41073b0/dep-lib-linux_raw_sys","checksum":false}}],"rustflags":[],"metadata":8421959000950547999,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
4fe63045e8992d87

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"alloc\", \"std\"]","declared_features":"[\"alloc\", \"compiler_builtins\", \"core\", \"default\", \"libc\", \"logging\", \"rustc-dep-of-std\", \"std\", \"use_std\"]","target":11224823532731451965,"profile":10243973527296709326,"path":13779650926054459912,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/memchr-7ee6dfd2d8b2c23e/dep-lib-memchr","checksum":false}}],"rustflags":[],"metadata":7513296495906230968,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"std\"]","declared_features":"[\"alloc\", \"compact\", \"default\", \"lint\", \"nightly\", \"std\"]","target":18188918291909960064,"profile":10243973527296709326,"path":3408356676592096060,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/minimal-lexical-bed642e143a15379/dep-lib-minimal_lexical","checksum":false}}],"rustflags":[],"metadata":2051824130325965549,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
3a9f26dfde6f5f2c

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"fs\", \"term\"]","declared_features":"[\"acct\", \"aio\", \"default\", \"dir\", \"env\", \"event\", \"feature\", \"fs\", \"hostname\", \"inotify\", \"ioctl\", \"kmod\", \"memoffset\", \"mman\", \"mount\", \"mqueue\", \"net\", \"personality\", \"pin-utils\", \"poll\", \"process\", \"pthread\", \"ptrace\", \"quota\", \"reboot\", \"resource\", \"sched\", \"signal\", \"socket\", \"term\", \"time\", \"ucontext\", \"uio\", \"user\", \"zerocopy\"]","target":2888969515341575249,"profile":10243973527296709326,"path":11613792981725561153,"deps":[[2452538001284770427,"cfg_if",false,13213712046277420101],[7333356460339158070,"libc",false,4642729928300125779],[14051957667571541382,"bitflags",false,3067026190628982584]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/nix-68ad17a6529c8499/dep-lib-nix","checksum":false}}],"rustflags":[],"metadata":7592889295042356366,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
5432f92e5a855727

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[\"alloc\", \"std\"]","declared_features":"[\"alloc\", \"default\", \"docsrs\", \"std\"]","target":15366292972967833352,"profile":10243973527296709326,"path":8654824742148661146,"deps":[[889836035008422344,"memchr",false,9740610791944545871],[10953957149292187054,"minimal_lexical",false,10440926944818796021]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/nom-a2bc6cd6fdeb8f4e/dep-lib-nom","checksum":false}}],"rustflags":[],"metadata":9858338621379386705,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
a9e4deec04dec88f

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":2579419865376758268,"profile":10243973527296709326,"path":11920449365159802867,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/option-ext-6f7fa96f25d92544/dep-lib-option_ext","checksum":false}}],"rustflags":[],"metadata":13021374016669566089,"config":2202906307356721367,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1,7 @@
{"$message_type":"diagnostic","message":"unresolved import `directories`","code":{"code":"E0432","explanation":"An import was unresolved.\n\nErroneous code example:\n\n```compile_fail,E0432\nuse something::Foo; // error: unresolved import `something::Foo`.\n```\n\nIn Rust 2015, paths in `use` statements are relative to the crate root. To\nimport items relative to the current and parent modules, use the `self::` and\n`super::` prefixes, respectively.\n\nIn Rust 2018 or later, paths in `use` statements are relative to the current\nmodule unless they begin with the name of a crate or a literal `crate::`, in\nwhich case they start from the crate root. As in Rust 2015 code, the `self::`\nand `super::` prefixes refer to the current and parent modules respectively.\n\nAlso verify that you didn't misspell the import name and that the import exists\nin the module from where you tried to import it. Example:\n\n```\nuse self::something::Foo; // Ok.\n\nmod something {\n pub struct Foo;\n}\n# fn main() {}\n```\n\nIf you tried to use a module from an external crate and are using Rust 2015,\nyou may have missed the `extern crate` declaration (which is usually placed in\nthe crate root):\n\n```edition2015\nextern crate core; // Required to use the `core` crate in Rust 2015.\n\nuse core::any;\n# fn main() {}\n```\n\nSince Rust 2018 the `extern crate` declaration is not required and\nyou can instead just `use` it:\n\n```edition2018\nuse core::any; // No extern crate required in Rust 2018.\n# fn main() {}\n```\n"},"level":"error","spans":[{"file_name":"src/main.rs","byte_start":28,"byte_end":39,"line_start":2,"line_end":2,"column_start":5,"column_end":16,"is_primary":true,"text":[{"text":"use directories::UserDirs;","highlight_start":5,"highlight_end":16}],"label":"you might be missing crate `directories`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"consider importing the `directories` crate","code":null,"level":"help","spans":[{"file_name":"src/main.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"extern crate directories;\n","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror[E0432]\u001b[0m\u001b[0m\u001b[1m: unresolved import `directories`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/main.rs:2:5\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m2\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0muse directories::UserDirs;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9myou might be missing crate `directories`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing the `directories` crate\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m1\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ extern crate directories;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\n"}
{"$message_type":"diagnostic","message":"unresolved import `clearscreen`","code":{"code":"E0432","explanation":"An import was unresolved.\n\nErroneous code example:\n\n```compile_fail,E0432\nuse something::Foo; // error: unresolved import `something::Foo`.\n```\n\nIn Rust 2015, paths in `use` statements are relative to the crate root. To\nimport items relative to the current and parent modules, use the `self::` and\n`super::` prefixes, respectively.\n\nIn Rust 2018 or later, paths in `use` statements are relative to the current\nmodule unless they begin with the name of a crate or a literal `crate::`, in\nwhich case they start from the crate root. As in Rust 2015 code, the `self::`\nand `super::` prefixes refer to the current and parent modules respectively.\n\nAlso verify that you didn't misspell the import name and that the import exists\nin the module from where you tried to import it. Example:\n\n```\nuse self::something::Foo; // Ok.\n\nmod something {\n pub struct Foo;\n}\n# fn main() {}\n```\n\nIf you tried to use a module from an external crate and are using Rust 2015,\nyou may have missed the `extern crate` declaration (which is usually placed in\nthe crate root):\n\n```edition2015\nextern crate core; // Required to use the `core` crate in Rust 2015.\n\nuse core::any;\n# fn main() {}\n```\n\nSince Rust 2018 the `extern crate` declaration is not required and\nyou can instead just `use` it:\n\n```edition2018\nuse core::any; // No extern crate required in Rust 2018.\n# fn main() {}\n```\n"},"level":"error","spans":[{"file_name":"src/menu.rs","byte_start":28,"byte_end":39,"line_start":2,"line_end":2,"column_start":5,"column_end":16,"is_primary":true,"text":[{"text":"use clearscreen::clear;","highlight_start":5,"highlight_end":16}],"label":"you might be missing crate `clearscreen`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"consider importing the `clearscreen` crate","code":null,"level":"help","spans":[{"file_name":"src/main.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"extern crate clearscreen;\n","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror[E0432]\u001b[0m\u001b[0m\u001b[1m: unresolved import `clearscreen`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/menu.rs:2:5\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m2\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0muse clearscreen::clear;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9myou might be missing crate `clearscreen`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing the `clearscreen` crate\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/main.rs:1:1\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m1\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ extern crate clearscreen;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\n"}
{"$message_type":"diagnostic","message":"unresolved import `clearscreen`","code":{"code":"E0432","explanation":"An import was unresolved.\n\nErroneous code example:\n\n```compile_fail,E0432\nuse something::Foo; // error: unresolved import `something::Foo`.\n```\n\nIn Rust 2015, paths in `use` statements are relative to the crate root. To\nimport items relative to the current and parent modules, use the `self::` and\n`super::` prefixes, respectively.\n\nIn Rust 2018 or later, paths in `use` statements are relative to the current\nmodule unless they begin with the name of a crate or a literal `crate::`, in\nwhich case they start from the crate root. As in Rust 2015 code, the `self::`\nand `super::` prefixes refer to the current and parent modules respectively.\n\nAlso verify that you didn't misspell the import name and that the import exists\nin the module from where you tried to import it. Example:\n\n```\nuse self::something::Foo; // Ok.\n\nmod something {\n pub struct Foo;\n}\n# fn main() {}\n```\n\nIf you tried to use a module from an external crate and are using Rust 2015,\nyou may have missed the `extern crate` declaration (which is usually placed in\nthe crate root):\n\n```edition2015\nextern crate core; // Required to use the `core` crate in Rust 2015.\n\nuse core::any;\n# fn main() {}\n```\n\nSince Rust 2018 the `extern crate` declaration is not required and\nyou can instead just `use` it:\n\n```edition2018\nuse core::any; // No extern crate required in Rust 2018.\n# fn main() {}\n```\n"},"level":"error","spans":[{"file_name":"src/menu.rs","byte_start":52,"byte_end":63,"line_start":3,"line_end":3,"column_start":5,"column_end":16,"is_primary":true,"text":[{"text":"use clearscreen;","highlight_start":5,"highlight_end":16}],"label":"no `clearscreen` in the root","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror[E0432]\u001b[0m\u001b[0m\u001b[1m: unresolved import `clearscreen`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/menu.rs:3:5\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m3\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0muse clearscreen;\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mno `clearscreen` in the root\u001b[0m\n\n"}
{"$message_type":"diagnostic","message":"variable does not need to be mutable","code":{"code":"unused_mut","explanation":null},"level":"warning","spans":[{"file_name":"src/project_controls.rs","byte_start":2620,"byte_end":2637,"line_start":71,"line_end":71,"column_start":9,"column_end":26,"is_primary":true,"text":[{"text":" let mut customer_name = String::new();","highlight_start":9,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`#[warn(unused_mut)]` on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove this `mut`","code":null,"level":"help","spans":[{"file_name":"src/project_controls.rs","byte_start":2620,"byte_end":2624,"line_start":71,"line_end":71,"column_start":9,"column_end":13,"is_primary":true,"text":[{"text":" let mut customer_name = String::new();","highlight_start":9,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: variable does not need to be mutable\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/project_controls.rs:71:9\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m71\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m let mut customer_name = String::new();\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m----\u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^^\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mhelp: remove this `mut`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m= \u001b[0m\u001b[0m\u001b[1mnote\u001b[0m\u001b[0m: `#[warn(unused_mut)]` on by default\u001b[0m\n\n"}
{"$message_type":"diagnostic","message":"variable does not need to be mutable","code":{"code":"unused_mut","explanation":null},"level":"warning","spans":[{"file_name":"src/project_controls.rs","byte_start":2663,"byte_end":2679,"line_start":72,"line_end":72,"column_start":9,"column_end":25,"is_primary":true,"text":[{"text":" let mut project_name = String::new();","highlight_start":9,"highlight_end":25}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove this `mut`","code":null,"level":"help","spans":[{"file_name":"src/project_controls.rs","byte_start":2663,"byte_end":2667,"line_start":72,"line_end":72,"column_start":9,"column_end":13,"is_primary":true,"text":[{"text":" let mut project_name = String::new();","highlight_start":9,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: variable does not need to be mutable\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/project_controls.rs:72:9\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m72\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m let mut project_name = String::new();\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m----\u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mhelp: remove this `mut`\u001b[0m\n\n"}
{"$message_type":"diagnostic","message":"aborting due to 3 previous errors; 2 warnings emitted","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to 3 previous errors; 2 warnings emitted\u001b[0m\n\n"}
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0432`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0432`.\u001b[0m\n"}

View File

@@ -0,0 +1 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":2139575506939114894,"profile":11983525691607113661,"path":10602529704205407992,"deps":[[7608783394445712223,"fs_extra",false,7681762393121676691],[10212947688942307828,"directories",false,17175249592208382311],[16328207002492827064,"clearscreen",false,17610091363198549210]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/pentest_tool-071f5adbd2d4941c/dep-test-bin-pentest_tool","checksum":false}}],"rustflags":[],"metadata":7797948686568424061,"config":2202906307356721367,"compile_kind":0}

Some files were not shown because too many files have changed in this diff Show More