427 lines
17 KiB
Rust
427 lines
17 KiB
Rust
/*
|
|
Auther: Pyro
|
|
Purpose: To automate setting up my notes at the start of a pentest project
|
|
Install Instructions: Change the "Pentest_notes" variable below to the directory you keep your pentest notes in. Then run cargo build to compile and copy the binary at ./target/debug/start_pentest to something like /usr/bin
|
|
|
|
some special instructions for the file formats
|
|
the scope.txt file should be in the following formats
|
|
|
|
EXTERNAL:
|
|
host 3rd_party approval
|
|
|
|
INTERNAL:
|
|
network environment inscope?
|
|
|
|
examples:
|
|
External:
|
|
192.168.1.1 no yes
|
|
192.168.1.2 yes no
|
|
etc etc.
|
|
|
|
Internal:
|
|
192.168.1.0/24 servers yes
|
|
192.168.2.0/24 workstations yes
|
|
192.168.3.0/24 ICS no
|
|
|
|
*/
|
|
use std::fs;
|
|
use std::env;
|
|
use std::fs::create_dir_all;
|
|
use std::io::Write;
|
|
use std::path::{Path, PathBuf};
|
|
use dirs::home_dir;
|
|
|
|
fn install(){
|
|
let mut install_path: PathBuf = PathBuf::new();
|
|
install_path.push(home_dir().expect("error getting home dir"));
|
|
install_path.push(".config/pyro_pentest_tools/");
|
|
fs::create_dir_all(&install_path).expect("error creating config directory");
|
|
install_path.push("start_pentest.conf");
|
|
let mut conf_file = fs::File::create(install_path).expect("error creating config file");
|
|
let mut project_folder_path = String::new();
|
|
let mut porject_note_path = String::new();
|
|
println!("path to the project folders directory?");
|
|
std::io::stdin().read_line(&mut project_folder_path).expect("error reading project folder from stdin");
|
|
println!("path to the project notes directory");
|
|
std::io::stdin().read_line(&mut porject_note_path).expect("error reading project note folder form stdin");
|
|
write!(conf_file, "project_folder_path:{}
|
|
project_notes_path:{}
|
|
", project_folder_path.trim_end(), porject_note_path.trim_end()).expect("error writing config file");
|
|
std::process::exit(0);
|
|
}
|
|
|
|
|
|
fn external(project_folder_path: String,comapny_name: &String, project_name: &String, scope: Vec<&str>){
|
|
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file");
|
|
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file");
|
|
let mut host_notes = fs::File::create(format!("{}/host_notes.md", &project_folder_path)).expect("error creating host notes file");
|
|
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file");
|
|
// for tagging
|
|
let year = project_name.split("_").collect::<Vec<&str>>()[1];
|
|
let project_type = "External";
|
|
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file");
|
|
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing tags on attack notes");
|
|
writeln!(&mut host_notes, "#{} #{} #{} #host_notes", comapny_name, project_type, year).expect("error writing tag lin in host notes");
|
|
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tag line on findings");
|
|
writeln!(&mut general_notes, "# Scope").expect("error writing to general notes file");
|
|
writeln!(&mut general_notes, "| IP | Third Party | Approval |").expect("error writing to general notes file");
|
|
writeln!(&mut general_notes, "| -- | ----------- | -------- |").expect("error writing to general notes file");
|
|
for address in &scope{
|
|
if address.len() > 0{
|
|
let address_vec: Vec<&str> = address.split(" ").collect();
|
|
let address_line = format!("| {} | {} | {} |", address_vec[0], address_vec[1], address_vec[2]);
|
|
writeln!(&mut general_notes, "{}", address_line).expect("error writing to General Notes File");
|
|
}
|
|
}
|
|
writeln!(&mut general_notes, "# PPC").expect("failed to write general notes");
|
|
write!(&mut general_notes, "
|
|
Planning call notes:
|
|
* methodolgy
|
|
* whole month testing window
|
|
* start with a vuln scan in nessus pro
|
|
* pentesting execution standard framework
|
|
* info gathering
|
|
* recon
|
|
* exlpoitation
|
|
* reporting
|
|
* primary objective
|
|
* reasonable and expected protections are in place
|
|
* see if we can get access to the internal network
|
|
* if we do get inside
|
|
* reach out to the contact and see what they'd want us to know
|
|
* questions to ask
|
|
* custom objectives
|
|
*
|
|
* testing main website
|
|
* password attacks
|
|
* password sprays 3-12 hours
|
|
* lock out policy -
|
|
|
|
## Enumeration in progress
|
|
|
|
### DNS Bruteforcing
|
|
| domain name | IP | inscope? |
|
|
| ----------- | -- | -------- |
|
|
|
|
# Attack Surface Enumeration
|
|
| IP | host notes | needs? |
|
|
| -- | ---------- | ------ |\n").expect("faile to write pentest notes");
|
|
|
|
// set up the basics for our attack notes
|
|
write!(&mut attack_notes,"
|
|
# Directory Bruteforcing
|
|
- [ ] example.com
|
|
|
|
----
|
|
|
|
# Login attacks
|
|
## examle.com/login
|
|
- [ ] stuffed
|
|
- [ ] sprayed
|
|
- [ ] bruteforced
|
|
- [ ] default
|
|
|
|
----
|
|
|
|
# MSOLspray.py
|
|
passwords tried:
|
|
* password\n
|
|
" ).expect("failed to write attack notes template");
|
|
|
|
for host in scope{
|
|
write!(&mut host_notes, "
|
|
# {}
|
|
Domain Name:
|
|
| port | service | attack_notes |
|
|
| ---- | ------- | ------------ |
|
|
|
|
----
|
|
|
|
|
|
", host).expect("faield to write host notes");
|
|
write!(&mut finding_notes, "
|
|
# Critical
|
|
|
|
# High
|
|
|
|
# Medium
|
|
|
|
# Low
|
|
|
|
# informational
|
|
|
|
").expect("errror writing to findings for external");
|
|
}
|
|
}
|
|
|
|
fn internal(project_folder_path: String, comapny_name: &String, project_name: &String, scope: Vec<&str>){
|
|
let loot_folder = format!("{}/l00t", project_folder_path);
|
|
create_dir_all(&loot_folder).expect("error creating loot directory");
|
|
let mut general_notes = fs::File::create(format!("{}/general.md", &project_folder_path)).expect("error creating general notes file");
|
|
let mut attack_notes = fs::File::create(format!("{}/attacks.md", &project_folder_path)).expect("error creating attack notes file");
|
|
let mut finding_notes = fs::File::create(format!("{}/findings.md", &project_folder_path)).expect("error creating findings notes file");
|
|
let mut systeminfo = fs::File::create(format!("{}/systeminfo", &project_folder_path)).expect("error creating systeminfo note file");
|
|
let mut netsta = fs::File::create(format!("{}/netstat", &project_folder_path)).expect("error creating netstat file");
|
|
let mut creds_notes = fs::File::create(format!("{}/creds.md", &loot_folder)).expect("error creating creds note");
|
|
let mut todo_notes = fs::File::create(format!("{}/todo.md", &project_folder_path)).expect("error creating todo notes");
|
|
let mut cleanup_notes = fs::File::create(format!("{}/cleanup.md", &project_folder_path)).expect("error creating cleanup notes");
|
|
let mut password_spray = fs::File::create(format!("{}/password_spray.md", &project_folder_path)).expect("error creating password spray notes");
|
|
// for tagging notes
|
|
let oyear = project_name.split("_").collect::<Vec<&str>>()[0];
|
|
let year = format!("year-{}", oyear);
|
|
let project_type = "Internal";
|
|
writeln!(&mut creds_notes, "#{} #{} #{} #l00t #creds", comapny_name, project_type, year).expect("error writing creds notes");
|
|
writeln!(&mut cleanup_notes, "#{} #{} #{} #cleanup", comapny_name, project_type, year).expect("error writing to cleanup notes");
|
|
writeln!(&mut general_notes, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing to general notes file");
|
|
writeln!(&mut attack_notes, "#{} #{} #{} #attack", comapny_name, project_type, year).expect("error writing attack note tags");
|
|
writeln!(&mut todo_notes, "#{} #{} #{} #todo", comapny_name, project_type, year).expect("error writing tag line on todo");
|
|
writeln!(&mut finding_notes, "#{} #{} #{} #findings", comapny_name, project_type, year).expect("error writing tags line on findings");
|
|
writeln!(&mut systeminfo, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tag line for system info");
|
|
writeln!(&mut systeminfo, "#{} #{} #{} #Password_sprays", comapny_name, project_type, year).expect("error writing tag line for password spraying");
|
|
writeln!(&mut netsta, "#{} #{} #{} #general", comapny_name, project_type, year).expect("error writing tagline in the netstat file");
|
|
writeln!(&mut creds_notes, "| System | username | password |").expect("error writing creds notes");
|
|
writeln!(&mut creds_notes, "| ------ | -------- | -------- |").expect("error writing creds notes");
|
|
writeln!(&mut cleanup_notes, "- [ ] Breach machine C-temp-fr").expect("error writing to cleanup notes");
|
|
writeln!(&mut cleanup_notes, "- [ ] (continue to add as needed").expect("error writing ot cleanup notes");
|
|
writeln!(&mut general_notes, "# Scope\n").expect("error writing to general notes file");
|
|
writeln!(&mut general_notes, "| IP | environment | inscope? |").expect("error writing to general notes file");
|
|
writeln!(&mut general_notes, "| -- | ----------- | -------- |").expect("error writing to general notes file");
|
|
for address in &scope{
|
|
if address.len() > 0{
|
|
let address_vec: Vec<&str> = address.split(" ").collect();
|
|
let address_line = format!("| {}|{}|{} |", address_vec[0], address_vec[1], address_vec[2]);
|
|
writeln!(&mut general_notes, "{}", address_line).expect("error writing to General Notes File");
|
|
}
|
|
}
|
|
let netstat_path = format!("{}/netstat", &project_folder_path);
|
|
let systeminfo_path = format!("{}/systeminfo", &project_folder_path);
|
|
write!(&mut general_notes, "
|
|
On the call:
|
|
|
|
Introductions
|
|
Let them know that their primary contact will be the PM and there should be
|
|
|
|
Go over general attack strategy/procedure.
|
|
We will get a beacon payload by the time the test starts
|
|
The beacon payload should be executed on a domain joined windows system.
|
|
If the system is not domain joined/no domain - let Seth know as this modifies the standard beacon
|
|
Select a user based on a department/role that they would like tested (Marketing, Sales, HR, IT)
|
|
This can be a test system with a cloned user, but then we don't get keylogging or screen grabs
|
|
The beacon is created using Cobalt Strike and communicates over HTTPS
|
|
Since Cobalt Strike is very well signatured, remind them that they may need to add an exclusion in antivirus and/or web filter
|
|
We will look at local privilege escalation, conduct portscans, password sprays, targeted vulnerability scanning (NOT NESSUS), lateral movement opportunities, and escalating to DOMAIN ADMIN privilege.
|
|
Ask if they want a focus on any particular assets. for example, an old time logging system, or remote access system.
|
|
|
|
Ask if they have any questions or concerns
|
|
|
|
Do they have a specific contact
|
|
|
|
Email any follow-up items from the call to the PM
|
|
").expect("error writing PPC text");
|
|
write!(&mut attack_notes,"
|
|
# current dat (ex: 7/5)
|
|
Got Persistence via (schtasks, bat schtasks, startup folder)
|
|
```
|
|
```
|
|
|
|
whoami /all
|
|
```
|
|
```
|
|
|
|
|
|
ipconfig /all
|
|
```
|
|
```
|
|
|
|
|
|
netstat -ano
|
|
[[{}|netstat]]
|
|
|
|
|
|
net accounts
|
|
```
|
|
```
|
|
|
|
|
|
net accounts /domain
|
|
```
|
|
```
|
|
|
|
|
|
net localgroup administrators
|
|
```
|
|
```
|
|
|
|
Net group \"domain admins\" /domain
|
|
```
|
|
```
|
|
|
|
|
|
net share
|
|
```
|
|
```
|
|
|
|
|
|
net use
|
|
```
|
|
```
|
|
|
|
|
|
systeminfo
|
|
[[{}|systeminfo]]
|
|
|
|
|
|
powerup.ps1/sharpup.exe notes.
|
|
```
|
|
```
|
|
|
|
", netstat_path, systeminfo_path).expect("error writing to attack notes for internal tests");
|
|
write!(&mut finding_notes, "
|
|
# normal findings
|
|
|
|
# data exfil
|
|
## [Sarting Username]
|
|
|
|
").expect("error writing to findings notes on internal");
|
|
write!(&mut todo_notes, "
|
|
|
|
- [ ] local checks
|
|
- [ ] find shares
|
|
- [ ] snaffle
|
|
- [ ] bloodhound
|
|
- [ ] admin or RDP?
|
|
- [ ] certify
|
|
- [ ] portscan
|
|
- [ ] sql stuff
|
|
- [ ] passwords in AD Descriptions?
|
|
- [ ] password spray
|
|
").expect("error writing todo list");
|
|
write!(&mut netsta,"
|
|
```
|
|
|
|
```").expect("error writing code block to system info");
|
|
write!(&mut systeminfo,"
|
|
```
|
|
|
|
```").expect("error writing code block to system info");
|
|
write!(&mut password_spray, "
|
|
|
|
- [ ] useraspass
|
|
- [ ] Seasonyear!
|
|
- [ ] Seasonyear
|
|
- [ ] seasonyear!
|
|
- [ ] seasonyear
|
|
- [ ] {comapny_name}year!
|
|
- [ ] {company_name}year
|
|
- [ ] {comapny_name}foundingyear!
|
|
- [ ] {company_name}foundingyear
|
|
- [ ] {company_name}streetnumber!
|
|
- [ ] {company_name}streetnumber
|
|
- [ ] Password
|
|
- [ ] P@ssw0rd
|
|
- [ ] Password1!
|
|
- [ ] Passwordyear!
|
|
- [ ] P@55w0rd
|
|
- [ ] P@$$w0rd
|
|
- [ ] Service
|
|
- [ ] Service!
|
|
- [ ] Serviceyear!
|
|
", company_name=comapny_name).expect("error writing password spray check list");
|
|
}
|
|
|
|
fn main() {
|
|
// change this to you own pentest notes folder
|
|
let mut pentest_notes = String::new();
|
|
// change this where you store your files for writing pentests
|
|
let mut project_files = String::new();
|
|
let args: Vec<String> = env::args().collect();
|
|
let usage = "
|
|
Welcome!!
|
|
|
|
This tool uses a config file at ~/.config/pyro_pentesting/tools/start_pentest.conf
|
|
If this file does not exist configuration creation function will run promping you for the paths needed for this program to run.
|
|
|
|
./start_pentest /path/to/scope.txt/file company_name project_name
|
|
|
|
Please make sure the type of pentest is included in the project name, such as internal, external, or webapp(to be implemented)
|
|
|
|
example:
|
|
start_pentest ./scope.txt victim_company_incorporated 2022_external_pentest
|
|
";
|
|
let mut config_file_path_buf = PathBuf::new();
|
|
config_file_path_buf.push(home_dir().expect("error reading home dir in main()"));
|
|
config_file_path_buf.push(".config/pyro_pentest_tools/start_pentest.conf");
|
|
println!("checking installation status");
|
|
if Path::new(&config_file_path_buf).exists(){
|
|
println!("reading existing configuration file");
|
|
}
|
|
else{
|
|
println!("no existing installation found");
|
|
install();
|
|
}
|
|
let config_string = fs::read_to_string(config_file_path_buf).expect("error reading ");
|
|
if config_string.contains("folder_path") && config_string.contains("notes_path"){
|
|
let config_string_vec: Vec<&str> = config_string.split("\n").collect();
|
|
for line in config_string_vec{
|
|
if line.contains("project_folder_path"){
|
|
let line_vec: Vec<&str> = line.split(":").collect();
|
|
project_files = line_vec[1].to_owned();
|
|
}
|
|
else if line.contains("project_notes_path"){
|
|
let line_vec: Vec<&str> = line.split(":").collect();
|
|
pentest_notes = line_vec[1].to_owned();
|
|
}
|
|
}
|
|
}
|
|
println!("Project files path: {}\nProject Notes path: {}", project_files, pentest_notes);
|
|
if args.len() == 4{
|
|
// the following two lines make the scope a vector
|
|
let scope_content = fs::read_to_string(&args[1]).expect("Error reading scope file");
|
|
let scope: Vec<&str> = scope_content.split("\n").collect();
|
|
let company_name = &args[2];
|
|
let project_name = &args[3];
|
|
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, scope);
|
|
}
|
|
else if project_name.contains("external") {
|
|
println!("external pentest type detected, auto populating notes with external layout...");
|
|
external(project_folder_path, company_name, project_name, scope);
|
|
}
|
|
else if project_name.contains("webapp") {
|
|
println!("not implemented yet sorry");
|
|
println!("default file folder structure used, and empty notes folder created...")
|
|
}
|
|
else{
|
|
println!("unknown project type detected, default folder strucutre and empty note folder created...");
|
|
print!("
|
|
Known project types:
|
|
Internal Penetration Test
|
|
External Penetartion Test
|
|
|
|
If this test is actually one of these types please include the type in the project name parameter, example: 2023_internal_pentest.
|
|
If this test is a common test and you would like a default note structure implemented in this script let Kevin \"Kage\" Gunter know and supply an example markdown note sheet.");
|
|
}
|
|
}
|
|
|
|
else{
|
|
print!("{}", usage);
|
|
}
|
|
|
|
}
|