Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29bc50468d | ||
|
|
b30a62bb96 | ||
|
|
f621a46954 | ||
|
|
b18ada61c7 | ||
|
|
c2d6174fc9 | ||
|
|
a37f78a4e7 | ||
|
|
7bc5442416 | ||
|
|
7247e85762 | ||
|
|
0bad1c7b66 | ||
|
|
a6e50020ca |
No files matched your search
Generated
+486
-388
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
Whitespace-only changes.
+205
-45
@@ -32,6 +32,7 @@ use std::sync::{Arc, Mutex, mpsc::Sender, mpsc::channel};
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::{self, Instant};
|
use std::time::{self, Instant};
|
||||||
|
use trust_dns_resolver::proto::rr::rdata::svcb::SvcParamKey::Port;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
@@ -130,6 +131,7 @@ impl AppState {
|
|||||||
password: String::new(),
|
password: String::new(),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
cert_text: String::new(),
|
cert_text: String::new(),
|
||||||
|
hostnames: Vec::new(),
|
||||||
};
|
};
|
||||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||||
}
|
}
|
||||||
@@ -161,22 +163,26 @@ impl AppState {
|
|||||||
new_project.load_config(display)?;
|
new_project.load_config(display)?;
|
||||||
let template_box = self.config.get("template_box").unwrap();
|
let template_box = self.config.get("template_box").unwrap();
|
||||||
let tools = self.config.get("tools").unwrap();
|
let tools = self.config.get("tools").unwrap();
|
||||||
let db = DistroBox {
|
if template_box != "NONE" || new_project.distrobox {
|
||||||
name: format!(
|
let db = DistroBox {
|
||||||
"{}-{}-{}",
|
name: format!(
|
||||||
template_box,
|
"{}-{}-{}",
|
||||||
new_project.org_name.clone(),
|
template_box,
|
||||||
new_project.name.clone()
|
new_project.org_name.clone(),
|
||||||
),
|
new_project.name.clone()
|
||||||
volumes: vec![
|
),
|
||||||
new_project.files.display().to_string(),
|
volumes: vec![
|
||||||
new_project.notes.display().to_string(),
|
new_project.files.display().to_string(),
|
||||||
tools.clone(),
|
new_project.notes.display().to_string(),
|
||||||
],
|
tools.clone(),
|
||||||
created: false,
|
],
|
||||||
template: template_box.clone(),
|
created: false,
|
||||||
};
|
template: template_box.clone(),
|
||||||
new_project.db = Some(db);
|
};
|
||||||
|
new_project.db = Some(db);
|
||||||
|
} else {
|
||||||
|
new_project.db = None;
|
||||||
|
}
|
||||||
self.projects.push(new_project);
|
self.projects.push(new_project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,6 +224,7 @@ impl AppState {
|
|||||||
password: String::new(),
|
password: String::new(),
|
||||||
name,
|
name,
|
||||||
cert_text: cert,
|
cert_text: cert,
|
||||||
|
hostnames: Vec::new(),
|
||||||
};
|
};
|
||||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||||
}
|
}
|
||||||
@@ -279,6 +286,8 @@ impl AppState {
|
|||||||
self.help.push(
|
self.help.push(
|
||||||
"Shortcuts:\nCTRL+P = new_project\nCTRL+s = save\nCTRL_+h = select_host\n".to_string(),
|
"Shortcuts:\nCTRL+P = new_project\nCTRL+s = save\nCTRL_+h = select_host\n".to_string(),
|
||||||
);
|
);
|
||||||
|
self.help.push("exclude\nexcludes an IP or a cidr network from the scope and all future tool calls.\nexport 192.168.1.1 192.168.2.0/24\n".to_string());
|
||||||
|
self.help.push("start_odysseus\nstarts the odyssues server in the distrobox of the project.\nUSAGE:\nstart_odysseus port_number\n".to_string());
|
||||||
self.help.push("exit\nquit the tool\n".to_string());
|
self.help.push("exit\nquit the tool\n".to_string());
|
||||||
self.initialize_modules();
|
self.initialize_modules();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -354,24 +363,24 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
"generate_victim" => {
|
"generate_victim" => {
|
||||||
let mut success = false;
|
let mut success = false;
|
||||||
|
let mut addresses = Vec::new();
|
||||||
if let Some(args) = command_args {
|
if let Some(args) = command_args {
|
||||||
if args.split(" ").into_iter().count() == 1 {
|
if let Some((target, address)) = args.split_once(" ") {
|
||||||
let mut address = String::new();
|
|
||||||
let mut password = String::new();
|
let mut password = String::new();
|
||||||
let config_file = self.config_file.clone();
|
let config_file = self.config_file.clone();
|
||||||
let files = self.projects[self.selected_project].files.clone();
|
let files = self.projects[self.selected_project].files.clone();
|
||||||
let mut cert_text = String::new();
|
let mut cert_text = String::new();
|
||||||
if let Ok(lock) = self.servers[self.selected_server].lock() {
|
if let Ok(lock) = self.servers[self.selected_server].lock() {
|
||||||
address = lock.address.clone();
|
|
||||||
password = lock.password.clone();
|
password = lock.password.clone();
|
||||||
cert_text = lock.cert_text.clone();
|
cert_text = lock.cert_text.clone();
|
||||||
|
addresses = lock.hostnames.clone();
|
||||||
}
|
}
|
||||||
match victim::generate_code(
|
match victim::generate_code(
|
||||||
address,
|
address.to_string(),
|
||||||
password,
|
password,
|
||||||
config_file,
|
config_file,
|
||||||
files,
|
files,
|
||||||
args,
|
target.to_string(),
|
||||||
self.main_tx.clone(),
|
self.main_tx.clone(),
|
||||||
cert_text,
|
cert_text,
|
||||||
) {
|
) {
|
||||||
@@ -393,6 +402,14 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !success {
|
if !success {
|
||||||
|
let _ = self
|
||||||
|
.main_tx
|
||||||
|
.send(ToolMessage::Output((0, format!("available addresses:"))));
|
||||||
|
addresses.iter().for_each(|a| {
|
||||||
|
let _ = self
|
||||||
|
.main_tx
|
||||||
|
.send(ToolMessage::Output((0, format!("{}", a))));
|
||||||
|
});
|
||||||
let _ = self.main_tx.send(ToolMessage::Output((
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
0,
|
0,
|
||||||
format!("Usage: generate_victim (windows/linux)"),
|
format!("Usage: generate_victim (windows/linux)"),
|
||||||
@@ -568,11 +585,24 @@ impl AppState {
|
|||||||
let project = self.projects[self.selected_project].clone();
|
let project = self.projects[self.selected_project].clone();
|
||||||
if let Some(cmd) = self.config.get("term_cmd") {
|
if let Some(cmd) = self.config.get("term_cmd") {
|
||||||
if let Some(db) = project.db {
|
if let Some(db) = project.db {
|
||||||
db.launch_terminal(cmd.to_string());
|
let _ = self
|
||||||
|
.main_tx
|
||||||
|
.send(ToolMessage::Output((rid, format!("launcing distrobox..."))));
|
||||||
|
db.launch_terminal(
|
||||||
|
cmd.to_string(),
|
||||||
|
self.projects[self.selected_project].files.clone(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if let Some((prog, _)) = cmd.split_once(" ") {
|
if let Some((prog, _)) = cmd.split_once(" ") {
|
||||||
let mut launch_cmd = Command::new(prog);
|
let mut launch_cmd = Command::new(prog);
|
||||||
match launch_cmd.spawn() {
|
launch_cmd.current_dir(&project.files);
|
||||||
|
if let Some(dir) = launch_cmd.get_current_dir() {
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("launcing terminal in {}", dir.display()),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
match launch_cmd.current_dir(&project.files).spawn() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let _ = self.main_tx.send(ToolMessage::Output((
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
@@ -625,6 +655,7 @@ impl AppState {
|
|||||||
password: String::new(),
|
password: String::new(),
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
cert_text: String::new(),
|
cert_text: String::new(),
|
||||||
|
hostnames: Vec::new(),
|
||||||
};
|
};
|
||||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||||
self.save_all()?;
|
self.save_all()?;
|
||||||
@@ -853,23 +884,52 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
"parse_scope" => {
|
"parse_scope" => {
|
||||||
let mut general_path = self.projects[self.selected_project].notes.clone();
|
let mut general_path = self.projects[self.selected_project].notes.clone();
|
||||||
|
let mut scope_path = self.projects[self.selected_project].notes.clone();
|
||||||
|
scope_path.push("scope.md");
|
||||||
general_path.push("general.md");
|
general_path.push("general.md");
|
||||||
let general_string = read_to_string(general_path)?;
|
let general_string = read_to_string(general_path)?;
|
||||||
if let Some((_, scope_section)) = general_string.split_once("# Scope") {
|
let mut scope_file = OpenOptions::new()
|
||||||
if let Some((scope_section, _)) = scope_section.split_once("#") {
|
.create(true)
|
||||||
scope_section.lines().into_iter().for_each(|line| {
|
.truncate(true)
|
||||||
if line.contains("|") {
|
.write(true)
|
||||||
if !line.contains("Subnet") {
|
.open(scope_path)?;
|
||||||
if !line.contains("--") {
|
general_string
|
||||||
let host =
|
.split_whitespace()
|
||||||
line.split("|").collect::<Vec<&str>>()[1].to_string();
|
.into_iter()
|
||||||
self.projects[self.selected_project].add_scope(host);
|
.for_each(|word| {
|
||||||
}
|
if let Ok(_) = word.trim().parse::<IpNet>() {
|
||||||
}
|
if let Err(e) = write!(scope_file, "{}\n", word) {
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("Error writing scope file! {e}"),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
});
|
} else if let Ok(_) = word.trim().parse::<IpAddr>() {
|
||||||
}
|
if let Err(e) = write!(scope_file, "{}\n", word) {
|
||||||
}
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("Error writing scope file! {e}"),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
} else if word.contains(".com")
|
||||||
|
|| word.contains(".org")
|
||||||
|
|| word.contains(".gov")
|
||||||
|
|| word.contains(".site")
|
||||||
|
|| word.contains(".local")
|
||||||
|
|| word.contains(".ad")
|
||||||
|
{
|
||||||
|
if let Err(e) = write!(scope_file, "{}\n", word) {
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
format!("Error writing scope file! {e}"),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
"[success] scope parsed and scope.md written!".to_string(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
"show_config" | "sc" => {
|
"show_config" | "sc" => {
|
||||||
let _ = self
|
let _ = self
|
||||||
@@ -1140,15 +1200,17 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
args_vec[0].split(",").into_iter().for_each(|ip| {
|
args_vec[0].split(",").into_iter().for_each(|ip| {
|
||||||
if let Ok(ip) = ip.parse::<IpAddr>() {
|
if !project.exclusions.contains(&ip.to_string()) {
|
||||||
let mut new_host = Host::new();
|
if let Ok(ip) = ip.parse::<IpAddr>() {
|
||||||
new_host.ip = ip.to_string();
|
|
||||||
hosts.push(new_host);
|
|
||||||
} else if let Ok(net) = ip.parse::<IpNet>() {
|
|
||||||
for host_addr in net.hosts() {
|
|
||||||
let mut new_host = Host::new();
|
let mut new_host = Host::new();
|
||||||
new_host.ip = host_addr.to_string();
|
new_host.ip = ip.to_string();
|
||||||
hosts.push(new_host);
|
hosts.push(new_host);
|
||||||
|
} else if let Ok(net) = ip.parse::<IpNet>() {
|
||||||
|
for host_addr in net.hosts() {
|
||||||
|
let mut new_host = Host::new();
|
||||||
|
new_host.ip = host_addr.to_string();
|
||||||
|
hosts.push(new_host);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1649,6 +1711,74 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"exclude" => {
|
||||||
|
if let Some(args) = command_args {
|
||||||
|
let project = self.projects[self.selected_project].clone();
|
||||||
|
if args.contains(" ") {
|
||||||
|
args.split(" ")
|
||||||
|
.into_iter()
|
||||||
|
.filter(|ex| !project.exclusions.contains(&ex.to_string()))
|
||||||
|
.for_each(|ex| {
|
||||||
|
if let Ok(_) = ex.parse::<IpAddr>() {
|
||||||
|
self.projects[self.selected_project]
|
||||||
|
.exclusions
|
||||||
|
.push(ex.to_string());
|
||||||
|
} else if let Ok(net) = ex.parse::<IpNet>() {
|
||||||
|
net.hosts().into_iter().for_each(|ip| {
|
||||||
|
self.projects[self.selected_project]
|
||||||
|
.exclusions
|
||||||
|
.push(ip.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"start_odysseus" => {
|
||||||
|
if let Some(args) = command_args {
|
||||||
|
let working_db = self.projects[self.selected_project].db.clone();
|
||||||
|
if let Some(db) = working_db {
|
||||||
|
if let Some(tools_dir) = self.config.get("TOOLS") {
|
||||||
|
let mut odysseus_path = None;
|
||||||
|
let entries = WalkDir::new(tools_dir);
|
||||||
|
entries.into_iter().for_each(|entry| {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
if entry.file_name().to_string_lossy().contains("odysseus") {
|
||||||
|
if entry.path().is_dir() {
|
||||||
|
odysseus_path = Some(entry.into_path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if let Some(path) = odysseus_path {
|
||||||
|
let tx_clone = self.main_tx.clone();
|
||||||
|
self.workers.spawn(move||{
|
||||||
|
let output = db.run_command(format!("cd {}; source venv/bin/activate; python -m uvicorn app:app --host 127.0.0.1 --port {}", path.display(), args.trim()).as_str());
|
||||||
|
let _ = tx_clone.send(ToolMessage::Output((rid, format!("{}", output))));
|
||||||
|
});
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
"[success] odysseus command ran!".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
"[error] malformed command".to_string(),
|
||||||
|
)));
|
||||||
|
let _ = self
|
||||||
|
.main_tx
|
||||||
|
.send(ToolMessage::Output((rid, "[error] USAGE:".to_string())));
|
||||||
|
let _ = self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
"[error] start_odysseus {port number}".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"exit" => {
|
"exit" => {
|
||||||
self.save_all()?;
|
self.save_all()?;
|
||||||
let _ = self.main_tx.send(ToolMessage::AppStateExit);
|
let _ = self.main_tx.send(ToolMessage::AppStateExit);
|
||||||
@@ -1912,6 +2042,7 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut db = None;
|
let mut db = None;
|
||||||
|
let mut distrobx = false;
|
||||||
if template_box != &"NONE".to_string() {
|
if template_box != &"NONE".to_string() {
|
||||||
db = Some(DistroBox {
|
db = Some(DistroBox {
|
||||||
name: format!("{}-{}-{}", template_box, org, name),
|
name: format!("{}-{}-{}", template_box, org, name),
|
||||||
@@ -1923,6 +2054,7 @@ impl AppState {
|
|||||||
created: false,
|
created: false,
|
||||||
template: template_box.to_string(),
|
template: template_box.to_string(),
|
||||||
});
|
});
|
||||||
|
distrobx = true;
|
||||||
};
|
};
|
||||||
let mut new_project = Project {
|
let mut new_project = Project {
|
||||||
org_name: org,
|
org_name: org,
|
||||||
@@ -1933,7 +2065,9 @@ impl AppState {
|
|||||||
config_folder: project_config_file,
|
config_folder: project_config_file,
|
||||||
current: false,
|
current: false,
|
||||||
db: db,
|
db: db,
|
||||||
|
distrobox: distrobx,
|
||||||
scope: Vec::new(),
|
scope: Vec::new(),
|
||||||
|
exclusions: Vec::new(),
|
||||||
};
|
};
|
||||||
match new_project.save_config() {
|
match new_project.save_config() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
@@ -1970,8 +2104,24 @@ impl AppState {
|
|||||||
rid,
|
rid,
|
||||||
String::from("[success] folders copied!"),
|
String::from("[success] folders copied!"),
|
||||||
)))?;
|
)))?;
|
||||||
|
let mut old_files = new_project.files.clone();
|
||||||
|
let mut old_notes = new_project.notes.clone();
|
||||||
|
old_files.pop();
|
||||||
|
old_notes.pop();
|
||||||
remove_dir_all(&new_project.files)?;
|
remove_dir_all(&new_project.files)?;
|
||||||
remove_dir_all(&new_project.notes)?;
|
remove_dir_all(&new_project.notes)?;
|
||||||
|
if let Err(_) = remove_dir(old_files) {
|
||||||
|
self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
String::from("organization files folder is not empty and will not be deleted."),
|
||||||
|
)))?;
|
||||||
|
}
|
||||||
|
if let Err(_) = remove_dir(old_notes) {
|
||||||
|
self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
String::from("organization notes folder is not empty and will not be deleted."),
|
||||||
|
)))?;
|
||||||
|
}
|
||||||
new_files_path.push(&new_project.name);
|
new_files_path.push(&new_project.name);
|
||||||
new_notes_path.push(&new_project.name);
|
new_notes_path.push(&new_project.name);
|
||||||
new_project.files(new_files_path.clone());
|
new_project.files(new_files_path.clone());
|
||||||
@@ -1983,9 +2133,13 @@ impl AppState {
|
|||||||
)))?;
|
)))?;
|
||||||
self.main_tx.send(ToolMessage::Output((
|
self.main_tx.send(ToolMessage::Output((
|
||||||
rid,
|
rid,
|
||||||
String::from("creating distrobox..."),
|
String::from("checking if distrobox should be used..."),
|
||||||
)))?;
|
)))?;
|
||||||
if let Some(mut db) = new_project.db {
|
if let Some(mut db) = new_project.db {
|
||||||
|
self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
String::from("creating distrobox..."),
|
||||||
|
)))?;
|
||||||
db.volumes = vec![
|
db.volumes = vec![
|
||||||
new_files_path.display().to_string(),
|
new_files_path.display().to_string(),
|
||||||
new_notes_path.display().to_string(),
|
new_notes_path.display().to_string(),
|
||||||
@@ -1997,6 +2151,11 @@ impl AppState {
|
|||||||
rid,
|
rid,
|
||||||
String::from("distrobox sent to rebuild function..."),
|
String::from("distrobox sent to rebuild function..."),
|
||||||
)))?;
|
)))?;
|
||||||
|
} else {
|
||||||
|
self.main_tx.send(ToolMessage::Output((
|
||||||
|
rid,
|
||||||
|
String::from("Distrobox was not configured at the creation of this project, so no distrobox will be created."),
|
||||||
|
)))?;
|
||||||
}
|
}
|
||||||
new_project.save_config()?;
|
new_project.save_config()?;
|
||||||
self.projects[self.selected_project] = new_project;
|
self.projects[self.selected_project] = new_project;
|
||||||
@@ -2055,6 +2214,7 @@ impl AppState {
|
|||||||
password: String::new(),
|
password: String::new(),
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
cert_text: String::new(),
|
cert_text: String::new(),
|
||||||
|
hostnames: Vec::new(),
|
||||||
};
|
};
|
||||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||||
self.prompt.reset();
|
self.prompt.reset();
|
||||||
|
|||||||
+8
-1
@@ -24,6 +24,7 @@ pub struct Server {
|
|||||||
pub password: String,
|
pub password: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub cert_text: String,
|
pub cert_text: String,
|
||||||
|
pub hostnames: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
@@ -56,7 +57,9 @@ impl Server {
|
|||||||
self.last_check = Instant::now();
|
self.last_check = Instant::now();
|
||||||
let entry = Entry::new("tetanus", &self.address)?;
|
let entry = Entry::new("tetanus", &self.address)?;
|
||||||
if let Ok(password) = entry.get_password() {
|
if let Ok(password) = entry.get_password() {
|
||||||
self.login(password)?;
|
if let Err(e) = self.login(password) {
|
||||||
|
entry.delete_credential()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Ok(self.client_id);
|
return Ok(self.client_id);
|
||||||
}
|
}
|
||||||
@@ -72,6 +75,7 @@ impl Server {
|
|||||||
self.last_check = Instant::now();
|
self.last_check = Instant::now();
|
||||||
self.logged_in = true;
|
self.logged_in = true;
|
||||||
self.message_que.push(format!("SET_NAME|{}", self.name));
|
self.message_que.push(format!("SET_NAME|{}", self.name));
|
||||||
|
self.message_que.push(format!("REQ_HOSTNAMES"));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
return Err("[error] logging in!".into());
|
return Err("[error] logging in!".into());
|
||||||
@@ -82,6 +86,9 @@ impl Server {
|
|||||||
if self.logged_in {
|
if self.logged_in {
|
||||||
if let Ok(mut stream) = self.tls_connect() {
|
if let Ok(mut stream) = self.tls_connect() {
|
||||||
self.last_check = Instant::now();
|
self.last_check = Instant::now();
|
||||||
|
if self.hostnames.is_empty() {
|
||||||
|
self.message_que.push("REQ_HOSTNAMES".to_string());
|
||||||
|
}
|
||||||
let payload = format!(
|
let payload = format!(
|
||||||
"{}**{}|||{}\n",
|
"{}**{}|||{}\n",
|
||||||
self.password.clone(),
|
self.password.clone(),
|
||||||
|
|||||||
@@ -595,6 +595,30 @@ pub fn run_tui(
|
|||||||
let (action, data) =
|
let (action, data) =
|
||||||
action.split_once("|").unwrap();
|
action.split_once("|").unwrap();
|
||||||
match action.trim() {
|
match action.trim() {
|
||||||
|
"HOSTNAMES" => {
|
||||||
|
let _ = tx_clone.send(
|
||||||
|
ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
"Hostnames recieved:"
|
||||||
|
.to_string(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
data.split(",")
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|h| {
|
||||||
|
let _ = tx_clone.send(
|
||||||
|
ToolMessage::Output((
|
||||||
|
0,
|
||||||
|
h.to_string(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
locked_server
|
||||||
|
.hostnames
|
||||||
|
.push(
|
||||||
|
h.to_string(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
"OUTPUT" => {
|
"OUTPUT" => {
|
||||||
let _ = tx_clone.send(
|
let _ = tx_clone.send(
|
||||||
ToolMessage::Output((
|
ToolMessage::Output((
|
||||||
@@ -1062,6 +1086,9 @@ pub fn run_tui(
|
|||||||
server_lock.action_que.push("disconnect".to_string());
|
server_lock.action_que.push("disconnect".to_string());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
println!("saving state information");
|
||||||
|
let _ = state.save_all();
|
||||||
|
println!("SAVED!");
|
||||||
for handle in handles {
|
for handle in handles {
|
||||||
handle.join().unwrap();
|
handle.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-2
@@ -1,11 +1,12 @@
|
|||||||
use fs_extra::dir::{CopyOptions, copy};
|
use fs_extra::dir::{CopyOptions, copy};
|
||||||
use std::env;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::{File, create_dir_all, remove_dir_all};
|
use std::fs::{File, OpenOptions, create_dir_all, remove_dir_all};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use std::{env, fs};
|
||||||
use tetanus::funcs::get_user_input;
|
use tetanus::funcs::get_user_input;
|
||||||
|
|
||||||
pub fn install() -> Result<(), Box<dyn Error>> {
|
pub fn install() -> Result<(), Box<dyn Error>> {
|
||||||
@@ -98,6 +99,7 @@ pub fn client_install() -> Result<(), Box<dyn Error>> {
|
|||||||
client_config_file.write(format!("term_cmd: {}\n", term_cmd).as_bytes())?;
|
client_config_file.write(format!("term_cmd: {}\n", term_cmd).as_bytes())?;
|
||||||
client_config_file.write(format!("tools: {}\n", tools_folder).as_bytes())?;
|
client_config_file.write(format!("tools: {}\n", tools_folder).as_bytes())?;
|
||||||
client_config_file.write("alternate_configs: \n".as_bytes())?;
|
client_config_file.write("alternate_configs: \n".as_bytes())?;
|
||||||
|
let mut version_file = File::create(root_config_folder_path.join("version"))?;
|
||||||
println!("\ndefault config files written!");
|
println!("\ndefault config files written!");
|
||||||
println!("downloading note templates, victim templates, and modules...");
|
println!("downloading note templates, victim templates, and modules...");
|
||||||
create_dir_all("./temp")?;
|
create_dir_all("./temp")?;
|
||||||
@@ -129,6 +131,81 @@ pub fn client_install() -> Result<(), Box<dyn Error>> {
|
|||||||
root_config_folder_path.join("victim"),
|
root_config_folder_path.join("victim"),
|
||||||
&options,
|
&options,
|
||||||
)?;
|
)?;
|
||||||
|
if get_user_input(
|
||||||
|
"do you want to copy tetanus to your path so you can run it anywhere?",
|
||||||
|
)?
|
||||||
|
.contains("y")
|
||||||
|
{
|
||||||
|
println!("this will require sudo. Please complete the following sudo prompt.");
|
||||||
|
if let Ok(exe_path) = env::current_exe() {
|
||||||
|
if let Ok(res) = Command::new("sudo")
|
||||||
|
.arg("cp")
|
||||||
|
.arg(exe_path.display().to_string())
|
||||||
|
.arg("/usr/bin/tetanus")
|
||||||
|
.status()
|
||||||
|
{
|
||||||
|
if res.success() {
|
||||||
|
let base_update_string = fs::read_to_string("./tetanus_update.sh")?;
|
||||||
|
let update_string = base_update_string.replace(
|
||||||
|
"|||config|||",
|
||||||
|
&root_config_folder_path.display().to_string(),
|
||||||
|
);
|
||||||
|
let update_path = PathBuf::from("./tetanus_update");
|
||||||
|
let mut update_script = OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.write(true)
|
||||||
|
.open(&update_path)?;
|
||||||
|
update_script.write(update_string.as_bytes())?;
|
||||||
|
let mut perms = fs::metadata(&update_path)?.permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
fs::set_permissions(update_path, perms)?;
|
||||||
|
let _ = Command::new("sudo")
|
||||||
|
.arg("cp")
|
||||||
|
.arg("./tetanus_update")
|
||||||
|
.arg("/usr/bin/tetanus_update")
|
||||||
|
.status();
|
||||||
|
version_file
|
||||||
|
.write("version: 0.0.7\npath: /usr/bin/tetanus".as_bytes())?;
|
||||||
|
println!("copied to path!");
|
||||||
|
println!("install completed!");
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"error copying to path. please copy this executable to your path manually."
|
||||||
|
);
|
||||||
|
eprintln!("please download the update_script to your path manually");
|
||||||
|
eprintln!(
|
||||||
|
"sudo curl https://git.pyro.monster/pyro/tetanus/raw/branch/main/tetanus_update.sh -o /usr/bin/tetanus_update"
|
||||||
|
);
|
||||||
|
eprintln!("sudo chmod +x /usr/bin/tetanus_update");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"Ok, we will keep the tetanus binary where it is. The tetanus_update bash script will be in the same directory."
|
||||||
|
);
|
||||||
|
let base_update_string = fs::read_to_string("./tetanus_update.sh")?;
|
||||||
|
let update_string = base_update_string.replace(
|
||||||
|
"|||config|||",
|
||||||
|
&root_config_folder_path.display().to_string(),
|
||||||
|
);
|
||||||
|
let mut update_path = env::current_exe()?;
|
||||||
|
update_path.pop();
|
||||||
|
update_path.push("tetanus_update");
|
||||||
|
let mut update_script = OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.write(true)
|
||||||
|
.open(&update_path)?;
|
||||||
|
update_script.write(update_string.as_bytes())?;
|
||||||
|
let mut perms = fs::metadata(&update_path)?.permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
fs::set_permissions(update_path, perms)?;
|
||||||
|
version_file.write(
|
||||||
|
format!("version: 0.0.7\npath: {}", env::current_exe()?.display()).as_bytes(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
env::set_current_dir("../")?;
|
env::set_current_dir("../")?;
|
||||||
remove_dir_all("./temp")?;
|
remove_dir_all("./temp")?;
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-1
@@ -2,6 +2,8 @@ use clap::Parser;
|
|||||||
use keyring::Entry;
|
use keyring::Entry;
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
use rand::distr::Alphanumeric;
|
use rand::distr::Alphanumeric;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::{Write, read_to_string};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread::{sleep, spawn};
|
use std::thread::{sleep, spawn};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -60,6 +62,13 @@ struct Args {
|
|||||||
help = "The name to set this instance, on servers it will name the server so clients know who it is, on clients it names the clinet for server communications. This defaults to the hostname of the machine, or if the hostname can't be determined it falls back to the username of who runs it."
|
help = "The name to set this instance, on servers it will name the server so clients know who it is, on clients it names the clinet for server communications. This defaults to the hostname of the machine, or if the hostname can't be determined it falls back to the username of who runs it."
|
||||||
)]
|
)]
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "additional hostnames or ip addresses to add to the tls certificate to allow it to connect via portforwarding or proxies. Comma separate the values."
|
||||||
|
)]
|
||||||
|
addresses: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@@ -108,6 +117,30 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Ok(version_string) = std::fs::read_to_string(config_path.join("version")) {
|
||||||
|
version_string
|
||||||
|
.lines()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|line| line.contains("path:"))
|
||||||
|
.for_each(|line| {
|
||||||
|
if let Some((_, path)) = line.split_once(" ") {
|
||||||
|
if let Ok(current_exe) = env::current_exe() {
|
||||||
|
if PathBuf::from(path) != current_exe {
|
||||||
|
let new_version_string =
|
||||||
|
version_string.replace(path, ¤t_exe.display().to_string());
|
||||||
|
if let Ok(mut version_file) = OpenOptions::new()
|
||||||
|
.truncate(true)
|
||||||
|
.write(true)
|
||||||
|
.open(config_path.join("version"))
|
||||||
|
{
|
||||||
|
let _ = version_file.write(new_version_string.as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if args.client {
|
if args.client {
|
||||||
let banner = "
|
let banner = "
|
||||||
XXXXXXXXXXXXXXXXXXXXXXXXXX
|
XXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
@@ -151,6 +184,7 @@ async fn main() {
|
|||||||
banner.lines().for_each(|line| {
|
banner.lines().for_each(|line| {
|
||||||
appstate.output.push(line.to_string());
|
appstate.output.push(line.to_string());
|
||||||
});
|
});
|
||||||
|
|
||||||
let handles = Arc::new(Mutex::new(Vec::new()));
|
let handles = Arc::new(Mutex::new(Vec::new()));
|
||||||
let handles_clone = handles.clone();
|
let handles_clone = handles.clone();
|
||||||
let primary_handle = spawn(move || {
|
let primary_handle = spawn(move || {
|
||||||
@@ -201,6 +235,13 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut addresses = Vec::new();
|
||||||
|
if let Some(adds) = args.addresses {
|
||||||
|
adds.split(",").into_iter().for_each(|a| {
|
||||||
|
addresses.push(a.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
addresses.push(server_hostname);
|
||||||
let new_server = server::Server {
|
let new_server = server::Server {
|
||||||
address,
|
address,
|
||||||
clients: Vec::new(),
|
clients: Vec::new(),
|
||||||
@@ -208,7 +249,7 @@ async fn main() {
|
|||||||
key_path,
|
key_path,
|
||||||
password: server_pass,
|
password: server_pass,
|
||||||
name,
|
name,
|
||||||
hostname: server_hostname,
|
hostnames: addresses,
|
||||||
};
|
};
|
||||||
let res = start_server(Arc::new(Mutex::new(new_server))).await;
|
let res = start_server(Arc::new(Mutex::new(new_server))).await;
|
||||||
match res {
|
match res {
|
||||||
|
|||||||
+35
-13
@@ -10,6 +10,7 @@ use std::net::IpAddr;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
@@ -21,7 +22,9 @@ pub struct Project {
|
|||||||
pub hosts: Vec<Host>,
|
pub hosts: Vec<Host>,
|
||||||
pub current: bool,
|
pub current: bool,
|
||||||
pub db: Option<DistroBox>,
|
pub db: Option<DistroBox>,
|
||||||
|
pub distrobox: bool,
|
||||||
pub scope: Vec<String>,
|
pub scope: Vec<String>,
|
||||||
|
pub exclusions: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
@@ -35,7 +38,9 @@ impl Project {
|
|||||||
hosts: Vec::new(),
|
hosts: Vec::new(),
|
||||||
current: false,
|
current: false,
|
||||||
db: None,
|
db: None,
|
||||||
|
distrobox: false,
|
||||||
scope: Vec::new(),
|
scope: Vec::new(),
|
||||||
|
exclusions: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +61,18 @@ impl Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_host(&mut self, mut host: Host) {
|
pub fn add_host(&mut self, mut host: Host) {
|
||||||
let mut new_id = 0;
|
if !self.exclusions.contains(&host.ip) {
|
||||||
self.hosts.iter().for_each(|h| {
|
let mut new_id = 0;
|
||||||
if h.id > new_id {
|
self.hosts.iter().for_each(|h| {
|
||||||
new_id = h.id.clone();
|
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);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
new_id += 1;
|
|
||||||
if !self.hosts.iter().any(|h| h.ip == host.ip) {
|
|
||||||
host.id = new_id;
|
|
||||||
self.hosts.push(host);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +113,19 @@ impl Project {
|
|||||||
self.add_scope(ip.trim().to_string());
|
self.add_scope(ip.trim().to_string());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
"exclusions" => {
|
||||||
|
let ips: Vec<&str> = parts[1].split(",").collect();
|
||||||
|
ips.iter().for_each(|ip| {
|
||||||
|
self.exclusions.push(ip.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"db" => {
|
||||||
|
if parts[1].contains("false") {
|
||||||
|
self.distrobox = false;
|
||||||
|
} else {
|
||||||
|
self.distrobox = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,12 +245,14 @@ impl Project {
|
|||||||
}
|
}
|
||||||
let mut file = File::create(&self.config_folder)?;
|
let mut file = File::create(&self.config_folder)?;
|
||||||
let mut out_string = format!(
|
let mut out_string = format!(
|
||||||
"org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\n",
|
"org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\nexclusions: {}\ndb: {}\n",
|
||||||
self.org_name,
|
self.org_name,
|
||||||
self.name,
|
self.name,
|
||||||
self.notes.display(),
|
self.notes.display(),
|
||||||
self.files.display(),
|
self.files.display(),
|
||||||
self.scope.join(","),
|
self.scope.join(","),
|
||||||
|
self.exclusions.join(","),
|
||||||
|
self.distrobox
|
||||||
);
|
);
|
||||||
if self.current {
|
if self.current {
|
||||||
out_string.push_str("stage: current");
|
out_string.push_str("stage: current");
|
||||||
@@ -306,7 +328,7 @@ impl DistroBox {
|
|||||||
if !added_volumes.contains(&String::from(folder_name)) {
|
if !added_volumes.contains(&String::from(folder_name)) {
|
||||||
create_command
|
create_command
|
||||||
.arg("--volume")
|
.arg("--volume")
|
||||||
.arg(format!("{}:/{}:rw", volume, folder_name));
|
.arg(format!("{}:/project:rw", volume));
|
||||||
added_volumes.push(folder_name.to_string());
|
added_volumes.push(folder_name.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,7 +468,7 @@ impl DistroBox {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch_terminal(&self, cmd: String) {
|
pub fn launch_terminal(&self, cmd: String, dir: PathBuf) {
|
||||||
if let Some((terminal_cmd, args)) = cmd.split_once(" ") {
|
if let Some((terminal_cmd, args)) = cmd.split_once(" ") {
|
||||||
let mut term_cmd = Command::new(terminal_cmd);
|
let mut term_cmd = Command::new(terminal_cmd);
|
||||||
args.split(" ").into_iter().for_each(|arg| {
|
args.split(" ").into_iter().for_each(|arg| {
|
||||||
@@ -462,7 +484,7 @@ impl DistroBox {
|
|||||||
term_cmd.arg(arg);
|
term_cmd.arg(arg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let _ = term_cmd.spawn();
|
let _ = term_cmd.current_dir(dir).spawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-5
@@ -23,6 +23,7 @@ enum ClientAction {
|
|||||||
Output(String),
|
Output(String),
|
||||||
Cmd(String),
|
Cmd(String),
|
||||||
Collab(String),
|
Collab(String),
|
||||||
|
Hostnames(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
@@ -49,7 +50,7 @@ pub struct Server {
|
|||||||
pub key_path: PathBuf,
|
pub key_path: PathBuf,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub hostname: String,
|
pub hostnames: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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>> {
|
||||||
@@ -58,13 +59,15 @@ pub async fn start_server(server: Arc<Mutex<Server>>) -> Result<(), Box<dyn Erro
|
|||||||
name_path.pop();
|
name_path.pop();
|
||||||
name_path.push("names.txt");
|
name_path.push("names.txt");
|
||||||
let (server_ip, _) = lock.address.split_once(':').unwrap();
|
let (server_ip, _) = lock.address.split_once(':').unwrap();
|
||||||
let server_hostname = lock.hostname.clone();
|
let server_hostnames = lock.hostnames.clone();
|
||||||
let current_config_names = vec![
|
let mut current_config_names = vec![
|
||||||
server_hostname,
|
|
||||||
server_ip.trim().to_string(),
|
server_ip.trim().to_string(),
|
||||||
"127.0.0.1".to_string(),
|
"127.0.0.1".to_string(),
|
||||||
"localhost".to_string(),
|
"localhost".to_string(),
|
||||||
];
|
];
|
||||||
|
server_hostnames.iter().for_each(|n| {
|
||||||
|
current_config_names.push(n.clone());
|
||||||
|
});
|
||||||
let mut regen = true;
|
let mut regen = true;
|
||||||
if let Ok(saved_names_string) = read_to_string(&name_path).await {
|
if let Ok(saved_names_string) = read_to_string(&name_path).await {
|
||||||
let mut saved_names = Vec::new();
|
let mut saved_names = Vec::new();
|
||||||
@@ -103,7 +106,10 @@ pub async fn start_server(server: Arc<Mutex<Server>>) -> Result<(), Box<dyn Erro
|
|||||||
|
|
||||||
println!("Listening on {}", lock.address);
|
println!("Listening on {}", lock.address);
|
||||||
println!("password: {}", lock.password);
|
println!("password: {}", lock.password);
|
||||||
|
println!("Hostnames:");
|
||||||
|
lock.hostnames.iter().for_each(|h| {
|
||||||
|
println!("{}", h);
|
||||||
|
});
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -479,6 +485,15 @@ where
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
if action.contains("REQ_HOSTNAMES") {
|
||||||
|
let hostnames = lock.hostnames.clone().join(",");
|
||||||
|
lock.clients.iter_mut().filter(|c| c.id == source_id).for_each(|c|{
|
||||||
|
c.actions.push(ClientAction::Hostnames(hostnames.clone()));
|
||||||
|
});
|
||||||
|
println!("hostnames sent!");
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if responses.len() > 0 {
|
if responses.len() > 0 {
|
||||||
@@ -495,6 +510,9 @@ where
|
|||||||
ClientAction::Collab(text) => {
|
ClientAction::Collab(text) => {
|
||||||
println!("todo, {}", text);
|
println!("todo, {}", text);
|
||||||
}
|
}
|
||||||
|
ClientAction::Hostnames(hostnames) => {
|
||||||
|
messages.push(format!("HOSTNAMES|{}", hostnames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let full_message = messages.join("||");
|
let full_message = messages.join("||");
|
||||||
@@ -566,6 +584,9 @@ where
|
|||||||
ClientAction::Collab(text) => {
|
ClientAction::Collab(text) => {
|
||||||
println!("todo, {}", text);
|
println!("todo, {}", text);
|
||||||
}
|
}
|
||||||
|
ClientAction::Hostnames(_) => {
|
||||||
|
messages.push("OUTPUT|Not authenticated".to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let full_message = messages.join("||");
|
let full_message = messages.join("||");
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
config_path="|||CONFIG|||"
|
||||||
|
current_version=$(cat $config_path/version | grep version | cut -d " " -f 2)
|
||||||
|
path=$(cat $config_path/version | grep path | cut -d " " -f 2)
|
||||||
|
version=$(curl https://git.pyro.monster/pyro/tetanus/releases/tag/latest | grep "<title>" | cut -d ">" -f 2 | cut -d " " -f 1)
|
||||||
|
|
||||||
|
if [[ "$version" == "$current_version" ]]; then
|
||||||
|
echo "up to date"
|
||||||
|
else
|
||||||
|
echo "update needed"
|
||||||
|
curl https://git.pyro.monster/pyro/tetanus/releases/download/latest/tetanus -o $config_path/new_tetanus
|
||||||
|
chmod +x $config_path/new_tetanus
|
||||||
|
if [ "$(stat -c '%u' $path)" -eq 0 ]; then
|
||||||
|
sudo cp $config_path/new_tetanus $path
|
||||||
|
else
|
||||||
|
cp $config_path/new_tetanus $path
|
||||||
|
fi
|
||||||
|
echo "version: $version" > $config_path/version
|
||||||
|
echo "path: $path" >> $config_path/version
|
||||||
|
echo update complete!
|
||||||
|
fi
|
||||||
@@ -10,3 +10,24 @@ rayon = "1.12.0"
|
|||||||
rustls = "0.23.43"
|
rustls = "0.23.43"
|
||||||
rustls-pemfile = "2.2.0"
|
rustls-pemfile = "2.2.0"
|
||||||
sysinfo = "0.39.6"
|
sysinfo = "0.39.6"
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "tetanus_victim"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ipnet = "2.12.1"
|
||||||
|
obfstr = "0.4.6"
|
||||||
|
rayon = "1.12.0"
|
||||||
|
rustls = "0.23.43"
|
||||||
|
rustls-pemfile = "2.2.0"
|
||||||
|
sysinfo = "0.39.6"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "s"
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort"
|
||||||
|
strip = "symbols"
|
||||||
|
debug = false
|
||||||
@@ -54,6 +54,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
self.connected = true;
|
self.connected = true;
|
||||||
self.last_check = Instant::now();
|
self.last_check = Instant::now();
|
||||||
|
self.login(self.password.clone())?;
|
||||||
return Ok(self.client_id);
|
return Ok(self.client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user