54 Commits
2.0 ... 3.1.1

Author SHA1 Message Date
pyro57000
12e5ab38d2 bumped the version in the cargo.toml file 2025-04-22 12:46:23 -05:00
pyro57000
f2370e463d added help function to cli 2025-04-22 12:42:38 -05:00
pyro57000
92dd9766b8 refactored for CLI!!! 2025-04-22 12:10:45 -05:00
pyro57000
dbbae0eb4e added a function to parse your host notes and
generate the attack notes based off of them.
2025-04-16 17:28:39 -05:00
pyro57000
2346988e23 added an option to parse cs portscann output 2025-04-15 13:08:48 -05:00
pyro57000
5bfa645b3d added a url for the obsidian notes of the current
project, and to get the vault name from the user
at install.
2025-04-09 10:42:00 -05:00
pyro57000
012ba517ab added a function to info_controls that parses
GatherContacts output and prints them to the
console as well as saves them to both a text file
in the /pentest/working directory as well as your
notes in a password_enumeration.md file.
2025-04-08 12:48:07 -05:00
pyro57000
649dad5e79 chaged some working for the menu 2025-04-07 09:03:25 -05:00
pyro57000
2e839adccf Fixed the installer on Kali linux 2025-04-05 17:49:16 -05:00
pyro57000
fc316c2a71 Completely re-wrote the install function.
Trying to get this working on default kali.
2025-04-04 20:17:35 -05:00
pyro57000
31dd862579 fixed logic for configuring distrobox during
install, and fixing some functions in info_controls
They may not be quite ready yet.
2025-04-01 11:41:24 -05:00
pyro57000
b85d0e5d79 added some logic to give you some time to
enter the sudo password when required for
cobalt strike.
2025-03-27 11:49:53 -05:00
pyro57000
477ac6e360 Added logic and settings for enabling fingerprint
authentication within distro box
2025-03-19 14:52:21 -05:00
pyro57000
fe6524016f added a check to make sure cobalt strike exists
before spawning a thread.
2025-03-13 15:27:15 -05:00
pyro57000
967052a4e2 cleaned up un-needed library imports from
box_controls.
2025-03-13 15:03:14 -05:00
pyro57000
2796d31f14 added logic to launch bloodhound with the
distrobox.
2025-03-13 15:02:01 -05:00
pyro57000
b137e0c34d switched the cobalt strike command to be
.output instead of .status to prevent
it from locking you out of returning to the
main menu.
2025-03-12 12:52:02 -05:00
pyro57000
8a1dca30e1 added logic to copy the cobaltstrike
folder into your project directory
and an option to launch that cobaltstrike
instance within the distrobox of your project
this should help keep cobalt strike data separate
also took a stab at cleaning up the left over
folders in the upcomming files and notes directories
the files folder cleans up now, but the notes folder
still needs work.
2025-03-12 12:48:21 -05:00
pyro57000
854feb2e2a added install logic to configure distrobox
to not pull the container image always.
this should save space, and fix cloning on
universal blue distros.
2025-03-12 10:50:37 -05:00
pyro57000
bfa766a2c3 fixed the new folders not being created first 2025-03-12 09:56:54 -05:00
pyro57000
f7bdd0ad8a fixed promotion function to use the project name
folder as well!
2025-03-12 09:49:15 -05:00
pyro57000
16706f8f6d fixed some stuff with box creation. 2025-03-12 09:39:19 -05:00
pyro57000
b6ec849b36 added some ideas for future development 2025-03-06 12:22:54 -06:00
pyro57000
69f5a4bd78 added stopping the template box to ensure
that cloning operations works
2025-03-06 11:53:11 -06:00
pyro57000
cad1f9d51c removed one redundant line 2025-03-06 09:24:33 -06:00
pyro57000
837012d163 fixed note folder creation with new pentest option 2025-03-06 09:22:15 -06:00
pyro57000
4dba68cdcf refactor for upcomming project management 2025-03-05 14:56:17 -06:00
pyro57000
7765640e0e refactor for managing upcoming and current
projects!
2025-03-05 14:55:56 -06:00
pyro57000
d50625167b added --init to distrobox creation
this will allow us to do things like docker
inside of distroboxes
2025-02-20 13:20:02 -06:00
pyro57000
a798e39461 did the distrobox stuff 2025-02-20 13:09:12 -06:00
pyro57000
4e1ab4c30f split making a distrobox into its own function
this will allow us to write more functions
like the newly added one to re-create the
current project's distrobox
2025-02-20 13:08:20 -06:00
pyro57000
ac037a15a9 fixed the start_pentest function 2025-02-13 14:14:00 -06:00
Pyro57000
345124baf1 Update README.md 2025-01-21 10:57:15 -06:00
Pyro57000
a9a451a8cf Update ToDo.md 2025-01-21 10:52:12 -06:00
Pyro57000
7081280247 Update ToDo.md 2025-01-21 10:51:57 -06:00
Pyro57000
2d97e81920 Create ToDo.md 2025-01-21 10:51:28 -06:00
pyro57000
761f71c6c1 modified the install to avoid the newlines
in folder names

added hash cracking function, though this doesn't
work yet...
2025-01-21 10:31:03 -06:00
pyro57000
882afe0f67 added logic to save already sprayed passwords
based on passwordspray markdown file.
2025-01-16 13:43:08 -06:00
pyro57000
1f47ff8229 just cleaned up a mutable 2025-01-15 15:58:11 -06:00
pyro57000
f40c0e31c1 added logic to save and come back to a password
spray.
2025-01-15 13:56:09 -06:00
pyro57000
bf95a375fb added logic to do msolspray as well!
this isn't tested very well, but give it a shot!
2025-01-15 13:28:12 -06:00
pyro57000
00e19bc1b4 added logic to display correct command for
user as pass sprays.
2025-01-15 12:07:41 -06:00
pyro57000
fd64caefc1 forgot to add execute-assembly to one line 2025-01-09 14:13:44 -06:00
pyro57000
e8b557bb4e edited install function to actually work right
the bell file was trying to be written
too soon, this has been fixed.
2025-01-09 14:08:46 -06:00
pyro57000
b2822a614a added password spray help funciton, and a bell.
also added downloading the bell file to the install
2025-01-09 13:55:36 -06:00
Pyro57000
37a942b8b3 Add files via upload 2025-01-09 13:17:52 -06:00
Pyro57000
a56e2f990c Create credits.txt 2025-01-09 13:17:20 -06:00
pyro57000
c950b02cbe removed target directory from git, this is used
for compilation and not required for source.
2024-12-19 09:58:59 -06:00
pyro57000
02022fc160 added command to build the cobalt strike
portscan command based off of the scope
in general notes
2024-12-19 09:54:12 -06:00
Pyro57000
ac3b4c32b8 Update README.md
added descriptions and example for the tools directory
2024-12-18 13:15:13 -06:00
pyro57000
773ba644a1 fixed notes about hour tracking 2024-12-18 13:03:41 -06:00
pyro57000
4f77bab6b6 fixed cargo.toml to have the right name 2024-12-18 13:00:47 -06:00
pyro57000
33555976a4 fixed typo 2024-12-18 12:59:57 -06:00
pyro57000
34d0c4ed09 added a bit of error handling
and resolved some compiler warnings
2024-12-18 12:57:06 -06:00
2042 changed files with 4332 additions and 17641 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/pentest_tool/target

View File

@@ -3,6 +3,8 @@ A quick little tool to manage which projects you're on and manage distrobox cont
In order to use this tool you'll want to have distrobox set up and have a "template" box you've created that has all yoru tools installed and what not, you'll likely also want to have a folder full of your other custom tools that you get from git hub, this makes it easier. In order to use this tool you'll want to have distrobox set up and have a "template" box you've created that has all yoru tools installed and what not, you'll likely also want to have a folder full of your other custom tools that you get from git hub, this makes it easier.
The distroboxes it sets up will have the prjoect files folder for the project mounted at /pentest and folder you use for custom tools (like the ones you clone from github) at /tools so getting to your files for the project is as easy as `cd /pentest`!
# General Use case and flow # General Use case and flow
I'm not very good at organization. In order to keep track of all the things needed for pentest engagements and keep client data separated from other client data I worte this tool to do it for me. Basically I have a distrobox for each engagement, a folder to keep files related to the engagement, and a separate folder full of my markdown notes for the engagement. An example is below I'm not very good at organization. In order to keep track of all the things needed for pentest engagements and keep client data separated from other client data I worte this tool to do it for me. Basically I have a distrobox for each engagement, a folder to keep files related to the engagement, and a separate folder full of my markdown notes for the engagement. An example is below
@@ -42,14 +44,20 @@ Current engagements: client1 internal pentest, client 2 internal pentest
- attack_notes.md - attack_notes.md
- upcomming - upcomming
- writing - writing
- tools
- bloodhound-linux-x86_64_4.3.1
- bofhound
- burp_extensions
- ek45
- etc
This tool automatically creates the file structure, and if you use the start_pentest option populates the markdown note files with the templates I use. This tool automatically creates the file structure, and if you use the start_pentest option populates the markdown note files with the templates I use.
For example if I get a new internal pentest engagement for client 3 but it hasn't started yet I'll start by creating the folder and note structure using option 4 in the menu system. This would create the folder structure and notes templates in the /home/pyro/pentests/upcomming/client3/internal_pentest and /home/pyro/notes/upcomming/client3/internal_pentest folders respectively. It does not create the distrobox or add it to the tracked project list yet. For example if I get a new internal pentest engagement for client 3 but it hasn't started yet I'll start by creating the folder and note structure using option 4 in the menu system. This would create the folder structure and notes templates in the /home/pyro/pentests/upcomming/client3/internal_pentest and /home/pyro/notes/upcomming/client3/internal_pentest folders respectively. It does not create the distrobox, but it does add it to the list of tracked projects, with a status of upcomming.
Once the engagement starts I'd run option 6 "import new project - and set up new distrobox" from the menu system. It will ask if you have an existing folder structure to copy over, since I created that structure before with option 4 I would answer y, yes, or anything with the letter y in it. Then it prompts you to past the path to the folders to copy over. Here I browse to /home/pyro/pentests/upcomming in dolphin. I right click on the client3 folder and select "copy path" and then paste that into the terminal. I repeat this process for the notes folder. Once the engagement starts I'd run option 9 to promote a project from upcomming status to current status. This will automatically copy the needed files over, and will clean up the empty directory in the upcomming files directory, but the empty folder in the upcomming notes folder is still not cleaning correctly, I'm working on that.
It then attempts to guess the client name and project name based on the folder structure, and asks you to confirm. If its correct the project object will be created, the folders will be copied, and a new distrobox will be set up. If it is not correct it will prompt you to correct it, then copy the files, create a new project object, and setup a new distrobox. At the moment it is not very fault tollerant and will fail if there is an existing folder with the same name. I plan to fix that later, but haven't gotten around to it yet. Once the distro box is set up (this takes a while) it will return you to the main menu. It then will create a new distrobox and ask you if you need to set up cobalt strike for the project. if so it'll ask you for the path to your cobalt strike, it'll copy that into the project files folder so that you can run it if needed.
During the test I use the menu system to spawn new terminals in the distrobox created for the engagement, use the various file generation options to get data in easily usable format for attack operations, etc. During the test I use the menu system to spawn new terminals in the distrobox created for the engagement, use the various file generation options to get data in easily usable format for attack operations, etc.
@@ -67,7 +75,8 @@ Once the project is done and I'm ready to clean up the distrobox I use option 7
1. clone this repository `git clone https://github.com/Pyro57000/pentest_tool.git` 1. clone this repository `git clone https://github.com/Pyro57000/pentest_tool.git`
2. cd into the nested "pentest_tool" folder `cd pentest_tool/pentest_tool` 2. cd into the nested "pentest_tool" folder `cd pentest_tool/pentest_tool`
3. use cargo to build the release binary `cargo build --release` 3. use cargo to build the release binary `cargo build --release`
4. follow the same installation instructions, skipping the step where you download the release binary. 4. copy the compiled binary to a folder on your path `sudo cp ./target/release/pentest_tool /usr/bin/`
5. follow the same installation instructions, skipping the step where you download the release binary.

29
ToDo.md Normal file
View File

@@ -0,0 +1,29 @@
# planned features
1.) finish hash cracking with a dedictated cracking rig code.
2.) cracte hash cracking with current computer code.
4.) create code that moves projects to a "writing" state and folder.
5.) create code that tracks "current, upcomming, and writing" states, maybe automatic zipping of folders after writing is done?
upcoming and current are done, but need to add writing yet...
# Unplanned, but would be cool
1.) create a "server" and "Client" infrastructure that can help manage the distrobox clients and the main server
2.) maybe expand this server client model to interact with cracking rigs and what not.
3.) implment a function to searchsploit and copy wanted exploits to the project folder.
4.) implement a function to execute those copied exploits.
5.) add a "client" model for compromised internal hosts, this would likely need to be a server from a networking perspective that listens on 127.0.0.1 and then have the main interface connect to that over a proxy to run jobs. a good starting point would be to run some of our enumeration commands and scripts and save the output to the notes directly.
6.) add the ability to interact with the cobalt strike beacons... would need to learn agressor script... what a pain...
# NOTE
if you wish to contribute, please do! just fix a bug or implement any of the above features and make a pull request!!
I'll keep plugging away as I have time throughout my days as well.

2019
pentest_tool/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,14 @@
[package] [package]
name = "pentest_tool2" name = "pentest_tool"
version = "0.1.0" version = "3.1.1"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
chrono = "0.4.39"
clearscreen = "3.0.0" clearscreen = "3.0.0"
directories = "5.0.1" directories = "5.0.1"
fs_extra = "1.3.0" fs_extra = "1.3.0"
futures-io = { version = "0.2.0-beta" }
reqwest = {version = "0.12.12", features = ["blocking", "json"]}
rodio = "0.20.1"
walkdir = "2.5.0"

Binary file not shown.

View File

@@ -1,5 +1,11 @@
use std::process; use std::process::Command;
use crate::Project; use std::{path::PathBuf, process};
use std::env;
use std::fs;
use std::io::Write;
use std::thread::{self, JoinHandle};
use std::time::Duration;
use crate::{get_user_input, Project};
pub fn stop_all_boxes(projects: &Vec<Project>){ pub fn stop_all_boxes(projects: &Vec<Project>){
let mut problem_childs: Vec<Project> = Vec::new(); let mut problem_childs: Vec<Project> = Vec::new();
@@ -37,6 +43,10 @@ pub fn project_standalone_terminal(project: Project, mut terminal: String){
if terminal.contains("profile"){ if terminal.contains("profile"){
profile = true; profile = true;
} }
if terminal.contains("!!!"){
let terminal_launch_cmd = format!("distrobox enter --root {}", &project.boxname);
terminal = terminal.replace("!!!", &terminal_launch_cmd);
}
let terminal_vec:Vec<&str> = terminal.split(" ").collect(); let terminal_vec:Vec<&str> = terminal.split(" ").collect();
let mut terminal_start = process::Command::new(terminal_vec[0]); let mut terminal_start = process::Command::new(terminal_vec[0]);
let mut first = true; let mut first = true;
@@ -63,3 +73,214 @@ pub fn project_standalone_terminal(project: Project, mut terminal: String){
pub fn project_inline_terminal(project: Project){ 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"); 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");
} }
pub fn make_box(project: &Project, tools_dir: &PathBuf, boxtemplate: &String, new: bool, fingerprint: bool){
println!("stopping template box to ensure we can clone it!");
let stop_result = Command::new("distrobox").arg("stop").arg("--root").arg(boxtemplate).status();
if stop_result.is_err(){
println!("error stopping template!");
}
if !new{
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!");
}
}
let mut box_name_path = project.files_folder.clone();
let box_name = format!("{}_{}", &boxtemplate, &project.customer);
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", &project.files_folder.display());
let toold_volume = format!("{}:/tools:rw", tools_dir.display());
let mut distrobox_cmd = String::new();
if fingerprint{
println!("creating box with shared volume for fingerprints... note you will still need to set up fingerprint authentication in your distrobox");
println!("\nfor example, you may need to install fprintd and imagemegick on your template box, and set up the pam files to utilize finger print auth");
println!("\nsee https://wiki.archlinux.org/title/Fprint for more information and instructions");
distrobox_cmd = format!("distrobox create --root --init --clone {} --volume {} --volume {} --volume /var/lib/fprint:/var/lib/fprint:rw --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
}
else {
distrobox_cmd = format!("distrobox create --root --init --clone {} --volume {} --volume {} --name {}", boxtemplate, toold_volume, pentest_volume, box_name);
}
println!("{}", distrobox_cmd);
let distrobox_cmd_vec: Vec<&str> = distrobox_cmd.split_whitespace().collect();
let mut distrobox_cmd_build = process::Command::new("distrobox");
let mut first = true;
for word in &distrobox_cmd_vec{
if first == false{
println!("adding {} as an argument for the creation command...", word);
distrobox_cmd_build.arg(word);
}
else{
first = false;
}
}
let distrobox_result = distrobox_cmd_build.status();
if distrobox_result.is_err(){
println!("oooof we ran into trouble creating your distrobox!!");
println!("try creating it manually!");
println!("{}", distrobox_cmd);
}
else{
if distrobox_result.unwrap().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();
if distrobox_start_result.is_err(){
println!("ooof did not start successfully try entering it yoruself");
println!("distrobox enter --root {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
}
else if distrobox_start_result.unwrap().success(){
println!("distrobox was started as well!!!! good job me!");
}
else {
println!("ooof did not start successfully try entering it yoruself");
println!("distrobox enter --root {} -- sudo -s ln -sf /pentest/boxname /etc/boxname", &box_name);
}
}
}
}
pub fn clean_unused_boxes(projects: &Vec<Project>, boxtemplate: &String) -> Option<JoinHandle<()>>{
println!("starting template box: {}", boxtemplate);
let template_status = process::Command::new("distrobox").arg("enter").arg("--root").arg(boxtemplate).arg("--").arg("exit").status();
if template_status.is_err(){
let start_error = template_status.err().unwrap();
println!("OOOF issue starting template box, cancelling...");
println!("ERROR: {}", start_error);
return None;
}
println!("starting project boxes...");
for project in projects{
if project.stage.contains("current"){
let start_status = process::Command::new("distrobox").arg("enter").arg("--root").arg(&project.boxname).arg("--").arg("exit").status();
if start_status.is_err(){
let start_error = start_status.err().unwrap();
println!("OOOF issue starting {}, cancelling...", project.boxname);
println!("ERROR: {}", start_error);
return None;
}
}
}
println!("pruning unused containers...");
let handle = thread::spawn(move ||{
let spawn_result = process::Command::new("sudo").arg("podman").arg("system").arg("prune").arg("-a").arg("-f").output();
if spawn_result.is_err(){
let spawn_error = spawn_result.err().unwrap();
println!("oof trouble spawing prune command!, try manually");
println!("ERROR: {}", spawn_error);
}
println!("PRUNING COMPLETE!");
});
thread::sleep(Duration::from_secs(3));
println!("this will take some time, but its running on a different thread so you can continue working!");
return Some(handle);
}
pub fn launch_cobalt_strike(project: Project) -> Option<JoinHandle<()>>{
let mut check_path = PathBuf::new();
check_path.push(&project.files_folder);
check_path.push("cobaltstrike/client");
if check_path.as_path().exists() == false{
println!("looks like you don't have cobalt strike set up on this beacon... try copying your cobalt strike folder to the following path!");
println!("{}", &check_path.display());
return None;
}
println!("you will need to enter your sudo password shortly, when you've done that successfully please type END and hit enter");
let handle = thread::spawn(move ||{
let mut cs_dir = PathBuf::new();
cs_dir.push(project.files_folder);
cs_dir.push("cobaltstrike/client");
let cd_res = env::set_current_dir(&cs_dir);
if cd_res.is_ok(){
let cobalt_strike_launch_result = Command::new("distrobox")
.arg("enter")
.arg("--root").arg(project.boxname)
.arg("--")
.arg("./cobaltstrike")
.output();
if cobalt_strike_launch_result.is_err(){
let error = cobalt_strike_launch_result.err().unwrap();
println!("error launching cobalt strike!");
println!("{}", error);
}
}
});
thread::sleep(Duration::from_secs(5));
loop{
let end = get_user_input("please enter END if the sudo password was enter correctly!");
if end == "END".to_string(){
break;
}
}
return Some(handle);
}
pub fn launch_bloodhound_gui(project: Project) -> Option<JoinHandle<()>>{
let mut bloodhound_command = String::new();
let version_response = get_user_input("do you want to use a specific bloodhound version?");
if version_response.to_lowercase().contains("y"){
bloodhound_command = get_user_input("path to the bloodhound binary you want to use?");
}
else{
bloodhound_command = "bloodhound".to_owned();
}
let mut neo4j_started = false;
let neo4jstart_res = Command::new("distrobox")
.arg("enter")
.arg("--root")
.arg(&project.boxname)
.arg("--")
.arg("sudo")
.arg("neo4j")
.arg("start")
.status();
if neo4jstart_res.is_err(){
let error = neo4jstart_res.err().unwrap();
println!("errror starting neo4j...");
println!("{}", error);
}
else{
neo4j_started = true;
thread::sleep(Duration::from_secs(3));
}
if neo4j_started == false{
println!("review previous errors, not spawning bloodhound thread...");
return None;
}
let handle = thread::spawn(move ||{
let bloodhound_res = Command::new("distrobox")
.arg("enter")
.arg("--root")
.arg(&project.boxname)
.arg("--")
.arg(bloodhound_command)
.output();
if bloodhound_res.is_err(){
let error = bloodhound_res.err().unwrap();
println!("error starting bloodhound!");
println!("{}", error);
}
});
return Some(handle);
}

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

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,130 +1,277 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::env::home_dir;
use std::fs::{File, create_dir_all, remove_dir_all};
use std::io::{read_to_string, Read};
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::io::stdin;
use std::process; use std::io::copy;
use std::process::Command;
use std::time::Duration;
use reqwest::blocking::get;
use std::{path::Path, path::PathBuf};
use std::{process, thread};
use std::process::exit;
use directories::UserDirs;
use crate::get_user_input;
pub fn install(config_path: &PathBuf){ pub fn install(config_path: &PathBuf){
let mut _terminal_commands = HashMap::from([ let mut _terminal_commands = HashMap::from([
("konsole", "konsole -e !!!"), ("kde", "konsole -e !!!"),
("plasma", "konsole -e !!!"),
("gnome", "gnome-terminal -- bash !!!"), ("gnome", "gnome-terminal -- bash !!!"),
("xfce", "xfce4-terminal --execute '!!!'"), ("xfce", "xfce4-terminal --execute '!!!'"),
("alacritty", "alacritty -e !!!"), ("alacritty", "alacritty -e !!!"),
]); ]);
let mut folder_creation = true;
let current_projects = PathBuf::from(get_user_input("path to store your active projects?"));
let current_notes = PathBuf::from(get_user_input("path to store your active project notes?"));
let upcoming_projects = PathBuf::from(get_user_input("path to store your upcomming projects?"));
let upcoming_notes = PathBuf::from(get_user_input("path to store your upcomming project notes?"));
let tools = PathBuf::from(get_user_input("path where you store your custom tools (like from github and places)?"));
let mut vault_name = String::new();
let folders = vec![&current_projects, &current_notes, &upcoming_projects, &upcoming_notes, &tools];
let mut config_folder_path: PathBuf = config_path.clone(); let mut config_folder_path: PathBuf = config_path.clone();
config_folder_path.pop(); config_folder_path.pop();
let mut password_path = config_folder_path.clone();
password_path.push("password_spray.md");
let mut projects_conf_path = config_folder_path.clone(); let mut projects_conf_path = config_folder_path.clone();
let mut bell_file_path = config_folder_path.clone();
let del_on_fail = config_folder_path.clone(); let del_on_fail = config_folder_path.clone();
projects_conf_path.push("projects.conf"); projects_conf_path.push("projects.conf");
fs::create_dir_all(&config_folder_path).expect("error creating config dir"); create_dir_all(&config_folder_path).expect("error creating config dir");
let mut config_file = fs::File::create(config_path).expect("error creating file"); bell_file_path.push("bell.mp3");
let mut projects_conf_file = fs::File::create(projects_conf_path).expect("error creating projects config file"); let bell_sound_url = "https://github.com/Pyro57000/pentest_tool/raw/refs/heads/main/resources/bell.mp3";
projects_conf_file.write_all(b"customer:name:notes:files:active:box_name\n").expect("error writing default project info"); let response = get(bell_sound_url).unwrap();
let mut terminal_response = String::new(); let response_length = response.content_length().unwrap_or(0);
let mut notes_response = String::new(); let mut bell_file = File::create(bell_file_path).unwrap();
let mut files_response = String::new(); copy(&mut response.take(response_length), &mut bell_file).unwrap();
let mut tools_response = String::new(); println!("bell notification tone sucessfully downloaded!");
let mut template_name = String::new(); println!("creating new folders if needed...");
let mut have_template = String::new(); for folder in &folders{
println!("terminal you use? (example: konsole, xfce, gnome, etc)"); if !Path::exists(folder){
std::io::stdin().read_line(&mut terminal_response).unwrap(); let create_res = create_dir_all(folder);
let mut _terminal_command = String::new(); if create_res.is_err(){
if terminal_response.contains("konsole"){ let error = create_res.err().unwrap();
let mut response_buffer = String::new(); println!("error creating folder {}", folder.display());
println!("do you already have a custom profile setup?"); println!("{}", error);
println!("this is pretty specific to pyro's setup, I do some special sauce for my konsole stuff"); println!("you'll need to create this manually after the install is done!");
std::io::stdin().read_line(&mut response_buffer).unwrap(); folder_creation = false;
if response_buffer.to_lowercase().contains("y"){ }
let mut profile = String::new(); }
println!("konsole profile name?"); }
std::io::stdin().read_line(&mut profile).unwrap(); let tool_volume = format!("{}:/tools:rw", &tools.display());
_terminal_command = format!("konsole --profile {}", profile); println!("sweet, now let's get some distrobox stuff out of the way!");
let distrobox_run_res = Command::new("distrobox").arg("list").arg("--root").output();
if distrobox_run_res.is_err(){
let error = distrobox_run_res.err().unwrap();
println!("Distrobox file was not found!");
println!("This usually means that distrobox is not installed.");
println!("please install distrobox, if you're on kali run `sudo apt install distrobox`");
println!("{}", error);
println!("this project heavily relies on distrobox, as its primarily a distrobox mangement tool.");
println!("cleaning up up configuration folders, please install distrobox and re-run this program.");
let cleanup = remove_dir_all(&del_on_fail);
if cleanup.is_err(){
println!("error cleaning up configuration folder!");
println!("please manually delete {} before re-running this install.", &del_on_fail.display());
exit(1);
}
cleanup.unwrap();
exit(1);
}
let distrobox_output = distrobox_run_res.unwrap().stdout;
let distrobox_string = String::from_utf8_lossy(&distrobox_output);
let mut distrobox_names = Vec::new();
let distrobox_output_lines: Vec<&str> = distrobox_string.split("\n").collect();
for line in distrobox_output_lines{
if line.len() > 1{
let name = line.split(" | ").collect::<Vec<&str>>()[1];
distrobox_names.push(name.to_owned());
}
}
let mut have_box = false;
for name in distrobox_names{
if !name.contains("NAME"){
have_box = true;
println!("{}", name);
}
}
let mut template_box_name = String::new();
if have_box{
template_box_name = get_user_input("Name of the distrobox you want to use as a template?");
}
else{
println!("no exiting distroboxes created!");
println!("let's make one!");
template_box_name = get_user_input("name of the distrobox you want to create?");
println!("review images listed here: https://distrobox.it/compatibility/#containers-distros");
let box_image = get_user_input("image you want to base the template box on?");
let template_box_create_res = Command::new("distrobox")
.arg("create")
.arg("--root")
.arg("--image")
.arg(&box_image)
.arg("--name")
.arg(&template_box_name)
.arg("--init")
.arg("--volume")
.arg(&tool_volume)
.status();
if template_box_create_res.is_err(){
let error = template_box_create_res.err().unwrap();
println!("error creating template box!");
println!("{}", error);
println!("\n\n\nplese create it yourself with the following command.");
println!("\n\ndistrobox create --root --image {}, --name {}, --init --volume {}", &box_image, &template_box_name, &tool_volume);
}
else{
template_box_create_res.unwrap();
}
}
let mut cracking_rig = String::from("nobody@nothing");
let mut rockyou = String::from("n/a");
let mut rule = String::from("n/a");
let cracking_rig_response = get_user_input("do you have a separate machine to crack passwords on? (not the ambush cracking rig)");
if cracking_rig_response.to_lowercase().contains("y"){
let rig_ip = get_user_input("ip address or hostname of your cracking rig?");
let rig_user = get_user_input("username to log into your cracking rig with?");
rockyou = get_user_input("location of rockyou.txt on the cracking rig?");
rule = get_user_input("location of one rule to rule them all on the cracking rig?");
cracking_rig = format!("{}@{}", rig_user, rig_ip);
}
else{
println!("ok free loader");
}
let fingerprint = get_user_input("will you be using fingerprint authentication for your distroboxes?").to_lowercase();
let mut terminal = String::new();
for desktop in _terminal_commands.keys(){
println!("{}", desktop);
}
let desktop_response = get_user_input("do you use any of these desktops?").to_lowercase();
if desktop_response.contains("y"){
let default_response = get_user_input("do you use the default terminal for your desktop?").to_lowercase();
if default_response.contains("y"){
let de = get_user_input("which desktop do you use?");
terminal = _terminal_commands[&de.as_str()].to_owned();
} }
} }
else{ else{
_terminal_command = _terminal_commands[terminal_response.trim_end()].to_owned(); println!("OK, then please enter the command you'd use to launch a new terminal and run a command inside of it, replacing the command with three !s");
println!("for example for konsole you'd enter");
println!("konsole -e !!!");
terminal = get_user_input("");
} }
println!("path to save project notes?"); if terminal.contains("konsole"){
std::io::stdin().read_line(&mut notes_response).unwrap(); println!("do you use a specific profile for your attack boxes?");
println!("path to save project files?"); println!("this is pretty specific to Pyro's setup, so you probably don't");
std::io::stdin().read_line(&mut files_response).unwrap(); if get_user_input("").to_lowercase().contains("y"){
println!("path to folder with your custom tools?"); let profile_name = get_user_input("what is the name of your profile?");
std::io::stdin().read_line(&mut tools_response).unwrap(); terminal = format!("konsole --profile {}", profile_name);
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!("many of the fuctions of this tool assume you're using obsidian or some other markdown editor for note taking");
println!("distrobox template name?"); let obsidian_used = get_user_input("do you use obsidian for your notes?");
std::io::stdin().read_line(&mut template_name).unwrap(); if obsidian_used.to_lowercase().contains("y"){
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()); vault_name = get_user_input("the name of the vault you're going to use?");
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()); let configuration_string = format!("
projects_conf_file.write_all(default_projectline.as_bytes()).expect("error writing default project line"); Project_files:{}
println!("config file generated and saved to {}\n", config_path.display()); Project_notes:{}
println!("please rerun the program"); tools_folder:{}
upcoming_files:{}
upcoming_notes:{}
let config_path = &config_folder_path.clone(); box_template:{}
let mut install_path = config_path.clone(); terminal:{}
let mut password_spray_template_path = install_path.clone(); cracking_rig:{}
install_path.push("new_projects.conf"); rockyou_location:{}
password_spray_template_path.push("passwordspray.md"); rule_location:{}
let password_spray_template_path = install_path.clone(); pass_file:{}
let mut conf_file = fs::File::create(install_path).expect("error creating config file"); fingerprint:{}
let mut project_folder_path = String::new(); vault_name:{}"
let mut porject_note_path = String::new(); , &current_projects.display(), &current_notes.display(), &tools.display(), &upcoming_projects.display(), &upcoming_notes.display(), &template_box_name, &terminal, cracking_rig, rockyou, rule, &password_path.display(), fingerprint, &vault_name);
println!("path to the project folders directory?"); println!("cool everything, all folders and settings have been entered, now let's save this to a config file...");
std::io::stdin().read_line(&mut project_folder_path).expect("error reading project folder from stdin"); thread::sleep(Duration::from_secs(3));
println!("path to the project notes directory"); let mut config_file_res = File::create_new(config_path);
std::io::stdin().read_line(&mut porject_note_path).expect("error reading project note folder form stdin"); if config_file_res.is_err(){
write!(conf_file, "project_folder_path:{} println!("ooof error creating configuration file...");
project_notes_path:{} println!("try creating it manually.");
", project_folder_path.trim_end(), porject_note_path.trim_end()).expect("error writing config file"); println!("copy the following configuration and save it to {}", config_path.display());
let mut passpray_file = fs::File::create(password_spray_template_path).expect("error creating passwordspray file"); print!("{}\n", configuration_string);
write!(passpray_file, " exit(1);
- [ ] useraspass }
- [ ] Seasonyear! let mut config_file = config_file_res.unwrap();
- [ ] Service123! let config_write_res =write!(config_file, "{}", &configuration_string);
- [ ] admin if config_write_res.is_err(){
- [ ] Admin println!("error writing configuration string to the configuration file!");
- [ ] Admin123! println!(" try creating it manually.");
- [ ] admin123 println!("copy the following configuration and save it to {}", &configuration_string);
- [ ] admin1 exit(1);
- [ ] 1234567 }
- [ ] Seasonyear config_write_res.unwrap();
- [ ] seasonyear! println!("nice the configuration file was written correctly!");
- [ ] seasonyear println!("creating project configuration file, and poplulating it with the default project...");
- [ ] COMPANYYEAR! let project_conf_res = File::create_new(&projects_conf_path);
- [ ] COMPANYYEAR if project_conf_res.is_err(){
- [ ] November2024! let error = project_conf_res.err().unwrap();
- [ ] September2024! println!("ooof error creating the projects configuration file.");
- [ ] October2024! println!("try creating it manually!");
- [ ] COMPANYfoundingyear! println!("copy the following configuration and save it to {}", &projects_conf_path.display());
- [ ] COMPANYfoundingyear println!("customer:name:notes:files:active:time:box_name:stage");
- [ ] COMPANYstreetnumber! println!("default:default:{}:{}:yes:{}:current", &current_notes.display(), &current_projects.display(), &template_box_name);
- [ ] COMPANYstreetnumber exit(1);
- [ ] Password }
- [ ] P@ssw0rd let mut project_conf_file = project_conf_res.unwrap();
- [ ] Password1! let project_write_res = write!(project_conf_file, "customer:name:notes:files:active:time:box_name:stage\ndefault:default:{}:{}:yes:{}:current", &current_notes.display(), &current_projects.display(), &template_box_name);
- [ ] Password123! if project_write_res.is_err(){
- [ ] Passwordyear! println!("error writing project config file.");
- [ ] P@55w0rd exit(1);
- [ ] Service }
- [ ] Service! project_write_res.unwrap();
- [ ] Serviceyear!").expect("error writing password spray template"); let password_file_res = File::create_new(password_path);
std::process::exit(0); if password_file_res.is_err(){
println!("error creating password spray file");
exit(1);
}
let mut password_file = password_file_res.unwrap();
let password_write_res = write!(password_file, "
- [ ] useraspass
- [ ] Seasonyear!
- [ ] Service123!
- [ ] 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!
");
if password_write_res.is_err(){
println!("error writing password file");
exit(1);
}
password_write_res.unwrap();
println!("install completed successfully!");
println!("re-run this to launch!");
} }

View File

@@ -1,6 +1,8 @@
use std::path::PathBuf; use std::{io::stdin, path::PathBuf, process::Command};
use directories::UserDirs; use directories::UserDirs;
use std::fs; use reqwest::Response;
use std::process::exit;
use std::fs::{self, File};
#[derive(Clone)] #[derive(Clone)]
pub struct Project{ pub struct Project{
@@ -10,6 +12,7 @@ pub struct Project{
pub files_folder: PathBuf, pub files_folder: PathBuf,
pub active: bool, pub active: bool,
pub boxname: String, pub boxname: String,
pub stage: String,
pub id: i32, pub id: i32,
} }
@@ -19,6 +22,51 @@ mod project_controls;
mod box_controls; mod box_controls;
mod info_controls; mod info_controls;
mod start_pentest; mod start_pentest;
mod cli;
pub fn open_overwrite(path: &PathBuf) -> Option<File>{
let file_create_res = fs::OpenOptions::new().create(true).write(true).open(path);
if file_create_res.is_err(){
let error = file_create_res.err().unwrap();
println!("error opening {} file!", path.display());
println!("{}", error);
return None;
}
else {
let file = file_create_res.unwrap();
return Some(file);
}
}
pub fn open_append(path: &PathBuf) -> Option<File>{
let file_create_res = fs::OpenOptions::new().create(true).append(true).open(path);
if file_create_res.is_err(){
let error = file_create_res.err().unwrap();
println!("error opening {} file!", path.display());
println!("{}", error);
return None;
}
else {
let file = file_create_res.unwrap();
return Some(file);
}
}
pub fn get_user_input(prompt: &str) -> String{
let mut response = String::new();
loop{
println!("{}", prompt);
let result = stdin().read_line(&mut response);
if result.is_err(){
println!("we need input here dummy! try again...");
}
else{
result.unwrap();
break;
}
}
return response.trim_end().to_owned();
}
fn main() { fn main() {
@@ -42,8 +90,23 @@ fn main() {
⠀⠀⠀⠀⢿⡉⠳⡟⣸⠃⠀⠀⠀⠘⢷⣌⠉⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⢿⡉⠳⡟⣸⠃⠀⠀⠀⠘⢷⣌⠉⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠙⢦⣴⠏⠀⠀⠀⠀⠀⠀⠉⠳⠶⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠙⢦⣴⠏⠀⠀⠀⠀⠀⠀⠉⠳⠶⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
"); ");
let user_dirs = UserDirs::new().expect("error getting user directories"); let mut config_path = PathBuf::new();
let mut config_path = user_dirs.home_dir().to_path_buf(); let user_dirs_res = UserDirs::new();
if user_dirs_res.is_none(){
println!("oof couldn't get the config directory the right way, falling back to the stpuid way...");
let get_home_res = Command::new("echo").arg("$HOME").output();
if get_home_res.is_err(){
println!("ooof the stupid way didn't work... this is a bruh moment, gotta fix your environment variabls!!!");
exit(1);
}
let get_home_output = get_home_res.unwrap().stdout;
let home_string = String::from_utf8_lossy(&get_home_output);
config_path.push(home_string.trim());
}
else{
let user_dirs = user_dirs_res.unwrap();
config_path.push(user_dirs.home_dir());
}
config_path.push(".config/pyro_pentest_tool/conf"); config_path.push(".config/pyro_pentest_tool/conf");
if config_path.as_path().exists() == false{ if config_path.as_path().exists() == false{
install::install(&config_path); install::install(&config_path);
@@ -53,6 +116,14 @@ fn main() {
let mut tools_folder = PathBuf::new(); let mut tools_folder = PathBuf::new();
let mut terminal_command = String::new(); let mut terminal_command = String::new();
let mut box_template = String::new(); let mut box_template = String::new();
let mut cracking_rig = String::new();
let mut rockyou = String::new();
let mut rule = String::new();
let mut upcoming_files = PathBuf::new();
let mut upcoming_notes = PathBuf::new();
let mut pass_spray_file = PathBuf::new();
let mut fingerprint = false;
let mut vault_name = String::new();
println!("\nconfig already generated\nloading config file...\n"); println!("\nconfig already generated\nloading config file...\n");
let settings_string = fs::read_to_string(&config_path).expect("error reading config file"); let settings_string = fs::read_to_string(&config_path).expect("error reading config file");
let settings: Vec<&str> = settings_string.split("\n").collect(); let settings: Vec<&str> = settings_string.split("\n").collect();
@@ -63,8 +134,16 @@ fn main() {
"Project_files" => project_base_folder.push(setting_vec[1].trim_end()), "Project_files" => project_base_folder.push(setting_vec[1].trim_end()),
"Project_notes" => project_base_notes.push(setting_vec[1].trim_end()), "Project_notes" => project_base_notes.push(setting_vec[1].trim_end()),
"tools_folder" => tools_folder.push(setting_vec[1].trim_end()), "tools_folder" => tools_folder.push(setting_vec[1].trim_end()),
"upcoming_files" => upcoming_files.push(setting_vec[1].trim_end()),
"upcoming_notes" => upcoming_notes.push(setting_vec[1].trim_end()),
"box_template" => box_template = setting_vec[1].trim_end().to_owned(), "box_template" => box_template = setting_vec[1].trim_end().to_owned(),
"terminal" => terminal_command = setting_vec[1].trim_end().to_owned(), "terminal" => terminal_command = setting_vec[1].trim_end().to_owned(),
"cracking_rig" => cracking_rig = setting_vec[1].trim_end().to_owned(),
"rockyou_location" => rockyou = setting_vec[1].trim_end().to_owned(),
"rule_location" => rule = setting_vec[1].trim_end().to_owned(),
"pass_file"=> pass_spray_file.push(setting_vec[1]),
"fingerprint" => {if setting_vec[1].contains("y"){fingerprint = true}},
"vault_name" => vault_name = setting_vec[1].trim_end().to_owned(),
_ => println!("error unknown setting: {}", setting_vec[0]) _ => println!("error unknown setting: {}", setting_vec[0])
} }
} }
@@ -74,12 +153,15 @@ fn main() {
Note Folders: {} Note Folders: {}
Tools Folder: {} Tools Folder: {}
distrobox template: {} distrobox template: {}
terminal_command: {}\n terminal_command: {}
", project_base_folder.display(), project_base_notes.display(), tools_folder.display(), box_template, terminal_command); cracking_rig: {}\n
upcoming project folders: {}
upcoming project notes: {}
", &project_base_folder.display(), &project_base_notes.display(), &tools_folder.display(), box_template, terminal_command, cracking_rig, &upcoming_files.display(), &upcoming_notes.display());
println!("loading project configs..."); println!("loading project configs...");
let projects = project_controls::get_projects(&config_path); let projects = project_controls::get_projects(&config_path, true);
println!("Enter to start main menu"); 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();
menu::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, cracking_rig, rockyou, rule, &upcoming_files, &upcoming_notes, &pass_spray_file, fingerprint, vault_name);
} }

View File

@@ -1,14 +1,18 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit;
use chrono::Datelike;
use clearscreen::clear; use clearscreen::clear;
use clearscreen; use clearscreen;
use chrono::Local;
use crate::Project; use crate::Project;
use crate::project_controls; use crate::project_controls;
use crate::box_controls; use crate::box_controls;
use crate::info_controls; use crate::info_controls;
use crate::start_pentest; use crate::start_pentest;
use crate::cli;
fn next_project_id(config_path: &PathBuf) -> i32{ pub fn next_project_id(config_path: &PathBuf) -> i32{
let projects = project_controls::get_projects(config_path); let projects = project_controls::get_projects(config_path, false);
let mut new_id = 0; let mut new_id = 0;
for project in projects.clone(){ for project in projects.clone(){
if project.id > new_id{ if project.id > new_id{
@@ -18,7 +22,7 @@ fn next_project_id(config_path: &PathBuf) -> i32{
return new_id; return new_id;
} }
fn get_active_project(projects: &Vec<Project>) -> &Project{ pub fn get_active_project(projects: &Vec<Project>) -> &Project{
let mut active_project = &projects[0]; let mut active_project = &projects[0];
for project in projects{ for project in projects{
if project.active == true{ if project.active == true{
@@ -28,12 +32,40 @@ fn get_active_project(projects: &Vec<Project>) -> &Project{
return active_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){ pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &PathBuf, base_notes: &PathBuf, tools_dir: &PathBuf, boxtemplate: String, terminal: String, cracking_rig: String, rockyou: String, rule: String, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, password_spray_file: &PathBuf, fingerprint: bool, vault_name: String){
let mut loopize = true; let mut loopize = true;
let mut new_id = next_project_id(&config_path); let mut new_id = next_project_id(&config_path);
let mut threads = Vec::new();
loop { loop {
let active_project = get_active_project(&projects); let active_project = get_active_project(&projects);
let mut notes_folder_string = format!("{}", &active_project.notes_folder.display());
let mut obsidian_folder_vec = PathBuf::new();
let mut reached_vault_folder = false;
for folder in notes_folder_string.split("/").collect::<Vec<&str>>(){
if !folder.contains(&vault_name){
reached_vault_folder = true;
obsidian_folder_vec.push(folder);
}
else{
if reached_vault_folder{
obsidian_folder_vec.push(folder);
}
}
}
let obsidian_uri = format!("obsidian://open?vault={}&file={}", vault_name, obsidian_folder_vec.display().to_string().replace("/", "%2F"));
let mut response = String::new(); let mut response = String::new();
let now = Local::now();
let month = now.month();
let year = now.year();
let mut season = String::new();
let mut lseason = String::new();
match month{
12 | 01 | 02 => {season = "Winter".to_owned(); lseason = "Fall".to_owned()},
03 | 04 | 05 => {season = "Spring".to_owned(); lseason = "Winter".to_owned()},
06 | 07 | 08 => {season = "Summer".to_owned(); lseason = "Spring".to_owned()},
09 | 10 | 11 => {season = "Fall".to_owned(); lseason = "Summer".to_owned()},
_ => {println!("error getting season! Check code..."); exit(1)}
}
clear().expect("error clearing screen"); clear().expect("error clearing screen");
print!(" print!("
,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,'''' ,,,;;::ccccc::;;;::c::;,;::cccccllc::::::;:::;;;;,,;,'',,;,,;;;;;;;:;;;;;,,,,,,,,,,,'''''',,,,,,''''
@@ -82,53 +114,76 @@ pub fn main_menu(mut projects: Vec<Project>, config_path: PathBuf, base_files: &
NOTE SAVE PROJECT INFO BEFORE STOPPING THE APPLICATION, OR HOUR TRACKIGN WON'T BE ACCURATE NOTE OPTION 29 WILL SAVE YOUR PROJECTS BEFORE QUITTING
NOTE OPTION 10 WILL SAVE YOUR PROJECTS BEFORE QUITTING
base prject folder: {}
upcoming project folder: {}
Current Project: {} {} Current Project: {} {}
Working Folder: {}
Obsidian_uri: {}
Box Name: {}
Terminal Command: {}
Current Season: {}
Year: {}
General Notes: {}
Main Menu: Main Menu:
1 .) Show Active Project 1 .) Show Active Project
2 .) List Projects 2 .) List Projects
3 .) Switch Active Project 3 .) Switch Active Project
4 .) create new project with Pyro's default tool 4 .) create new project with Pyro's default layout
5 .) Save Project Information 5 .) Save Project Information
6 .) Import New Project - and setup new Distrobox 6 .) Import New Project to Current projects list - and setup new Distrobox
7 .) Remove Project 7 .) Remove Project
8 .) Open A New Terminal in Current Active Project 8 .) Print upcoming projects
9 .) Open A Terminal In this windows for the current active project 9. ) promote project from upcoming to current
10.) Open Project Files Folder In Dolphin 10.) Open A New Terminal in Current Active Project
11.) Open Project Notes Folder In Dolphin 11.) Open A Terminal In this windows for the current active project
12.) generate userpass file from your obsidian notes 12.) open current project's cobalt strike
13.) run pyro's initail enum script on a nessus csv for the current project 13.) re-create the distrobox for the current active project
14.) Print Project Info For Report 14.) generate userpass file from your obsidian notes
15.) Build host discovery cmd command from scope in notes 15.) run pyro's initail enum script on a nessus csv for the current project
16.) Stop All Distroboxes 16.) build external attack notes from host notes
17.) Quit Application 17.) Build host discovery cmd command from scope in notes
\n", active_project.customer, active_project.project_name); 18.) build portscan command from scope in notes
19.) parse a cs portscan services.tsv file
20.) Stop All Distroboxes
21.) Password Spray (will print password to spray, and wait the obervation window time)
22.) Launch bloodhound with the current project's distrobox
23.) Parse GatherContacts output file
24.) prune unused distroboxes (free up system storage)
25.) enter cli
26.) Quit Application
\n",&base_files.display(), &upcoming_files.display(), active_project.customer, active_project.project_name, active_project.files_folder.display(), active_project.notes_folder.display(), active_project.boxname, terminal, season, year, &obsidian_uri);
std::io::stdin().read_line(&mut response).expect("error getting menu input"); std::io::stdin().read_line(&mut response).expect("error getting menu input");
clear().expect("error clearing screen"); clear().expect("error clearing screen");
match response.as_str().trim_end(){ 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()), "1" => {let cli_thread_option = cli::run_command(String::from("show active project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"2" => {println!("+++++++++++++++++++++"); "2" => {let cli_thread_option = cli::run_command(String::from("list projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
for project in &projects{ "3" => {let cli_thread_option = cli::run_command(String::from("switch project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
println!("++{}|{}++",project.customer ,project.project_name)} "4" => {let cli_thread_option = cli::run_command(String::from("new project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
println!("++++++++++++++++++++")}, "5" => {let cli_thread_option = cli::run_command(String::from("save projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"3" => project_controls::switch_project(&mut projects), "6" => {let cli_thread_option = cli::run_command(String::from("import projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"4" => start_pentest::start_pentest(&config_path), "7" => {let cli_thread_option = cli::run_command(String::from("remove project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"5" => project_controls::save_projects(&projects, &config_path), "8" => {let cli_thread_option = cli::run_command(String::from("show upcoming projects"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"6" => {new_id = new_id + 1; project_controls::new_project(&mut projects, &base_files, &base_notes, &tools_dir, &boxtemplate, &config_path, new_id)}, "9" => {let cli_thread_option = cli::run_command(String::from("promote project"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"7" => project_controls::remove_project(&mut projects, &config_path), "10" => {let cli_thread_option = cli::run_command(String::from("new terminal"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"8" => box_controls::project_standalone_terminal(active_project.clone(), terminal.clone()), "11" => {let cli_thread_option = cli::run_command(String::from("inline terminal"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"9" => box_controls::project_inline_terminal(active_project.clone()), "12" => {let cli_thread_option = cli::run_command(String::from("cobalt strike"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"10" => info_controls::open_in_dolphin("files", active_project.clone()), "13" => {let cli_thread_option = cli::run_command(String::from("recreate distrobox"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"11" => info_controls::open_in_dolphin("notes", active_project.clone()), "14" => {let cli_thread_option = cli::run_command(String::from("generate userpass"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"12" => info_controls::generate_userpass(&active_project), "15" => {let cli_thread_option = cli::run_command(String::from("initail enum"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"13" => info_controls::run_initial_enum(&active_project), "16" => {let cli_thread_option = cli::run_command(String::from("build attack notes"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"14" =>info_controls::print_report_information(active_project.clone()), "17" => {let cli_thread_option = cli::run_command(String::from("host discovery"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"15" => info_controls::build_cmd_for_host_discovery(&active_project), "18" => {let cli_thread_option = cli::run_command(String::from("port scan"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"16" => box_controls::stop_all_boxes(&projects), "19" => {let cli_thread_option = cli::run_command(String::from("parse port scan"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"17" => {project_controls::save_projects(&projects, &config_path); "20" => {let cli_thread_option = cli::run_command(String::from("stop boxes"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"21" => {let cli_thread_option = cli::run_command(String::from("password spray"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"22" => {let cli_thread_option = cli::run_command(String::from("bloodhound"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"23" => {let cli_thread_option = cli::run_command(String::from("parse gather contacts"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"24" => {let cli_thread_option = cli::run_command(String::from("prun distroboxes"), projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_thread_option.is_some(){threads.push(cli_thread_option.unwrap());}},
"25" => {let cli_threads_option = cli::cli(true, projects.clone(), config_path.clone(), base_files, base_notes, tools_dir, boxtemplate.clone(), terminal.clone(), cracking_rig.clone(), rockyou.clone(), rule.clone(), upcoming_files, upcoming_notes, password_spray_file, fingerprint, vault_name.clone()); if cli_threads_option.is_some(){for thread in cli_threads_option.unwrap(){threads.push(thread);}}},
"26" => {project_controls::save_projects(&projects, &config_path);
let mut stop = String::new(); let mut stop = String::new();
println!("stop all boxes?\ny/n"); println!("stop all boxes?\ny/n");
std::io::stdin().read_line(&mut stop).unwrap(); std::io::stdin().read_line(&mut stop).unwrap();
@@ -145,4 +200,9 @@ Current Project: {} {}
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();
} }
println!("this will hang until all threads are finished.");
println!("make sure to close all programs opened with this menu, like cobalt strike or bloodhound.");
for thread in threads{
thread.join().unwrap();
}
} }

View File

@@ -4,10 +4,13 @@ use std::io::stdin;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
use std::process::Command;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use std::str::FromStr; use std::str::FromStr;
use crate::get_user_input;
use crate::Project; use crate::Project;
use crate::box_controls::make_box;
pub fn switch_project(projects: &mut Vec<Project>){ pub fn switch_project(projects: &mut Vec<Project>){
for project in projects.clone(){ for project in projects.clone(){
@@ -46,34 +49,64 @@ pub fn save_projects(projects: &Vec<Project>, config_path: &PathBuf){
save_file_path.pop(); save_file_path.pop();
save_file_path.push("projects.conf"); save_file_path.push("projects.conf");
let mut save_file = fs::File::create(save_file_path).expect("error creating save_file"); 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"); save_file.write_all(b"customer:name:notes:files:active:time:box_name:stage\n").expect("error writing first line to file");
for project in projects{ for project in projects{
let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()}; let default = format!{"{}:{}:{}:{}:", project.customer, project.project_name, project.notes_folder.display(), project.files_folder.display()};
let mut _outline = String::new(); let mut _outline = String::new();
if project.active{ if project.active{
if active_set == false{ if active_set == false{
_outline = format!("{}yes:{}\n", default, project.boxname); _outline = format!("{}yes:{}:{}\n", default, project.boxname, project.stage);
active_set = true; active_set = true;
} }
} }
else{ else{
_outline = format!("{}no:{}\n", default, project.boxname); _outline = format!("{}no:{}:{}\n", default, project.boxname, project.stage);
} }
save_file.write_all(_outline.as_bytes()).expect("error writing outline"); 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){ 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, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, fingerprint: bool){
let mut new_project_dir = project_dir.clone(); let mut new_project_dir = PathBuf::new();
let mut new_note_dir = notes_dir.clone(); let mut new_note_dir = PathBuf::new();
let mut existing_folders = String::new(); let mut existing_folders = String::new();
let mut customer_name = String::new(); let mut customer_name = String::new();
let mut project_name = String::new(); let mut project_name = String::new();
let mut project_stage = String::new();
loop{
let mut stage_response = String::new();
println!("what stage is this project in?");
print!("
1.) current
2.) upcoming
");
let stage_result = stdin().read_line(&mut stage_response);
if stage_result.is_err(){
println!("we need input here dummy, try again...");
}
else{
match &stage_response.trim_end(){
&"1" => {project_stage = "current".to_owned(); break;},
&"2" => {project_stage = "upcoming".to_owned(); break;},
_ => println!("unknown option, try again...")
}
}
}
if project_stage.contains("current"){
new_project_dir = project_dir.clone();
new_note_dir = notes_dir.clone();
}
else if project_stage.contains("upcoming"){
new_project_dir = upcoming_files.clone();
new_note_dir = upcoming_notes.clone();
}
else{
println!("unknown stage!!")
}
println!("{}", new_project_dir.display());
println!("do you have an existing notes and folder structure to copy over?\ny/n"); println!("do you have an existing notes and folder structure to copy over?\ny/n");
std::io::stdin().read_line(&mut existing_folders).unwrap(); 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"){ 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"); 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 files_to_copy = String::new();
@@ -185,54 +218,6 @@ pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir
} }
thread::sleep(Duration::from_secs(2)); thread::sleep(Duration::from_secs(2));
let box_name = format!("atarchbox_{}", customer_name); 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(), let new_project = Project{customer: customer_name.trim_end().to_owned(),
project_name: project_name.trim_end().to_owned(), project_name: project_name.trim_end().to_owned(),
notes_folder: new_note_dir, notes_folder: new_note_dir,
@@ -240,7 +225,11 @@ pub fn new_project(projects: &mut Vec<Project>, project_dir: &PathBuf, notes_dir
active: false, active: false,
id: new_id, id: new_id,
boxname: box_name, boxname: box_name,
stage: project_stage.to_owned()
}; };
if project_stage.contains("current"){
make_box(&new_project, &tools_dir, &boxtemplate, true, fingerprint);
}
projects.push(new_project); projects.push(new_project);
save_projects(projects, config_path); save_projects(projects, config_path);
@@ -300,7 +289,7 @@ pub fn remove_project(projects: &mut Vec<Project>, config_path: &PathBuf){
} }
} }
pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{ pub fn get_projects(config_path: &PathBuf, show: bool) -> Vec<Project>{
let mut mut_config_path = config_path.clone(); let mut mut_config_path = config_path.clone();
mut_config_path.pop(); mut_config_path.pop();
mut_config_path.push("projects.conf"); mut_config_path.push("projects.conf");
@@ -314,6 +303,12 @@ pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{
if first != 1{ if first != 1{
if line.len() > 1{ if line.len() > 1{
let settings: Vec<&str> = line.split(":").collect(); let settings: Vec<&str> = line.split(":").collect();
//debug config file...
/*let mut count = 0;
for settin in &settings{
println!("{}: {}", count, settin);
count = count + 1;
}*/
let customer = settings[0].to_owned(); let customer = settings[0].to_owned();
let project = settings[1].to_owned(); let project = settings[1].to_owned();
let notes_string = settings[2].to_owned(); let notes_string = settings[2].to_owned();
@@ -329,11 +324,132 @@ pub fn get_projects(config_path: &PathBuf) -> Vec<Project>{
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}; let project_stage = settings[6].to_owned();
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name); let new_project = Project{customer: customer, project_name: project, files_folder: project_folder, notes_folder: notes_folder, active: active, id: first, boxname: boxname, stage: project_stage};
if show{
println!("{} {} LOADED!", &new_project.customer, &new_project.project_name);
}
projects.push(new_project); projects.push(new_project);
} }
} }
} }
return projects return projects
} }
pub fn print_upcoming_projects(projects: &Vec<Project>){
for project in projects{
if project.stage.contains("upcoming"){
println!("{}:{}", project.customer, project.project_name);
}
}
}
pub fn promote_project(projects: &mut Vec<Project>, config_path: &PathBuf, project_dir: &PathBuf, notes_dir: &PathBuf, tools_dir: &PathBuf, boxtemplate: &String, fingerprint: bool){
let working_projects = projects.clone();
for project in &working_projects{
if project.stage.contains("upcoming"){
println!("{}.) {}:{}", project.id, project.customer, project.project_name);
}
}
println!("which project to promote?");
let mut selection = String::new();
let result = stdin().read_line(&mut selection);
if result.is_err(){
println!("we need input here dummy try again....");
}
result.unwrap();
println!("{}", project_dir.display());
let promote_id: i32 = selection.trim_end().parse().unwrap();
let mut projects_to_save = Vec::new();
for project in &working_projects{
if project.id == promote_id{
let mut promoted_project = project.clone();
let mut new_files_dir = project_dir.clone();
let mut new_notes_dir = notes_dir.clone();
new_files_dir.push(&promoted_project.customer);
new_notes_dir.push(&promoted_project.customer);
fs::create_dir_all(&new_files_dir).unwrap();
fs::create_dir_all(&new_notes_dir).unwrap();
let folder_move_success = process::Command::new("mv")
.arg("-i")
.arg(&project.files_folder)
.arg(&new_files_dir.display().to_string())
.status().expect("unable to call the system mv command");
let note_move_success = process::Command::new("mv")
.arg("-i")
.arg(&project.notes_folder)
.arg(&new_notes_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!!");
let mut remove_folder = PathBuf::new();
remove_folder.push(&project.files_folder);
remove_folder.pop();
let remove_files_res = fs::remove_dir_all(remove_folder);
if remove_files_res.is_err(){
println!("error removing the original files folder form the upcomming folder, manual cleanup required");
}
else{
remove_files_res.unwrap();
println!("upcoming files folder cleanup successful!");
}
}
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!!");
let mut remove_folder = PathBuf::new();
remove_folder.push(&project.files_folder);
remove_folder.pop();
let remove_notes_res = fs::remove_dir_all(remove_folder);
if remove_notes_res.is_err(){
println!("error removing the original notes folder form the upcomming folder, manual cleanup required");
}
else{
remove_notes_res.unwrap();
println!("upcoming notes folder cleanup successful!");
}
}
else{
println!("failed to copy the notes folder, try to move it manually!");
}
new_files_dir.push(&promoted_project.project_name);
new_notes_dir.push(&promoted_project.project_name);
promoted_project.files_folder = new_files_dir;
promoted_project.notes_folder = new_notes_dir;
promoted_project.stage = "current".to_owned();
let cs_response = get_user_input("will you need to be using cobalt strike for this project?");
if cs_response.to_lowercase().contains("y"){
let cs_path = get_user_input("path to your current cobalt strike directory?");
let copy_result = Command::new("cp").arg("-R").arg(&cs_path).arg(&promoted_project.files_folder).status();
if copy_result.is_err(){
println!("oof we had an error copying... you'll have to copy this manually");
}
else{
let copy_exit = copy_result.unwrap();
if copy_exit.success() == false{
println!("oof we had an error copying... you'll have to copy this manually");
println!("run cp -R {} {}", &cs_path, &promoted_project.files_folder.display());
}
}
}
thread::sleep(Duration::from_secs(3));
make_box(&promoted_project, tools_dir, boxtemplate, true, fingerprint);
projects_to_save.push(promoted_project);
}
else{
projects_to_save.push(project.clone());
}
}
projects.clear();
projects.append(&mut projects_to_save);
save_projects(&projects_to_save, config_path);
}
pub fn list_projects(projects: &Vec<Project>){
println!("+++++++++++++++++++++");
for project in projects{
println!("++Customer: {}|Project name: {}|Stage: {}++",project.customer ,project.project_name, project.stage)}
println!("++++++++++++++++++++")
}

View File

@@ -1,25 +1,59 @@
use std::fs; use std::fs;
use std::io::stdin; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use crate::Project;
use crate::project_controls;
use crate::get_user_input;
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"); fn create_project_folder(path: &mut PathBuf, folder: &str){
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file"); path.push(folder);
let mut host_notes = fs::File::create(format!("{}/host_notes.md", &project_folder_path)).expect("error creating host notes file"); let result = fs::create_dir_all(&path);
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file"); if result.is_err(){
// for tagging println!("error creating {} directory!", folder);
let year = project_name.split("_").collect::<Vec<&str>>()[1]; }
let project_type = "External"; else{
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file"); result.unwrap();
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"); path.pop();
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"); fn create_note_file(path: &PathBuf) -> Option<File>{
writeln!(&mut general_notes, "| -- | ----------- | -------- |").expect("error writing to general notes file"); let result = fs::File::create(path);
writeln!(&mut general_notes, "# PPC").expect("failed to write general notes"); if result.is_err(){
write!(&mut general_notes, " println!("error creating {} try manually!", path.display());
return None;
}
else{
let file = result.unwrap();
return Some(file);
}
}
fn external(passtemp: &PathBuf, project: &Project){
// using a pathbuf to create files.
let mut notes_path = project.notes_folder.clone();
let file_creation_res = fs::create_dir_all(&notes_path);
if file_creation_res.is_err(){
let error = file_creation_res.err().unwrap();
println!("error creating notes folder! {}", error);
}
else{
file_creation_res.unwrap();
}
notes_path.push("general.md");
let general_notes_result = create_note_file(&notes_path);
if general_notes_result.is_some(){
let mut general_notes = general_notes_result.unwrap();
// for tagging
let project_type = "External";
writeln!(&mut general_notes, "#{} #{} #general", project.customer, project_type).expect("error writing to general notes file");
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: Planning call notes:
* methodolgy * methodolgy
* whole month testing window * whole month testing window
@@ -54,8 +88,14 @@ Planning call notes:
| IP | host notes | needs? | | IP | host notes | needs? |
| -- | ---------- | ------ |\n").expect("faile to write pentest notes"); | -- | ---------- | ------ |\n").expect("faile to write pentest notes");
// set up the basics for our attack notes }
write!(&mut attack_notes," notes_path.pop();
notes_path.push("attacks.md");
let attack_notes_result = create_note_file(&notes_path);
if attack_notes_result.is_some(){
let mut attack_notes = attack_notes_result.unwrap();
writeln!(&mut attack_notes, "#{} #{} #attack", project.customer, "external").expect("error writing tags on attack notes");
write!(&mut attack_notes,"
# Directory Bruteforcing # Directory Bruteforcing
- [ ] example.com - [ ] example.com
@@ -74,59 +114,79 @@ write!(&mut attack_notes,"
passwords tried: passwords tried:
* password\n * password\n
" ).expect("failed to write attack notes template"); " ).expect("failed to write attack notes template");
let new_spray_path = format!("{}/passwordspray.md", &project_folder_path); }
fs::copy(passtemp,new_spray_path).unwrap(); notes_path.pop();
notes_path.push("password_spray.md");
let pass_result = fs::copy(&passtemp, &notes_path);
if pass_result.is_err(){
println!("error copying password spray file! try manually");
}
else{
pass_result.unwrap();
}
notes_path.pop();
notes_path.push("host_notes.md");
let host_notes_result = create_note_file(&notes_path);
if host_notes_result.is_some(){
let mut host_notes = host_notes_result.unwrap();
writeln!(&mut host_notes, "##{} #{} #host_notes", project.customer, "external").expect("error writing tag lin in host notes");
}
notes_path.pop();
notes_path.push("findings.md");
let findings_notes_result = create_note_file(&notes_path);
if findings_notes_result.is_some(){
let mut finding_notes = findings_notes_result.unwrap();
writeln!(&mut finding_notes, "#{} #{} #findings", project.customer, "external").expect("error writing tag line on findings");
}
} }
fn internal(project_folder_path: String, comapny_name: &String, project_name: &String, passtemp: PathBuf){ fn internal(passtemp: &PathBuf, project: &Project){
let loot_folder = format!("{}/l00t", project_folder_path); let mut notes_path = project.notes_folder.clone();
fs::create_dir_all(&loot_folder).expect("error creating loot directory"); let file_creation_res = fs::create_dir_all(&notes_path);
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file"); if file_creation_res.is_err(){
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file"); let error = file_creation_res.err().unwrap();
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file"); println!("error creating notes folder! {}", error);
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"); else{
let mut creds_notes = fs::File::create(format!("{}/creds.md", &loot_folder)).expect("error creating creds note"); file_creation_res.unwrap();
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"); notes_path.push("password_spray.md");
let mut dump_notes = fs::File::create(format!("{}/dumps.md", &loot_folder)).expect("error creating password spray notes"); println!("copying from {} to {}", passtemp.display(), &notes_path.display());
let mut enum_notes = fs::File::create(format!("{}/initial_enum.md", &project_folder_path)).expect("error creating password spray notes"); let pass_result = fs::copy(&passtemp, &notes_path);
let enum_obsidian_path = format!("Hack_Notes/pentest_notes/upcomming/{customer}//initial_enum.md", customer = comapny_name); if pass_result.is_err(){
// for tagging notes let error = pass_result.err().unwrap();
let oyear = project_name.split("_").collect::<Vec<&str>>()[0]; println!("error copying password spray file, try again manually! {}", error);
let year = format!("year-{}", oyear); }
let project_type = "Internal"; else{
writeln!(&mut creds_notes, "#{} #{} #{} #l00t #creds", comapny_name, project_type, year).expect("error writing creds notes"); pass_result.unwrap();
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"); notes_path.pop();
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file"); notes_path.push("l00t");
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing attack note tags"); fs::create_dir_all(&notes_path).expect("error creating loot directory");
writeln!(&mut todo_notes, "#{} #{} #{} #todo", comapny_name, project_type, year).expect("error writing tag line on todo"); notes_path.push("creds.md");
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tags line on findings"); let creds_notes_result = create_note_file(&notes_path);
writeln!(&mut systeminfo, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tag line for system info"); if creds_notes_result.is_some(){
writeln!(&mut systeminfo, "#{} #{} #{} #Password_sprays", comapny_name, project_type, year).expect("error writing tag line for password spraying"); let mut creds_notes = creds_notes_result.unwrap();
writeln!(&mut netsta, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tagline in the netstat file"); writeln!(&mut creds_notes, "#{} #{} #l00t #creds", project.customer, "internal").expect("error writing creds notes");
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, "# CREDS").expect("error writing creds notes"); writeln!(&mut creds_notes, "\n| System | username | password |").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, "| ------ | -------- | -------- |").expect("error writing creds notes"); writeln!(&mut creds_notes, "\n\n").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, "# HASHES\n\n").expect("error writing creds notes"); writeln!(&mut creds_notes, "| TYPE | USER | HASH |").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 creds_notes, "| ---- | ---- | ---- |").expect("error writing creds notes"); }
writeln!(&mut cleanup_notes, "- [ ] Breach machine C-temp-fr").expect("error writing to cleanup notes"); notes_path.pop();
writeln!(&mut cleanup_notes, "- [ ] (continue to add as needed").expect("error writing ot cleanup notes"); notes_path.pop();
writeln!(&mut general_notes, "# Scope\n").expect("error writing to general notes file"); notes_path.push("general.md");
writeln!(&mut general_notes, "PASTE SCOPE FROM EXCELL HERE (THE EXCEL TO MARKDOWN TABLE PLUGIN WILL FORMAT FOR YOU").expect("shouldn't ever fail"); let general_result = create_note_file(&notes_path);
writeln!(&mut dump_notes, "# SAM\n\n").expect("shouldn't ever fail"); if general_result.is_some(){
writeln!(&mut dump_notes, "## system name\n").expect("shouldn't ever fail"); let mut general_notes = general_result.unwrap();
writeln!(&mut dump_notes, "```").expect("shouldn't ever fail"); writeln!(&mut general_notes, "#{} #{} #general", project.customer, "internal").expect("error writing to general notes file");
writeln!(&mut dump_notes, "```\n\n").expect("shouldn't ever fail"); writeln!(&mut general_notes, "# Scope\n").expect("error writing to general notes file");
writeln!(&mut dump_notes, "# LSASS\n\n").expect("shouldn't ever fail"); 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, "## system name\n").expect("shouldn't ever fail"); write!(&mut general_notes, "
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: On the call:
Introductions Introductions
@@ -151,7 +211,15 @@ Do they have a specific contact
Email any follow-up items from the call to the PM Email any follow-up items from the call to the PM
").expect("error writing PPC text"); ").expect("error writing PPC text");
write!(&mut attack_notes," }
notes_path.pop();
let enum_path = format!("{}/initial_enum.md", notes_path.display());
notes_path.push("attacks.md");
let attack_result = create_note_file(&notes_path);
if attack_result.is_some(){
let mut attack_notes = attack_result.unwrap();
writeln!(&mut attack_notes, "#{} #{} #attack", project.customer, "internal").expect("error writing attack note tags");
write!(&mut attack_notes,"
# current dat (ex: 7/5) # current dat (ex: 7/5)
Got Persistence via (schtasks, bat schtasks, startup folder) Got Persistence via (schtasks, bat schtasks, startup folder)
@@ -206,15 +274,29 @@ powerup.ps1/sharpup.exe notes.
", enum = enum_obsidian_path).expect("error writing to attack notes for internal tests"); ", enum = enum_path).expect("error writing to attack notes for internal tests");
write!(&mut finding_notes, " }
# normal findings notes_path.pop();
notes_path.push("findings.md");
let findings_result = create_note_file(&notes_path);
if findings_result.is_some(){
let mut finding_notes = findings_result.unwrap();
writeln!(&mut finding_notes, "#{} #{} #findings", project.customer, "internal").expect("error writing tags line on findings");
write!(&mut finding_notes, "
# normal findings
# data exfil # data exfil
## [Sarting Username] ## [Sarting Username]
").expect("error writing to findings notes on internal"); ").expect("error writing to findings notes on internal");
write!(&mut todo_notes, " }
notes_path.pop();
notes_path.push("todo.md");
let todo_result = create_note_file(&notes_path);
if todo_result.is_some(){
let mut todo_notes = todo_result.unwrap();
writeln!(&mut todo_notes, "#{} #{} #todo", project.customer, "internal").expect("error writing tag line on todo");
write!(&mut todo_notes, "
- [ ] local checks - [ ] local checks
- [ ] find shares - [ ] find shares
@@ -227,87 +309,47 @@ powerup.ps1/sharpup.exe notes.
- [ ] passwords in AD Descriptions? - [ ] passwords in AD Descriptions?
- [ ] password spray - [ ] password spray
").expect("error writing todo list"); ").expect("error writing todo list");
write!(&mut netsta," }
``` notes_path.pop();
notes_path.push("cleanup.md");
```").expect("error writing code block to system info"); let cleanup_result = create_note_file(&notes_path);
write!(&mut systeminfo," if cleanup_result.is_some(){
``` let mut cleanup_notes = cleanup_result.unwrap();
writeln!(&mut cleanup_notes, "#{} #{} #cleanup", project.customer, "internal").expect("error writing to cleanup notes");
```").expect("error writing code block to system info"); writeln!(&mut cleanup_notes, "- [ ] Breach machine C-temp-fr").expect("error writing to cleanup notes");
let new_pass_path = format!("{}/passwordspray.md", &project_folder_path); writeln!(&mut cleanup_notes, "- [ ] (continue to add as needed").expect("error writing ot cleanup notes");
println!("{} | {}", passtemp.display(), new_pass_path); }
fs::copy(passtemp, new_pass_path).unwrap();
} }
pub fn start_pentest(config_path: &PathBuf) { pub fn start_pentest(config_path: &PathBuf, projects: &mut Vec<Project>, id: i32, upcoming_files: &PathBuf, upcoming_notes: &PathBuf, boxtemplate: &String, password_spray_file: &PathBuf) {
let mut pentest_notes = String::new(); let mut project_files = upcoming_files.clone();
let mut project_files = String::new(); let mut project_notes = upcoming_notes.clone();
let mut company_name = String::new(); let customer_name = get_user_input("Customer name?");
let mut project_name = String::new(); let project_name = get_user_input("Project Name?");
let mut config_file_path_buf = config_path.clone(); project_files.push(&customer_name);
let mut passpray_path = config_file_path_buf.clone(); project_files.push(&project_name);
passpray_path.push("passwordspray.md"); project_notes.push(&customer_name);
config_file_path_buf.push("new_projects.conf"); project_notes.push(&project_name);
let config_string = fs::read_to_string(config_file_path_buf).expect("error reading "); println!("Files: {}\nNotes: {}\n\n", project_files.display(), project_notes.display());
if config_string.contains("folder_path") && config_string.contains("notes_path"){ let confirm_response = get_user_input("does this look ok?");
let config_string_vec: Vec<&str> = config_string.split("\n").collect(); if confirm_response.to_lowercase().contains("n"){
for line in config_string_vec{ println!("oof sorry");
if line.contains("project_folder_path"){ return;
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); let mut working = project_files.clone();
println!("Comapny Name?"); create_project_folder(&mut working, "working");
std::io::stdin().read_line(&mut company_name); create_project_folder(&mut working, "writing");
println!("project Name?"); create_project_folder(&mut working, "delivery");
stdin().read_line(&mut project_name); let project_boxname = format!("{}_{}", boxtemplate, customer_name);
//remove new lines from input let new_prject = Project{customer:customer_name.clone(), project_name:project_name.clone(), notes_folder:project_notes.clone(), files_folder:project_files.clone(),active:false, boxname:project_boxname.clone(),stage:"upcoming".to_owned(), id};
company_name.trim_end(); if project_name.contains("external"){
project_name.trim_end(); external(password_spray_file, &new_prject);
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") { else if project_name.contains("internal"){
println!("external pentest type detected, auto populating notes with external layout..."); internal(password_spray_file, &new_prject);
external(project_folder_path, &company_name, &project_name, passpray_path);
} }
else if project_name.contains("webapp") { projects.push(new_prject);
println!("not implemented yet sorry"); project_controls::save_projects(projects, config_path);
println!("default file folder structure used, and empty notes folder created...") println!("project created and saved to the projects config file!");
}
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 +0,0 @@
{"rustc_fingerprint":1960306743998270933,"outputs":{"14371922958718593042":{"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":""},"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\nfmt_debug=\"full\"\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\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\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"unknown\"\nub_checks\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

@@ -1,3 +0,0 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by cargo.
# For information about cache directory tags see https://bford.info/cachedir/

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
{"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

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

View File

@@ -1 +0,0 @@
{"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

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

View File

@@ -1 +0,0 @@
{"rustc":18217185010275080438,"features":"[\"std\"]","declared_features":"","target":14463131919016566876,"profile":10243973527296709326,"path":96659009738692421,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-d96cb1cfd8335477/dep-lib-bitflags"}}],"rustflags":[],"metadata":14564035643000669268,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

@@ -1 +0,0 @@
{"rustc":18217185010275080438,"features":"[\"default\"]","declared_features":"","target":202096439108023897,"profile":10243973527296709326,"path":4706328860019254468,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-f1b2eea508d06d09/dep-lib-bitflags"}}],"rustflags":[],"metadata":14564035643000669268,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

@@ -1 +0,0 @@
{"rustc":18217185010275080438,"features":"[]","declared_features":"","target":11601024444410784892,"profile":10243973527296709326,"path":14751567272659301693,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/cfg-if-c1fbdb19b888f7ea/dep-lib-cfg_if"}}],"rustflags":[],"metadata":8462187951337715540,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

@@ -1 +0,0 @@
{"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

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

View File

@@ -1 +0,0 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[]","target":12544613461349730042,"profile":13232757476167777671,"path":3082952703254974027,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/cfg_aliases-1f13698e8658435a/dep-lib-cfg_aliases","checksum":false}}],"rustflags":[],"metadata":16709548127506949239,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

@@ -1 +0,0 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[\"windows-console\"]","target":16510214328398099570,"profile":10243973527296709326,"path":8065629026401069409,"deps":[[4171369895214295011,"nix",false,14721634682339001905],[6670304167515094581,"terminfo",false,15574987113318484187],[11266840602298992523,"thiserror",false,7865905133239940446],[15094023649821285592,"which",false,3114378975027364186]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/clearscreen-034d850761e9268d/dep-lib-clearscreen","checksum":false}}],"rustflags":[],"metadata":3954388147124695588,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

@@ -1 +0,0 @@
{"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

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

View File

@@ -1 +0,0 @@
{"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

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

View File

@@ -1 +0,0 @@
{"rustc":18217185010275080438,"features":"[]","declared_features":"","target":16510214328398099570,"profile":10243973527296709326,"path":15789751593529559319,"deps":[[6165314194305105601,"thiserror",false,8920314343114863320],[6583558668148823975,"which",false,13684585653519867350],[6670304167515094581,"terminfo",false,3057214535705540554],[17995977118843992204,"nix",false,7029758982020207529]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/clearscreen-35ec903f591841be/dep-lib-clearscreen"}}],"rustflags":[],"metadata":3954388147124695588,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

@@ -1 +0,0 @@
{"rustc":11594289678289209806,"features":"[]","declared_features":"[\"windows-console\"]","target":16510214328398099570,"profile":10243973527296709326,"path":8065629026401069409,"deps":[[4171369895214295011,"nix",false,14721634682339001905],[6670304167515094581,"terminfo",false,1603648623332424207],[11266840602298992523,"thiserror",false,7865905133239940446],[15094023649821285592,"which",false,3114378975027364186]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/clearscreen-79a7f35c54511a30/dep-lib-clearscreen","checksum":false}}],"rustflags":[],"metadata":3954388147124695588,"config":2202906307356721367,"compile_kind":0}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
{"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

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
bd9e7e9ba848bf6d

View File

@@ -1 +0,0 @@
{"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

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

View File

@@ -1 +0,0 @@
895cbb3523b793a9

View File

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

View File

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

View File

@@ -1 +0,0 @@
7e48c0f8fb61d242

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