Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df9c8899b2 | ||
|
|
ec23b722f1 | ||
|
|
c97e05008d |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -257,7 +257,7 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "snaferrous"
|
||||
version = "0.1.0"
|
||||
version = "1.2.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"colored",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "snaferrous"
|
||||
version = "0.1.0"
|
||||
version = "1.2.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -22,6 +22,12 @@ Options:
|
||||
|
||||
-t, --targets <TARGETS> specific targets. should be comma separated.
|
||||
|
||||
-f, --filter_targets <targets> specific targets that should be ingored. Comma separated.
|
||||
|
||||
-l, --local scan the current hot's file system (defaults to false)
|
||||
|
||||
-d --disable_network disable network file discovery
|
||||
|
||||
-v, --verbose echo all found files to the console, regardless of keyword matching. (all files will still be saved to the log file)
|
||||
|
||||
-h, --help Print help (see more with '--help')
|
||||
|
||||
210
src/main.rs
210
src/main.rs
@@ -12,24 +12,10 @@ use tokio;
|
||||
use tokio::sync::mpsc::{channel, Sender};
|
||||
|
||||
/*
|
||||
Author: Kevin (Kaged Pyro) Gunter
|
||||
Author: Kevin (Bu4$t_Py40) Gunter
|
||||
Purpose: I got tired of snaffler getting caught, so I rewrote it in rust, which edrs have trouble detecting.
|
||||
|
||||
*/
|
||||
|
||||
/*#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = Some("finds shares, but its written in rust which sometimes gets past EDR!"))]
|
||||
struct Args{
|
||||
#[arg(short, long, help = "path to save output file Defaults to not saving output.")]
|
||||
outfile: Option<PathBuf>,
|
||||
|
||||
#[arg(short, long, help = "number of threads to use, default to 10. \nNote thre thread count will be doubled, one set for share finder tasks, and one set for file and infor finding tasks.")]
|
||||
threads: Option<usize>,
|
||||
|
||||
#[arg(short, long, help = "specific targets. should be comma separated.")]
|
||||
targets: Option<String>,
|
||||
}*/
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = Some("finds shares, but its written in rust which sometimes gets past EDR!"))]
|
||||
struct Args{
|
||||
@@ -42,8 +28,17 @@ struct Args{
|
||||
#[arg(short, long, help = "specific targets. should be comma separated.")]
|
||||
targets: Option<String>,
|
||||
|
||||
#[arg(short, long, help = "specific targets that should be ignored. comma separated.")]
|
||||
filter_targets: Option<String>,
|
||||
|
||||
#[arg(short, long, help = "echo all found files to the console, regardless of keyword matching. (all files will still be saved to the log file)")]
|
||||
verbose: bool,
|
||||
|
||||
#[arg(short, long, help = "scan only the current host's files")]
|
||||
local: bool,
|
||||
|
||||
#[arg(short, long, help = "disable network discovery")]
|
||||
diable_network: bool
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -151,6 +146,8 @@ async fn task_handler(id: usize, current_task: FinderTask, tx: Sender<Message>){
|
||||
"it",
|
||||
"identified",
|
||||
"username",
|
||||
"admin",
|
||||
"administrator",
|
||||
];
|
||||
let mut file_content = String::new();
|
||||
for extension in &files_to_read{
|
||||
@@ -197,11 +194,87 @@ async fn task_handler(id: usize, current_task: FinderTask, tx: Sender<Message>){
|
||||
|
||||
#[tokio::main]
|
||||
async fn main(){
|
||||
print!{
|
||||
"
|
||||
██▒▒
|
||||
▒▒████ ▓▓████████▓▓
|
||||
▒▒██████████ ██████████████
|
||||
██████████████ ▒▒██████████████
|
||||
████████████████ ████████████████
|
||||
████████████████▓▓ ▓▓████████████████
|
||||
██████████████████▓▓██████████████████████
|
||||
██████████████████████████████████████████ ▓▓██
|
||||
██████████████████████████████████████████ ▒▒████████
|
||||
▒▒████ ██████████████████████████████████████████████ ██████████████
|
||||
████████▓▓ ▒▒██████████████████████████████████████████████████████████████████
|
||||
████████████████▓▓████████████████████████████████████████████████████████████████████████
|
||||
██████████████████████████████████████████████████████████████████████████████████████████▓▓
|
||||
████████████████████████████████████████▓▓ ▓▓██████████████████████████████████
|
||||
██████████████████████████████████▓▓ ████████████████████████████▒▒
|
||||
██████████████████████████████ ████████████████████████
|
||||
████████████████████████▓▓ ▓▓██████████████████
|
||||
▒▒████████████████████▒▒ ████████████████
|
||||
▒▒████████████████▒▒ /----------------------------------\\ ██████████████
|
||||
██████████████▓▓ / \\ ████████████▓▓
|
||||
██████████████ / \\ ▓▓████████████████████▓▓▓▓
|
||||
▓▓████████████░░ / \\ ████████████████████████
|
||||
░░██████████████ / |-| |-| \\ ▓▓██████████████████████▓▓
|
||||
████████████████████████░░ / | | | | \\ ████████████████████████
|
||||
▓▓██████████████████████████ / | | | | \\ ████████████████████████
|
||||
██████████████████████████▒▒ / | | | | \\ ▒▒██████████████████████
|
||||
██████████████████████████ / | | | | \\ ██████████████████████
|
||||
░░██████████████████████████ / | | | | \\ ████████████████████▓▓
|
||||
▒▒██████████████████████████ / | | | | \\ ████████████████▓▓
|
||||
▓▓██████████████████████████ \\ | | | | / ██████████████
|
||||
▓▓██████████████████████ \\ | | | | / ████████████
|
||||
▓▓████████████████ \\ | | | | / ████████████
|
||||
▓▓████████████ \\ | | | | / ████████████
|
||||
████████████ \\ | | | | / ████████████
|
||||
████████████▒▒ \\ | | | | / ██████████████▒▒
|
||||
██████████████ \\ |-| |-| / ▓▓████████████████▓▓
|
||||
██████████████ \\ / ██████████████████████
|
||||
▒▒██████████████████ \\ / ▒▒████████████████████████
|
||||
██████████████████████ \\ / ████████████████████████
|
||||
██████████████████████████ \\----------------------------------/ ▓▓████████████████████████
|
||||
██████████████████████████████ ░░████████████████████████▓▓
|
||||
██████████████████████████████▒▒ ██████████████████████████
|
||||
░░██████████████████████████████░░ ██████████████░░ ▒▒██████
|
||||
████████████████████████████████ ████████████████
|
||||
▒▒████████████████████████████████░░ ▒▒████████████████
|
||||
██████▓▓▒▒ ██████████████████ ████████████████████
|
||||
████████████████████▒▒ ▒▒████████████████████████
|
||||
██████████████████████████▓▓▓▓▓▓████████████████████████████████▒▒
|
||||
██████████████████████████████████████████████████████████████████
|
||||
██████████████████████████████████████████████████████████████████
|
||||
▓▓████████████████████████████████████████████████████████████████████
|
||||
██████████████████████████████████████████████ ░░██████████████████
|
||||
░░████████████████▒▒ ▒▒██████████████████ ████████████▒▒
|
||||
▒▒██████████████ ████████████████ ██████
|
||||
▓▓████████ ▓▓██████████████ ▒▒
|
||||
▒▒████▒▒ ██████████████
|
||||
██████████████
|
||||
██████████████
|
||||
|
||||
|
||||
|
||||
__ __
|
||||
/ _\\_ __ __ _ / _| ___ _ __ _ __ ___ _ _ ___
|
||||
\\ \\| '_ \\ / _` | |_ / _ \\ '__| '__/ _ \\| | | / __|
|
||||
_\\ \\ | | | (_| | _| __/ | | | | (_) | |_| \\__ \\
|
||||
\\__/_| |_|\\__,_|_| \\___|_| |_| \\___/ \\__,_|___/
|
||||
"
|
||||
|
||||
}
|
||||
let args = Args::parse();
|
||||
let mut outfile = PathBuf::new();
|
||||
let mut threads = 10;
|
||||
let mut save = false;
|
||||
let mut computers = Vec::new();
|
||||
let mut filter_computers = Vec::new();
|
||||
let mut network = true;
|
||||
let file_filter = vec![
|
||||
String::from("ADMIN$")
|
||||
];
|
||||
if args.outfile.is_some(){
|
||||
outfile = args.outfile.unwrap();
|
||||
save = true;
|
||||
@@ -209,59 +282,86 @@ async fn main(){
|
||||
if args.threads.is_some(){
|
||||
threads = args.threads.unwrap();
|
||||
}
|
||||
if args.diable_network{
|
||||
network = false;
|
||||
}
|
||||
if args.targets.is_some(){
|
||||
println!("gathering the targets you gave me.");
|
||||
let targets = args.targets.unwrap();
|
||||
if targets.contains(","){
|
||||
let split_targets: Vec<&str> = targets.split(",").collect();
|
||||
for target in split_targets{
|
||||
computers.push(target.to_string());
|
||||
computers.push(target.trim().to_lowercase());
|
||||
}
|
||||
}
|
||||
else{
|
||||
computers.push(targets);
|
||||
}
|
||||
}
|
||||
else{
|
||||
println!("no targets given, proceeding with domain computer enumeration...");
|
||||
println!("finding computers...");
|
||||
let command_string = String::from("net group \"domain computers\" /domain");
|
||||
let mut temp_file = fs::File::create("./temp.bat").unwrap();
|
||||
write!(temp_file, "{}", command_string).unwrap();
|
||||
let computer_res = Command::new(".\\temp.bat").output();
|
||||
let mut error_string = String::new();
|
||||
let mut success_string = String::new();
|
||||
fs::remove_file("./temp.bat").unwrap();
|
||||
if computer_res.is_ok(){
|
||||
let output = computer_res.unwrap();
|
||||
if output.stdout.len() > 0{
|
||||
success_string = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
if args.filter_targets.is_some(){
|
||||
println!("gathering the filter you specified!");
|
||||
let given_filter = args.filter_targets.unwrap();
|
||||
let filters: Vec<&str> = given_filter.split(",").collect();
|
||||
for filter in filters{
|
||||
filter_computers.push(filter.trim().to_lowercase());
|
||||
}
|
||||
}
|
||||
let hostname_res = Command::new("hostname").output();
|
||||
if hostname_res.is_ok(){
|
||||
let hostname_output = hostname_res.unwrap();
|
||||
if hostname_output.stdout.len() > 0{
|
||||
let hostname_string = String::from_utf8_lossy(&hostname_output.stdout).to_string();
|
||||
if args.local{
|
||||
computers.push(hostname_string.trim().to_lowercase());
|
||||
}
|
||||
else if output.stderr.len() > 0{
|
||||
error_string = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
else{
|
||||
filter_computers.push(hostname_string.trim().to_lowercase());
|
||||
}
|
||||
}
|
||||
else{
|
||||
error_string = computer_res.err().unwrap().to_string();
|
||||
}
|
||||
if error_string.len() > 0{
|
||||
eprintln!("{}", "error getting computers!".red());
|
||||
eprintln!("{}", error_string.red());
|
||||
exit(1);
|
||||
}
|
||||
if success_string.len() > 0{
|
||||
for line in success_string.lines(){
|
||||
if line.contains("$"){
|
||||
let words:Vec<&str> = line.split_whitespace().collect();
|
||||
for word in words{
|
||||
let mut computer_name = word.to_string();
|
||||
computer_name.pop();
|
||||
computers.push(computer_name);
|
||||
if network{
|
||||
println!("no targets given, proceeding with domain computer enumeration...");
|
||||
println!("finding computers...");
|
||||
let command_string = String::from("net group \"domain computers\" /domain");
|
||||
let mut temp_file = fs::File::create("./temp.bat").unwrap();
|
||||
write!(temp_file, "{}", command_string).unwrap();
|
||||
let computer_res = Command::new(".\\\\temp.bat").output();
|
||||
let mut error_string = String::new();
|
||||
let mut success_string = String::new();
|
||||
fs::remove_file("./temp.bat").unwrap();
|
||||
if computer_res.is_ok(){
|
||||
let output = computer_res.unwrap();
|
||||
if output.stdout.len() > 0{
|
||||
success_string = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
}
|
||||
else if output.stderr.len() > 0{
|
||||
error_string = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
}
|
||||
}
|
||||
else{
|
||||
error_string = computer_res.err().unwrap().to_string();
|
||||
}
|
||||
if error_string.len() > 0{
|
||||
eprintln!("{}", "error getting computers!".red());
|
||||
eprintln!("{}", error_string.red());
|
||||
exit(1);
|
||||
}
|
||||
if success_string.len() > 0{
|
||||
for line in success_string.lines(){
|
||||
if line.contains("$"){
|
||||
let words:Vec<&str> = line.split_whitespace().collect();
|
||||
for word in words{
|
||||
let mut computer_name = word.to_string();
|
||||
computer_name.pop();
|
||||
computers.push(computer_name.trim().to_lowercase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if filter_computers.len() > 0{
|
||||
computers.retain(|x| !filter_computers.iter().any(|y| y==x));
|
||||
}
|
||||
let mut tasks = Vec::new();
|
||||
let mut id_counter = 0;
|
||||
for computer in &computers{
|
||||
@@ -331,7 +431,7 @@ async fn main(){
|
||||
}
|
||||
else{
|
||||
let mut save_file = open_res.unwrap();
|
||||
let write_res = write!(save_file,"share found! {}\n", finding.path);
|
||||
let write_res = write!(save_file,"share found! {}\\n", finding.path);
|
||||
if write_res.is_err(){
|
||||
if !continue_wihtout_save{
|
||||
eprintln!("{}", "error writing to save file!".red());
|
||||
@@ -352,9 +452,11 @@ async fn main(){
|
||||
}
|
||||
}
|
||||
}
|
||||
let new_task = FinderTask{id: id_counter, tasktype: TaskType::File, target: finding.path};
|
||||
tasks.push(new_task);
|
||||
id_counter += 1;
|
||||
if !file_filter.contains(&finding.path){
|
||||
let new_task = FinderTask{id: id_counter, tasktype: TaskType::File, target: finding.path};
|
||||
tasks.push(new_task);
|
||||
id_counter += 1;
|
||||
}
|
||||
}
|
||||
TaskType::File => {
|
||||
let new_task = FinderTask{id: id_counter, tasktype: TaskType::Info, target: finding.path};
|
||||
@@ -383,7 +485,7 @@ async fn main(){
|
||||
}
|
||||
else{
|
||||
let mut save_file = open_res.unwrap();
|
||||
let write_res = write!(save_file,"keyword match at {}\n", finding.path);
|
||||
let write_res = write!(save_file,"keyword match at {}\\n", finding.path);
|
||||
if write_res.is_err(){
|
||||
if !continue_wihtout_save{
|
||||
eprintln!("{}", "error writing to save file!".red());
|
||||
@@ -428,7 +530,7 @@ async fn main(){
|
||||
}
|
||||
else{
|
||||
let mut save_file = open_res.unwrap();
|
||||
let write_res = write!(save_file,"file found! {}\n", finding.path);
|
||||
let write_res = write!(save_file,"file found! {}\\n", finding.path);
|
||||
if write_res.is_err(){
|
||||
if !continue_wihtout_save{
|
||||
eprintln!("{}", "error writing to save file!".red());
|
||||
|
||||
Reference in New Issue
Block a user