Added the ability to write the host_notes from the nessus import, also
restructured ALOT of code into seperate files to make it easier to find things.
This commit is contained in:
+163
@@ -0,0 +1,163 @@
|
|||||||
|
use keyring::Entry;
|
||||||
|
use rustls::{ClientConfig, ClientConnection, RootCertStore, StreamOwned, pki_types::ServerName};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::{BufReader, Read, Write};
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::time::{self, Instant};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Server {
|
||||||
|
pub address: String,
|
||||||
|
pub connected: bool,
|
||||||
|
pub timer: Duration,
|
||||||
|
pub config: Option<Arc<ClientConfig>>,
|
||||||
|
pub last_check: time::Instant,
|
||||||
|
pub message_que: Vec<String>,
|
||||||
|
pub action_que: Vec<String>,
|
||||||
|
pub client_id: usize,
|
||||||
|
pub selected_client: usize,
|
||||||
|
pub logged_in: bool,
|
||||||
|
pub password: String,
|
||||||
|
pub name: String,
|
||||||
|
pub cert_text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
pub fn donwload_certificate(&self) -> Result<String, Box<dyn Error>> {
|
||||||
|
let mut stream = TcpStream::connect(self.address.clone())?;
|
||||||
|
stream.write_all("CERT_REQ".as_bytes())?;
|
||||||
|
let mut buf = [0u8; 8192];
|
||||||
|
let bytes_read = stream.read(&mut buf)?;
|
||||||
|
let response = String::from_utf8_lossy(&buf[..bytes_read]);
|
||||||
|
if let Some((_, cert)) = response.split_once("|") {
|
||||||
|
return Ok(cert.to_string());
|
||||||
|
}
|
||||||
|
Err("Server did not send certificate".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect(&mut self) -> Result<usize, Box<dyn Error>> {
|
||||||
|
if let Ok(cert) = self.donwload_certificate() {
|
||||||
|
self.config = Some(self.build_tls_config(cert.as_str())?);
|
||||||
|
self.cert_text = cert;
|
||||||
|
}
|
||||||
|
let mut stream = self.tls_connect()?;
|
||||||
|
stream.write("HELLO|attack".as_bytes())?;
|
||||||
|
let mut buf = [0; 8192];
|
||||||
|
let bytes_read = stream.read(&mut buf)?;
|
||||||
|
let response = String::from_utf8_lossy(&buf[..bytes_read]);
|
||||||
|
if let Some((_, id)) = response.split_once("|") {
|
||||||
|
self.client_id = id.trim().parse()?;
|
||||||
|
}
|
||||||
|
self.connected = true;
|
||||||
|
self.last_check = Instant::now();
|
||||||
|
let entry = Entry::new("tetanus", &self.address)?;
|
||||||
|
if let Ok(password) = entry.get_password() {
|
||||||
|
self.login(password)?;
|
||||||
|
}
|
||||||
|
return Ok(self.client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn login(&mut self, pass: String) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut stream = self.tls_connect()?;
|
||||||
|
stream.write(format!("NONE**{}|||LOGIN|{}||", self.client_id, pass).as_bytes())?;
|
||||||
|
let mut buf = [0; 8192];
|
||||||
|
let bytes_read = stream.read(&mut buf)?;
|
||||||
|
let response = String::from_utf8_lossy(&buf[..bytes_read]);
|
||||||
|
if response.contains("successful") {
|
||||||
|
self.password = pass;
|
||||||
|
self.last_check = Instant::now();
|
||||||
|
self.logged_in = true;
|
||||||
|
self.message_que.push(format!("SET_NAME|{}", self.name));
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
return Err("[error] logging in!".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkin(&mut self) {
|
||||||
|
if self.logged_in {
|
||||||
|
if let Ok(mut stream) = self.tls_connect() {
|
||||||
|
self.last_check = Instant::now();
|
||||||
|
let payload = format!(
|
||||||
|
"{}**{}|||{}\n",
|
||||||
|
self.password.clone(),
|
||||||
|
self.client_id.clone(),
|
||||||
|
self.message_que.join("||")
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = stream.write_all(payload.as_bytes()) {
|
||||||
|
self.action_que
|
||||||
|
.push(format!("Error|sending reponse output to server! {e}"));
|
||||||
|
}
|
||||||
|
self.message_que.clear();
|
||||||
|
let mut buffer = [0; 4096];
|
||||||
|
if let Ok(bytes_read) = stream.read(&mut buffer) {
|
||||||
|
if bytes_read > 0 {
|
||||||
|
let response = String::from_utf8_lossy(&buffer[..bytes_read]);
|
||||||
|
response.split("||").into_iter().for_each(|action| {
|
||||||
|
self.action_que.push(action.trim().to_string());
|
||||||
|
if action.contains("Not authenticated") {
|
||||||
|
self.logged_in = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_tls_config(&self, pem: &str) -> Result<Arc<ClientConfig>, Box<dyn Error>> {
|
||||||
|
let mut roots = RootCertStore::empty();
|
||||||
|
let mut reader = BufReader::new(pem.as_bytes());
|
||||||
|
let certs = rustls_pemfile::certs(&mut reader).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
for cert in certs {
|
||||||
|
roots.add(cert)?;
|
||||||
|
}
|
||||||
|
let config = ClientConfig::builder()
|
||||||
|
.with_root_certificates(roots)
|
||||||
|
.with_no_client_auth();
|
||||||
|
Ok(Arc::new(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tls_connect(&self) -> Result<StreamOwned<ClientConnection, TcpStream>, Box<dyn Error>> {
|
||||||
|
let config = self.config.clone().ok_or("TLS config not loaded")?;
|
||||||
|
let tcp = TcpStream::connect(&self.address)?;
|
||||||
|
let (host, _) = self.address.split_once(':').ok_or("Invalid address")?;
|
||||||
|
let server_name = ServerName::try_from(host.to_string())?;
|
||||||
|
let connection = ClientConnection::new(config, server_name)?;
|
||||||
|
let tls_stream = StreamOwned::new(connection, tcp);
|
||||||
|
Ok(tls_stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disconnect(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut stream = self.tls_connect()?;
|
||||||
|
stream.write(format!("{}**{}|||DISCONNECT||", self.password, self.client_id).as_bytes())?;
|
||||||
|
self.connected = false;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(&mut self, mut path: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||||
|
path.push(format!("{}.conf", self.address));
|
||||||
|
let mut conf_file = OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(path)?;
|
||||||
|
let outdata = format!(
|
||||||
|
"
|
||||||
|
name: {}
|
||||||
|
address: {}
|
||||||
|
cert: {}
|
||||||
|
",
|
||||||
|
self.name, self.address, self.cert_text
|
||||||
|
);
|
||||||
|
write!(conf_file, "{}", outdata)?;
|
||||||
|
let entry = Entry::new("tetanus", &self.address)?;
|
||||||
|
entry.set_password(&self.password)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
+197
@@ -0,0 +1,197 @@
|
|||||||
|
use crate::ShodanData;
|
||||||
|
use crate::ToolMessage;
|
||||||
|
use serde_json;
|
||||||
|
use shodan_rust::ShodanClient;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Host {
|
||||||
|
pub ip: String,
|
||||||
|
pub hostname: String,
|
||||||
|
pub open_ports: Vec<usize>,
|
||||||
|
pub control_port: usize,
|
||||||
|
pub users: Vec<User>,
|
||||||
|
pub pwned: bool,
|
||||||
|
pub id: usize,
|
||||||
|
pub findings: Vec<String>,
|
||||||
|
pub shodan_data: Option<ShodanData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Host {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
ip: String::new(),
|
||||||
|
hostname: String::new(),
|
||||||
|
open_ports: Vec::new(),
|
||||||
|
control_port: 0,
|
||||||
|
users: Vec::new(),
|
||||||
|
pwned: false,
|
||||||
|
id: 0,
|
||||||
|
findings: Vec::new(),
|
||||||
|
shodan_data: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip(&mut self, ip: String) {
|
||||||
|
self.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hostname(&mut self, name: String) {
|
||||||
|
self.hostname = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_ports(&mut self, ports: Vec<usize>) {
|
||||||
|
self.open_ports = ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn control_port(&mut self, port: usize) {
|
||||||
|
self.control_port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn users(&mut self, users: Vec<User>) {
|
||||||
|
self.users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pwnd(&mut self) {
|
||||||
|
self.pwned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&mut self, id: usize) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn findings(&mut self, findings: Vec<String>) {
|
||||||
|
self.findings = findings;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_port(&mut self, port: &str) {
|
||||||
|
if let Ok(port) = port.trim().parse() {
|
||||||
|
if !self.open_ports.contains(&port) && port != 0 {
|
||||||
|
self.open_ports.push(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_user(&mut self, user: User) {
|
||||||
|
self.users.push(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_finding(&mut self, finding: String) {
|
||||||
|
self.findings.push(finding);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_config_file(&mut self, path: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut host_file = File::create(path)?;
|
||||||
|
let mut out_string = format!(
|
||||||
|
"
|
||||||
|
ip: {}
|
||||||
|
hostname: {}
|
||||||
|
control_port: {}
|
||||||
|
pwned: {}
|
||||||
|
id: {}",
|
||||||
|
self.ip, self.hostname, self.control_port, self.pwned, self.id
|
||||||
|
);
|
||||||
|
if !self.findings.is_empty() {
|
||||||
|
out_string.push_str(&format!("\nfindings: "));
|
||||||
|
out_string.push_str(&self.findings.join(","));
|
||||||
|
}
|
||||||
|
if !self.open_ports.is_empty() {
|
||||||
|
out_string.push_str("\nopen_ports: ");
|
||||||
|
out_string.push_str(
|
||||||
|
&self
|
||||||
|
.open_ports
|
||||||
|
.iter()
|
||||||
|
.map(|port| port.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(","),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
write!(host_file, "{}", out_string)?;
|
||||||
|
host_file.sync_all()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_port(&mut self, port: u16, tx: Sender<ToolMessage>) -> Result<(), Box<dyn Error>> {
|
||||||
|
if let Ok(ip) = self.ip.parse::<IpAddr>() {
|
||||||
|
let address = SocketAddr::new(ip, port);
|
||||||
|
if let Ok(_) = TcpStream::connect_timeout(&address, Duration::from_secs(3)) {
|
||||||
|
self.add_port(&format!("{}", port));
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
format!("[success] {} is open on {}", port, self.ip),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
format!("[error] {} is not a valid ip address!", self.ip),
|
||||||
|
)));
|
||||||
|
return Err("not valid IP".into());
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_shodan(&mut self, key: String, tx: Sender<ToolMessage>) {
|
||||||
|
let client = ShodanClient::new(key);
|
||||||
|
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
runtime.block_on(async {
|
||||||
|
if let Ok(data) = client.host_info(&self.ip).await {
|
||||||
|
if let Ok(new_data) = serde_json::from_str::<ShodanData>(&data.to_string()) {
|
||||||
|
if let Some(ports) = new_data.ports {
|
||||||
|
ports.iter().for_each(|p| {
|
||||||
|
self.add_port(&p.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(vulns) = new_data.vulns {
|
||||||
|
vulns.iter().for_each(|v| {
|
||||||
|
self.findings.push(format!("shodan: {}", v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
"[error] parsing shodand data!".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
"[error] getting shodand data!".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
format!("shodan_function finished for {}", self.ip),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct User {
|
||||||
|
pub name: String,
|
||||||
|
pub password: Option<String>,
|
||||||
|
pub hash: Option<String>,
|
||||||
|
pub ticket: Option<PathBuf>,
|
||||||
|
pub compromised: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
name: String::new(),
|
||||||
|
password: None,
|
||||||
|
hash: None,
|
||||||
|
ticket: None,
|
||||||
|
compromised: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+140
-1051
File diff suppressed because it is too large
Load Diff
+241
@@ -0,0 +1,241 @@
|
|||||||
|
use crate::Project;
|
||||||
|
use crate::host::Host;
|
||||||
|
use crate::project::ToolCommand;
|
||||||
|
use ipnet::IpNet;
|
||||||
|
use rhai::{AST, Engine};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::{read_dir, read_to_string};
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct ModuleLoader {
|
||||||
|
pub engine: Arc<Engine>,
|
||||||
|
pub commands: HashMap<String, ToolCommand>,
|
||||||
|
pub asts: HashMap<String, AST>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleLoader {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
engine
|
||||||
|
.register_type_with_name::<PathBuf>("PathBuf")
|
||||||
|
.register_get_set(
|
||||||
|
"display",
|
||||||
|
|p: &mut PathBuf| p.to_string_lossy().into_owned(),
|
||||||
|
|p: &mut PathBuf, s: String| *p = PathBuf::from(s),
|
||||||
|
);
|
||||||
|
engine
|
||||||
|
.register_type_with_name::<Host>("Host")
|
||||||
|
.register_get_set(
|
||||||
|
"ip",
|
||||||
|
|h: &mut Host| h.ip.clone(),
|
||||||
|
|h: &mut Host, val: String| h.ip = val,
|
||||||
|
)
|
||||||
|
.register_get_set(
|
||||||
|
"hostname",
|
||||||
|
|h: &mut Host| h.hostname.clone(),
|
||||||
|
|h: &mut Host, val: String| h.hostname = val,
|
||||||
|
)
|
||||||
|
.register_get_set(
|
||||||
|
"pwned",
|
||||||
|
|h: &mut Host| h.pwned,
|
||||||
|
|h: &mut Host, val: bool| h.pwned = val,
|
||||||
|
)
|
||||||
|
.register_fn("add_port", Host::add_port)
|
||||||
|
.register_fn("add_finding", Host::add_finding);
|
||||||
|
engine
|
||||||
|
.register_type_with_name::<Project>("Project")
|
||||||
|
.register_get_set(
|
||||||
|
"name",
|
||||||
|
|p: &mut Project| p.name.clone(),
|
||||||
|
|p: &mut Project, val: String| p.name = val,
|
||||||
|
)
|
||||||
|
.register_get_set(
|
||||||
|
"org_name",
|
||||||
|
|p: &mut Project| p.org_name.clone(),
|
||||||
|
|p: &mut Project, val: String| p.org_name = val,
|
||||||
|
)
|
||||||
|
.register_get_set(
|
||||||
|
"current",
|
||||||
|
|p: &mut Project| p.current.clone(),
|
||||||
|
|p: &mut Project, val: bool| p.current = val,
|
||||||
|
)
|
||||||
|
.register_get_set(
|
||||||
|
"notes",
|
||||||
|
|p: &mut Project| p.notes.clone(),
|
||||||
|
|p: &mut Project, val: PathBuf| p.notes = val,
|
||||||
|
)
|
||||||
|
.register_get_set(
|
||||||
|
"files",
|
||||||
|
|p: &mut Project| p.files.clone(),
|
||||||
|
|p: &mut Project, val: PathBuf| p.files = val,
|
||||||
|
)
|
||||||
|
.register_fn("add_host", Project::add_host);
|
||||||
|
engine.register_fn("get_host", |hosts: &mut Vec<Host>, index: i64| {
|
||||||
|
hosts.get(index as usize).cloned().unwrap_or_else(Host::new)
|
||||||
|
});
|
||||||
|
engine.register_fn("new_host", Host::new);
|
||||||
|
engine.register_fn("open_file", |path: &str| {
|
||||||
|
std::fs::read_to_string(path).unwrap_or_else(|_| String::new())
|
||||||
|
});
|
||||||
|
engine.register_fn("add_port", |host: &mut Host, port: i64| {
|
||||||
|
host.add_port(format!("{}", port).as_str());
|
||||||
|
});
|
||||||
|
engine.register_fn("expand_target", |s: &str| -> rhai::Array {
|
||||||
|
let mut results = rhai::Array::new();
|
||||||
|
if let Ok(net) = s.trim().parse::<IpNet>() {
|
||||||
|
for host in net.hosts() {
|
||||||
|
results.push(host.to_string().into());
|
||||||
|
}
|
||||||
|
} else if let Ok(ip) = s.trim().parse::<IpAddr>() {
|
||||||
|
results.push(ip.to_string().into());
|
||||||
|
} else if s.contains(".") {
|
||||||
|
results.push(s.to_string().into());
|
||||||
|
}
|
||||||
|
results
|
||||||
|
});
|
||||||
|
engine.register_fn("filter_ips", |s: &str| -> rhai::Array {
|
||||||
|
let mut results = rhai::Array::new();
|
||||||
|
if let Ok(net) = s.trim().parse::<IpNet>() {
|
||||||
|
results.push(net.addr().to_string().trim().into());
|
||||||
|
} else if let Ok(ip) = s.trim().parse::<IpAddr>() {
|
||||||
|
results.push(ip.to_string().trim().into());
|
||||||
|
} else if s.contains(".") {
|
||||||
|
results.push(s.to_string().trim().into());
|
||||||
|
}
|
||||||
|
results
|
||||||
|
});
|
||||||
|
engine.register_fn("write_file", |path: &str, contents: &str| {
|
||||||
|
std::fs::write(path, contents).is_ok()
|
||||||
|
});
|
||||||
|
engine.register_fn("find_file", |path: PathBuf, filename: String| -> String {
|
||||||
|
for entry in walkdir::WalkDir::new(path).max_depth(50) {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
if entry
|
||||||
|
.file_name()
|
||||||
|
.to_string_lossy()
|
||||||
|
.contains(filename.as_str())
|
||||||
|
{
|
||||||
|
return entry.path().display().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String::new()
|
||||||
|
});
|
||||||
|
engine.register_fn("execute", |cmd: &str| -> String {
|
||||||
|
let out_string;
|
||||||
|
if let Ok(output) = Command::new("sh").arg("-c").arg(cmd).output() {
|
||||||
|
if output.status.success() {
|
||||||
|
out_string = format!("[success] {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
} else {
|
||||||
|
out_string = format!("[error] {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out_string = "[error] failed to run command".to_string();
|
||||||
|
}
|
||||||
|
return out_string;
|
||||||
|
});
|
||||||
|
engine.register_fn("db_run", |p: &mut Project, command: String| -> String {
|
||||||
|
let mut out_string = format!("No distrobox configured for selected project.");
|
||||||
|
if let Some(db) = p.db.clone() {
|
||||||
|
out_string = db.run_command(&command);
|
||||||
|
}
|
||||||
|
return out_string;
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
engine: Arc::new(engine),
|
||||||
|
commands: HashMap::new(),
|
||||||
|
asts: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_all(&mut self, base_path: &PathBuf) -> Result<(), std::io::Error> {
|
||||||
|
self.commands.clear();
|
||||||
|
self.asts.clear();
|
||||||
|
|
||||||
|
self.load_from_dir(&base_path.join("default"))?;
|
||||||
|
self.load_from_dir(&base_path.join("custom"))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_from_dir(&mut self, dir: &PathBuf) -> Result<(), std::io::Error> {
|
||||||
|
if !dir.exists() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in read_dir(dir)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
if let Some((command, ast)) = self.parse_module_directory(&path) {
|
||||||
|
self.asts.insert(command.name.clone(), ast);
|
||||||
|
self.commands.insert(command.name.clone(), command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_module_directory(&self, dir: &PathBuf) -> Option<(ToolCommand, AST)> {
|
||||||
|
let config_path = dir.join("config.conf");
|
||||||
|
let help_path = dir.join("help.txt");
|
||||||
|
let script_path = dir.join("script.rhai");
|
||||||
|
|
||||||
|
if !config_path.exists() || !help_path.exists() || !script_path.exists() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let config_content = read_to_string(&config_path).ok()?;
|
||||||
|
let mut name = String::new();
|
||||||
|
let mut output_type = String::new();
|
||||||
|
let mut args = Vec::new();
|
||||||
|
let mut calls = String::new();
|
||||||
|
for line in config_content.lines() {
|
||||||
|
if let Some((key, val)) = line.split_once(':') {
|
||||||
|
match key.trim() {
|
||||||
|
"name" => name = val.trim().to_string(),
|
||||||
|
"output_type" => output_type = val.trim().to_string(),
|
||||||
|
"args" => {
|
||||||
|
args = val
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
"calls" => {
|
||||||
|
calls = val.trim().to_string();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let help = read_to_string(&help_path).unwrap_or_default();
|
||||||
|
let ast = match self.engine.compile_file(script_path.clone()) {
|
||||||
|
Ok(compiled_ast) => compiled_ast,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[error] compiling script in {:?}: {}", script_path, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let command = ToolCommand {
|
||||||
|
name,
|
||||||
|
path: script_path,
|
||||||
|
help,
|
||||||
|
args,
|
||||||
|
output_type,
|
||||||
|
finished: false,
|
||||||
|
result: false,
|
||||||
|
calls,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((command, ast))
|
||||||
|
}
|
||||||
|
}
|
||||||
+488
@@ -0,0 +1,488 @@
|
|||||||
|
use crate::Host;
|
||||||
|
use crate::ToolMessage;
|
||||||
|
use crate::User;
|
||||||
|
use ipnet::IpNet;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs::{File, create_dir_all, read_dir, read_to_string};
|
||||||
|
use std::io::{BufRead, BufReader, Write};
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Project {
|
||||||
|
pub org_name: String,
|
||||||
|
pub config_folder: PathBuf,
|
||||||
|
pub name: String,
|
||||||
|
pub notes: PathBuf,
|
||||||
|
pub files: PathBuf,
|
||||||
|
pub hosts: Vec<Host>,
|
||||||
|
pub current: bool,
|
||||||
|
pub db: Option<DistroBox>,
|
||||||
|
pub scope: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Project {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
org_name: String::new(),
|
||||||
|
config_folder: PathBuf::new(),
|
||||||
|
name: String::new(),
|
||||||
|
notes: PathBuf::new(),
|
||||||
|
files: PathBuf::new(),
|
||||||
|
hosts: Vec::new(),
|
||||||
|
current: false,
|
||||||
|
db: None,
|
||||||
|
scope: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn org_name(&mut self, name: String) {
|
||||||
|
self.org_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notes(&mut self, path: PathBuf) {
|
||||||
|
self.notes = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn files(&mut self, path: PathBuf) {
|
||||||
|
self.files = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hosts(&mut self, hosts: Vec<Host>) {
|
||||||
|
self.hosts = hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_host(&mut self, mut host: Host) {
|
||||||
|
let mut new_id = 0;
|
||||||
|
self.hosts.iter().for_each(|h| {
|
||||||
|
if h.id > new_id {
|
||||||
|
new_id = h.id.clone();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
new_id += 1;
|
||||||
|
if !self.hosts.iter().any(|h| h.ip == host.ip) {
|
||||||
|
host.id = new_id;
|
||||||
|
self.hosts.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config_folder(&mut self, path: PathBuf) {
|
||||||
|
self.config_folder = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_scope(&mut self, host: String) {
|
||||||
|
if let Ok(ip) = host.parse::<IpAddr>() {
|
||||||
|
self.scope.push(ip.to_string())
|
||||||
|
} else if let Ok(net) = host.parse::<IpNet>() {
|
||||||
|
net.hosts().into_iter().for_each(|ip| {
|
||||||
|
self.scope.push(ip.to_string());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.scope.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config(&mut self, display: bool) -> Result<(), Box<dyn Error>> {
|
||||||
|
let config_contents = read_to_string(&self.config_folder)?;
|
||||||
|
for line in config_contents.lines() {
|
||||||
|
let parts: Vec<&str> = line.split(": ").collect();
|
||||||
|
if parts.len() == 2 {
|
||||||
|
match parts[0].trim() {
|
||||||
|
"org_name" => self.org_name(parts[1].trim().to_string()),
|
||||||
|
"name" => self.name = parts[1].trim().to_string(),
|
||||||
|
"notes" => self.notes(PathBuf::from(parts[1].trim())),
|
||||||
|
"files" => self.files(PathBuf::from(parts[1].trim())),
|
||||||
|
"stage" => {
|
||||||
|
if parts[1].trim() == "current" {
|
||||||
|
self.current = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"scope" => {
|
||||||
|
let ips: Vec<&str> = parts[1].split(",").collect();
|
||||||
|
ips.iter().for_each(|ip| {
|
||||||
|
self.add_scope(ip.trim().to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if display {
|
||||||
|
println!("{} | {} config loaded!", self.org_name, self.name);
|
||||||
|
println!("loading hosts...");
|
||||||
|
}
|
||||||
|
let mut conf_folder = self.config_folder.clone();
|
||||||
|
conf_folder.pop();
|
||||||
|
let mut hosts_folder = conf_folder.clone();
|
||||||
|
let mut users_folder = conf_folder.clone();
|
||||||
|
hosts_folder.push("hosts");
|
||||||
|
users_folder.push("users");
|
||||||
|
let mut users = HashMap::new();
|
||||||
|
if users_folder.exists() {
|
||||||
|
for entry in read_dir(users_folder)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let user_config_string = read_to_string(entry.path())?;
|
||||||
|
let mut new_user = User::new();
|
||||||
|
for line in user_config_string.lines() {
|
||||||
|
if line.contains(": ") {
|
||||||
|
let (setting, data) = line.split_once(": ").unwrap();
|
||||||
|
match setting.trim() {
|
||||||
|
"username" => new_user.name = data.trim().to_string(),
|
||||||
|
"password" => new_user.password = Some(data.trim().to_string()),
|
||||||
|
"hash" => new_user.hash = Some(data.trim().to_string()),
|
||||||
|
"compromised" => new_user.compromised = data.trim().parse().unwrap(),
|
||||||
|
"ticket" => new_user.ticket = Some(PathBuf::from(data.trim())),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
users.insert(new_user.name.clone(), new_user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hosts_folder.exists() {
|
||||||
|
read_dir(hosts_folder)?.into_iter().for_each(|res| {
|
||||||
|
if let Ok(entry) = res {
|
||||||
|
let host_path = entry.path();
|
||||||
|
let mut new_host = Host::new();
|
||||||
|
println!("loading {}...", host_path.display());
|
||||||
|
if let Ok(host_conf_text) = read_to_string(host_path) {
|
||||||
|
host_conf_text.lines().into_iter().for_each(|line| {
|
||||||
|
if line.contains(": ") {
|
||||||
|
let (setting, data) = line.split_once(": ").unwrap();
|
||||||
|
match setting.trim() {
|
||||||
|
"ip" => new_host.ip = data.trim().to_string(),
|
||||||
|
"hostname" => new_host.hostname = data.trim().to_string(),
|
||||||
|
"control_port" => {
|
||||||
|
new_host.control_port = data.trim().parse().unwrap();
|
||||||
|
}
|
||||||
|
"pwned" => {
|
||||||
|
new_host.pwned = data.trim().parse().unwrap();
|
||||||
|
}
|
||||||
|
"id" => new_host.id = data.trim().parse().unwrap(),
|
||||||
|
"findings" => {
|
||||||
|
new_host.findings = data
|
||||||
|
.trim()
|
||||||
|
.split(",")
|
||||||
|
.map(|finding| finding.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
}
|
||||||
|
"open_ports" => {
|
||||||
|
new_host.open_ports = data
|
||||||
|
.trim()
|
||||||
|
.split(",")
|
||||||
|
.into_iter()
|
||||||
|
.map(|port| port.parse().unwrap_or_default())
|
||||||
|
.collect::<Vec<usize>>()
|
||||||
|
}
|
||||||
|
"users" => {
|
||||||
|
let names: Vec<&str> = data.trim().split(",").collect();
|
||||||
|
names.into_iter().for_each(|name| {
|
||||||
|
if let Some(user) = users.get(name) {
|
||||||
|
new_host.users.push(user.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.add_host(new_host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if display {
|
||||||
|
println!("{} | {} loaded!", self.org_name, self.name);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_config(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut conf_folder = self.config_folder.clone();
|
||||||
|
conf_folder.pop();
|
||||||
|
if !conf_folder.exists() {
|
||||||
|
match create_dir_all(&conf_folder) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(
|
||||||
|
format!("save_config: couldn't create project conf folder! {e}").into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut hosts_folder = conf_folder.clone();
|
||||||
|
hosts_folder.push("hosts");
|
||||||
|
let mut users_folder = conf_folder.clone();
|
||||||
|
users_folder.push("users");
|
||||||
|
if !hosts_folder.exists() {
|
||||||
|
create_dir_all(&hosts_folder)?;
|
||||||
|
}
|
||||||
|
if !users_folder.exists() {
|
||||||
|
create_dir_all(&users_folder)?;
|
||||||
|
}
|
||||||
|
let mut file = File::create(&self.config_folder)?;
|
||||||
|
let mut out_string = format!(
|
||||||
|
"org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\n",
|
||||||
|
self.org_name,
|
||||||
|
self.name,
|
||||||
|
self.notes.display(),
|
||||||
|
self.files.display(),
|
||||||
|
self.scope.join(","),
|
||||||
|
);
|
||||||
|
if self.current {
|
||||||
|
out_string.push_str("stage: current");
|
||||||
|
} else {
|
||||||
|
out_string.push_str("stage: upcoming");
|
||||||
|
}
|
||||||
|
file.write_all(out_string.as_bytes())?;
|
||||||
|
self.hosts
|
||||||
|
.iter_mut()
|
||||||
|
.try_for_each(|h| -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut host_path = hosts_folder.clone();
|
||||||
|
host_path.push(format!("{}.conf", h.id));
|
||||||
|
h.save_config_file(host_path)
|
||||||
|
})?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Project {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{} | {}", self.org_name, self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Project {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
format!("{} | {}", self.org_name, self.name)
|
||||||
|
== format!("{} | {}", other.org_name, other.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Project {}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ToolCommand {
|
||||||
|
pub name: String,
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub help: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
pub output_type: String,
|
||||||
|
pub finished: bool,
|
||||||
|
pub result: bool,
|
||||||
|
pub calls: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DistroBox {
|
||||||
|
pub name: String,
|
||||||
|
pub volumes: Vec<String>,
|
||||||
|
pub created: bool,
|
||||||
|
pub template: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DistroBox {
|
||||||
|
pub fn create(&mut self, tx: Sender<ToolMessage>, rid: usize) -> Result<(), Box<dyn Error>> {
|
||||||
|
if let Err(e) = self.stop_template(tx.clone(), rid) {
|
||||||
|
tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("[error] stopping template box! {e}"),
|
||||||
|
)))?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut create_command = Command::new("distrobox");
|
||||||
|
create_command
|
||||||
|
.arg("create")
|
||||||
|
.arg("--clone")
|
||||||
|
.arg(self.template.clone())
|
||||||
|
.arg("--name")
|
||||||
|
.arg(self.name.clone());
|
||||||
|
let mut added_volumes = Vec::new();
|
||||||
|
for volume in &self.volumes {
|
||||||
|
let folder_name = volume.split("/").last().unwrap();
|
||||||
|
if !added_volumes.contains(&String::from(folder_name)) {
|
||||||
|
create_command
|
||||||
|
.arg("--volume")
|
||||||
|
.arg(format!("{}:/{}:rw", volume, folder_name));
|
||||||
|
added_volumes.push(folder_name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create_command.stdout(Stdio::piped());
|
||||||
|
create_command.stderr(Stdio::piped());
|
||||||
|
let mut child = create_command.spawn()?;
|
||||||
|
if let Some(stdout) = child.stdout.take() {
|
||||||
|
let tx_out = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let reader = BufReader::new(stdout);
|
||||||
|
for line in reader.lines().flatten() {
|
||||||
|
let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(stderr) = child.stderr.take() {
|
||||||
|
let tx_out = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let reader = BufReader::new(stderr);
|
||||||
|
for line in reader.lines().flatten() {
|
||||||
|
let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let status = child.wait()?;
|
||||||
|
if !status.success() {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("[error] creating distrobox!"),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.created = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_template(
|
||||||
|
&mut self,
|
||||||
|
tx: Sender<ToolMessage>,
|
||||||
|
rid: usize,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut stop_command = Command::new("distrobox");
|
||||||
|
stop_command
|
||||||
|
.arg("stop")
|
||||||
|
.arg(self.template.clone())
|
||||||
|
.arg("--yes");
|
||||||
|
stop_command.stdin(Stdio::piped());
|
||||||
|
stop_command.stdout(Stdio::piped());
|
||||||
|
stop_command.stderr(Stdio::piped());
|
||||||
|
let mut child = stop_command.spawn()?;
|
||||||
|
if let Some(stdout) = child.stdout.take() {
|
||||||
|
let tx_out = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let reader = BufReader::new(stdout);
|
||||||
|
for line in reader.lines().flatten() {
|
||||||
|
let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(stderr) = child.stderr.take() {
|
||||||
|
let tx_out = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let reader = BufReader::new(stderr);
|
||||||
|
for line in reader.lines().flatten() {
|
||||||
|
let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let status = child.wait()?;
|
||||||
|
if !status.success() {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("[error] stopping template distrobox!"),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self, tx: Sender<ToolMessage>, rid: usize) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut stop_command = Command::new("distrobox");
|
||||||
|
stop_command.arg("stop").arg(self.name.clone()).arg("--yes");
|
||||||
|
stop_command.stdin(Stdio::piped());
|
||||||
|
stop_command.stdout(Stdio::piped());
|
||||||
|
stop_command.stderr(Stdio::piped());
|
||||||
|
let mut child = stop_command.spawn()?;
|
||||||
|
if let Some(stdout) = child.stdout.take() {
|
||||||
|
let tx_out = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let reader = BufReader::new(stdout);
|
||||||
|
for line in reader.lines().flatten() {
|
||||||
|
let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(stderr) = child.stderr.take() {
|
||||||
|
let tx_out = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let reader = BufReader::new(stderr);
|
||||||
|
for line in reader.lines().flatten() {
|
||||||
|
let _ = tx_out.send(ToolMessage::Output((rid, line.clone())));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let status = child.wait()?;
|
||||||
|
if !status.success() {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("[error] stopping distrobox!"),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&mut self, tx: Sender<ToolMessage>, rid: usize) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut destroycmd = Command::new("distrobox");
|
||||||
|
destroycmd.arg("rm").arg(self.name.clone()).arg("-f");
|
||||||
|
let res = destroycmd.status()?;
|
||||||
|
if !res.success() {
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("[error] destroying distrobox!"),
|
||||||
|
)));
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
String::from("pleas try destroying manually:"),
|
||||||
|
)));
|
||||||
|
let _ = tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("distrobox rm {} -f", self.name),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
self.created = false;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch_terminal(&self, cmd: String) {
|
||||||
|
if let Some((terminal_cmd, args)) = cmd.split_once(" ") {
|
||||||
|
let mut term_cmd = Command::new(terminal_cmd);
|
||||||
|
args.split(" ").into_iter().for_each(|arg| {
|
||||||
|
if arg == "|||COMMAND|||" {
|
||||||
|
term_cmd
|
||||||
|
.arg("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg(self.name.clone());
|
||||||
|
} else if arg.contains("ENV_NAME=") {
|
||||||
|
let (_, env_name) = arg.split_once("=").unwrap();
|
||||||
|
unsafe { std::env::set_var(env_name, self.name.clone()) };
|
||||||
|
} else {
|
||||||
|
term_cmd.arg(arg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = term_cmd.spawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_command(&self, cmd: &str) -> String {
|
||||||
|
let output = Command::new("distrobox")
|
||||||
|
.arg("enter")
|
||||||
|
.arg("-e")
|
||||||
|
.arg(format!("\"{}\"", cmd))
|
||||||
|
.output();
|
||||||
|
match output {
|
||||||
|
Ok(output) => {
|
||||||
|
if output.status.success() {
|
||||||
|
return String::from_utf8_lossy(&output.stdout).to_string();
|
||||||
|
} else {
|
||||||
|
return format!("[error] {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return format!("[error] {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,6 @@ use anyhow::Context;
|
|||||||
use dns_lookup::lookup_host;
|
use dns_lookup::lookup_host;
|
||||||
use headless_chrome::{Browser, LaunchOptions};
|
use headless_chrome::{Browser, LaunchOptions};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use trust_dns_resolver::lookup::Ipv4Lookup;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum BusterTarget {
|
pub enum BusterTarget {
|
||||||
@@ -153,7 +151,3 @@ pub fn rustbuster(target: BusterTarget) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shodan(ip: String) -> String {
|
|
||||||
return "todo".to_string();
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-4
@@ -1,4 +1,3 @@
|
|||||||
use keyring::Entry;
|
|
||||||
use rcgen::generate_simple_self_signed;
|
use rcgen::generate_simple_self_signed;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@@ -54,7 +53,7 @@ pub struct Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_server(server: Arc<Mutex<Server>>) -> Result<(), Box<dyn Error>> {
|
pub async fn start_server(server: Arc<Mutex<Server>>) -> Result<(), Box<dyn Error>> {
|
||||||
let mut lock = server.lock().unwrap();
|
let lock = server.lock().unwrap();
|
||||||
let mut name_path = lock.certificate_path.clone();
|
let mut name_path = lock.certificate_path.clone();
|
||||||
name_path.pop();
|
name_path.pop();
|
||||||
name_path.push("names.txt");
|
name_path.push("names.txt");
|
||||||
@@ -494,7 +493,7 @@ where
|
|||||||
messages.push(format!("OUTPUT|{}", text));
|
messages.push(format!("OUTPUT|{}", text));
|
||||||
}
|
}
|
||||||
ClientAction::Collab(text) => {
|
ClientAction::Collab(text) => {
|
||||||
println!("todo");
|
println!("todo, {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,7 +564,7 @@ where
|
|||||||
messages.push(format!("OUTPUT|{}", text));
|
messages.push(format!("OUTPUT|{}", text));
|
||||||
}
|
}
|
||||||
ClientAction::Collab(text) => {
|
ClientAction::Collab(text) => {
|
||||||
println!("todo");
|
println!("todo, {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce, aead::Aead};
|
|
||||||
use rand::{self, Rng, TryRng};
|
|
||||||
use rayon::spawn;
|
use rayon::spawn;
|
||||||
|
|
||||||
pub fn generate_code(
|
pub fn generate_code(
|
||||||
@@ -48,44 +46,6 @@ pub fn generate_code(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fn generate_obfuscated_code(
|
|
||||||
address: String,
|
|
||||||
password: String,
|
|
||||||
config_file: PathBuf,
|
|
||||||
files: PathBuf,
|
|
||||||
target: String,
|
|
||||||
tx: Sender<ToolMessage>,
|
|
||||||
cert_text: String,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut source_path = config_file.clone();
|
|
||||||
source_path.pop();
|
|
||||||
source_path.push("victim/src/main.rs");
|
|
||||||
let mut source = read_to_string(&source_path)?;
|
|
||||||
source = source
|
|
||||||
.replace("|||SERVER|||", &address)
|
|
||||||
.replace("|||PASSWORD|||", &password)
|
|
||||||
.replace("|||CERT|||", &cert_text);
|
|
||||||
files_base.pop();
|
|
||||||
files_base.pop();
|
|
||||||
files_base.push("Cargo.toml");
|
|
||||||
let cargo_string = read_to_string(source_path)?;
|
|
||||||
let mut files_base = files.clone();
|
|
||||||
files_base.push("victim/src");
|
|
||||||
create_dir_all(&files_base)?;
|
|
||||||
files_base.push("main.rs");
|
|
||||||
let mut src_file = File::create(&files_base)?;
|
|
||||||
let mut key = [0u8; 32];
|
|
||||||
rand::rng().fill_bytes(&mut key);
|
|
||||||
let mut iv = [0u8; 16];
|
|
||||||
rand::rng().fill_bytes(&mut iv);
|
|
||||||
let cipher = Aes256Gcm::new_from_slice(&key)?;
|
|
||||||
let nonce = Nonce::try_from(&iv[..])?;
|
|
||||||
let mut ciphertext = cipher.encrypt(&nonce, source.as_bytes())?;
|
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}*/
|
|
||||||
|
|
||||||
fn compile_victim(mut cargo_command: Command, tx: Sender<ToolMessage>) {
|
fn compile_victim(mut cargo_command: Command, tx: Sender<ToolMessage>) {
|
||||||
let mut out = "Error compiling output!".to_string();
|
let mut out = "Error compiling output!".to_string();
|
||||||
if let Ok(output) = cargo_command.output() {
|
if let Ok(output) = cargo_command.output() {
|
||||||
|
|||||||
Reference in New Issue
Block a user