wrote the tool

This commit is contained in:
2026-06-17 12:01:25 -05:00
parent dcd775098a
commit 889bc86c50
3 changed files with 89 additions and 0 deletions
+5
View File
@@ -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
+9
View File
@@ -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
View File
@@ -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(())
}