wrote the tool
This commit is contained in:
@@ -16,3 +16,8 @@ target/
|
|||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
|
||||||
|
/target
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "own-users"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.6.1", features = ["derive"] }
|
||||||
|
neo4rs = "0.8.0"
|
||||||
|
tokio = { version = "1.52.3", features = ["full"] }
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use neo4rs::{Graph, query};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, BufRead};
|
||||||
|
use std::path::Path;
|
||||||
|
use tokio;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[command(
|
||||||
|
name = "BloodHound Owned Marker",
|
||||||
|
version = "1.0",
|
||||||
|
about = "Marks a list of usernames as owned inside a BloodHound Neo4j database"
|
||||||
|
)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short, long)]
|
||||||
|
input: String,
|
||||||
|
|
||||||
|
#[arg(short, long, default_value = "bolt://localhost:7687")]
|
||||||
|
address: String,
|
||||||
|
|
||||||
|
#[arg(short, long, default_value = "neo4j")]
|
||||||
|
user: String,
|
||||||
|
|
||||||
|
#[arg(short, long, default_value = "neo4j")]
|
||||||
|
pass: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let args = Args::parse();
|
||||||
|
if !Path::new(&args.input).exists() {
|
||||||
|
eprintln!("Error: Input file '{}' does not exist.", args.input);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
println!("Connecting to Neo4j database at {}...", args.address);
|
||||||
|
let graph = match Graph::new(&args.address, &args.user, &args.pass).await {
|
||||||
|
Ok(g) => g,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to initialize Neo4j connection configuration: {}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Err(e) = graph.run(query("RETURN 1")).await {
|
||||||
|
eprintln!(
|
||||||
|
"Database connection error: {}. Check your URI and credentials.",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
println!("Connected successfully!");
|
||||||
|
let file = File::open(&args.input)?;
|
||||||
|
let reader = io::BufReader::new(file);
|
||||||
|
let mut count = 0;
|
||||||
|
for line in reader.lines() {
|
||||||
|
let raw_user = line?;
|
||||||
|
let username = raw_user.trim();
|
||||||
|
if username.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cypher_query =
|
||||||
|
query("MATCH (u:User) WHERE toUpper(u.name) = toUpper($name) SET u.owned = true")
|
||||||
|
.param("name", username);
|
||||||
|
match graph.run(cypher_query).await {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("[-] Marked as owned: {}", username);
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[!] Error marking user '{}': {}", username, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("\nTask completed. Total users marked as owned: {}", count);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user