Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bad1c7b66 | ||
|
|
a6e50020ca |
No files matched your search
Generated
+486
-388
File diff suppressed because it is too large.
Load diff
+45
-5
@@ -130,6 +130,7 @@ impl AppState {
|
||||
password: String::new(),
|
||||
name: name.to_string(),
|
||||
cert_text: String::new(),
|
||||
hostnames: Vec::new(),
|
||||
};
|
||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||
}
|
||||
@@ -218,6 +219,7 @@ impl AppState {
|
||||
password: String::new(),
|
||||
name,
|
||||
cert_text: cert,
|
||||
hostnames: Vec::new(),
|
||||
};
|
||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||
}
|
||||
@@ -279,6 +281,7 @@ impl AppState {
|
||||
self.help.push(
|
||||
"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("exit\nquit the tool\n".to_string());
|
||||
self.initialize_modules();
|
||||
return Ok(());
|
||||
@@ -354,24 +357,24 @@ impl AppState {
|
||||
}
|
||||
"generate_victim" => {
|
||||
let mut success = false;
|
||||
let mut addresses = Vec::new();
|
||||
if let Some(args) = command_args {
|
||||
if args.split(" ").into_iter().count() == 1 {
|
||||
let mut address = String::new();
|
||||
if let Some((target, address)) = args.split_once(" ") {
|
||||
let mut password = String::new();
|
||||
let config_file = self.config_file.clone();
|
||||
let files = self.projects[self.selected_project].files.clone();
|
||||
let mut cert_text = String::new();
|
||||
if let Ok(lock) = self.servers[self.selected_server].lock() {
|
||||
address = lock.address.clone();
|
||||
password = lock.password.clone();
|
||||
cert_text = lock.cert_text.clone();
|
||||
addresses = lock.hostnames.clone();
|
||||
}
|
||||
match victim::generate_code(
|
||||
address,
|
||||
address.to_string(),
|
||||
password,
|
||||
config_file,
|
||||
files,
|
||||
args,
|
||||
target.to_string(),
|
||||
self.main_tx.clone(),
|
||||
cert_text,
|
||||
) {
|
||||
@@ -393,6 +396,14 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
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((
|
||||
0,
|
||||
format!("Usage: generate_victim (windows/linux)"),
|
||||
@@ -625,6 +636,7 @@ impl AppState {
|
||||
password: String::new(),
|
||||
name: String::new(),
|
||||
cert_text: String::new(),
|
||||
hostnames: Vec::new(),
|
||||
};
|
||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||
self.save_all()?;
|
||||
@@ -1140,6 +1152,7 @@ impl AppState {
|
||||
}
|
||||
2 => {
|
||||
args_vec[0].split(",").into_iter().for_each(|ip| {
|
||||
if !project.exclusions.contains(&ip.to_string()) {
|
||||
if let Ok(ip) = ip.parse::<IpAddr>() {
|
||||
let mut new_host = Host::new();
|
||||
new_host.ip = ip.to_string();
|
||||
@@ -1151,6 +1164,7 @@ impl AppState {
|
||||
hosts.push(new_host);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
args_vec[1].split(",").into_iter().for_each(|p| {
|
||||
if p.contains("-") {
|
||||
@@ -1649,6 +1663,30 @@ 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());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"exit" => {
|
||||
self.save_all()?;
|
||||
let _ = self.main_tx.send(ToolMessage::AppStateExit);
|
||||
@@ -1934,6 +1972,7 @@ impl AppState {
|
||||
current: false,
|
||||
db: db,
|
||||
scope: Vec::new(),
|
||||
exclusions: Vec::new(),
|
||||
};
|
||||
match new_project.save_config() {
|
||||
Ok(_) => {}
|
||||
@@ -2055,6 +2094,7 @@ impl AppState {
|
||||
password: String::new(),
|
||||
name: String::new(),
|
||||
cert_text: String::new(),
|
||||
hostnames: Vec::new(),
|
||||
};
|
||||
self.servers.push(Arc::new(Mutex::new(new_server)));
|
||||
self.prompt.reset();
|
||||
|
||||
+8
-1
@@ -24,6 +24,7 @@ pub struct Server {
|
||||
pub password: String,
|
||||
pub name: String,
|
||||
pub cert_text: String,
|
||||
pub hostnames: Vec<String>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
@@ -56,7 +57,9 @@ impl Server {
|
||||
self.last_check = Instant::now();
|
||||
let entry = Entry::new("tetanus", &self.address)?;
|
||||
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);
|
||||
}
|
||||
@@ -72,6 +75,7 @@ impl Server {
|
||||
self.last_check = Instant::now();
|
||||
self.logged_in = true;
|
||||
self.message_que.push(format!("SET_NAME|{}", self.name));
|
||||
self.message_que.push(format!("REQ_HOSTNAMES"));
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err("[error] logging in!".into());
|
||||
@@ -82,6 +86,9 @@ impl Server {
|
||||
if self.logged_in {
|
||||
if let Ok(mut stream) = self.tls_connect() {
|
||||
self.last_check = Instant::now();
|
||||
if self.hostnames.is_empty() {
|
||||
self.message_que.push("REQ_HOSTNAMES".to_string());
|
||||
}
|
||||
let payload = format!(
|
||||
"{}**{}|||{}\n",
|
||||
self.password.clone(),
|
||||
|
||||
@@ -595,6 +595,30 @@ pub fn run_tui(
|
||||
let (action, data) =
|
||||
action.split_once("|").unwrap();
|
||||
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" => {
|
||||
let _ = tx_clone.send(
|
||||
ToolMessage::Output((
|
||||
|
||||
+15
-1
@@ -60,6 +60,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."
|
||||
)]
|
||||
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]
|
||||
@@ -201,6 +208,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 {
|
||||
address,
|
||||
clients: Vec::new(),
|
||||
@@ -208,7 +222,7 @@ async fn main() {
|
||||
key_path,
|
||||
password: server_pass,
|
||||
name,
|
||||
hostname: server_hostname,
|
||||
hostnames: addresses,
|
||||
};
|
||||
let res = start_server(Arc::new(Mutex::new(new_server))).await;
|
||||
match res {
|
||||
|
||||
+13
-1
@@ -10,6 +10,7 @@ use std::net::IpAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc::Sender;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Project {
|
||||
@@ -22,6 +23,7 @@ pub struct Project {
|
||||
pub current: bool,
|
||||
pub db: Option<DistroBox>,
|
||||
pub scope: Vec<String>,
|
||||
pub exclusions: Vec<String>,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
@@ -36,6 +38,7 @@ impl Project {
|
||||
current: false,
|
||||
db: None,
|
||||
scope: Vec::new(),
|
||||
exclusions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +59,7 @@ impl Project {
|
||||
}
|
||||
|
||||
pub fn add_host(&mut self, mut host: Host) {
|
||||
if !self.exclusions.contains(&host.ip) {
|
||||
let mut new_id = 0;
|
||||
self.hosts.iter().for_each(|h| {
|
||||
if h.id > new_id {
|
||||
@@ -68,6 +72,7 @@ impl Project {
|
||||
self.hosts.push(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config_folder(&mut self, path: PathBuf) {
|
||||
self.config_folder = path;
|
||||
@@ -106,6 +111,12 @@ impl Project {
|
||||
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());
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -225,12 +236,13 @@ impl Project {
|
||||
}
|
||||
let mut file = File::create(&self.config_folder)?;
|
||||
let mut out_string = format!(
|
||||
"org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\n",
|
||||
"org_name: {}\nname: {}\nnotes: {}\nfiles: {}\nscope: {}\nexclusions: {}\n",
|
||||
self.org_name,
|
||||
self.name,
|
||||
self.notes.display(),
|
||||
self.files.display(),
|
||||
self.scope.join(","),
|
||||
self.exclusions.join(","),
|
||||
);
|
||||
if self.current {
|
||||
out_string.push_str("stage: current");
|
||||
|
||||
+26
-5
@@ -23,6 +23,7 @@ enum ClientAction {
|
||||
Output(String),
|
||||
Cmd(String),
|
||||
Collab(String),
|
||||
Hostnames(String),
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
@@ -49,7 +50,7 @@ pub struct Server {
|
||||
pub key_path: PathBuf,
|
||||
pub password: String,
|
||||
pub name: String,
|
||||
pub hostname: String,
|
||||
pub hostnames: Vec<String>,
|
||||
}
|
||||
|
||||
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.push("names.txt");
|
||||
let (server_ip, _) = lock.address.split_once(':').unwrap();
|
||||
let server_hostname = lock.hostname.clone();
|
||||
let current_config_names = vec![
|
||||
server_hostname,
|
||||
let server_hostnames = lock.hostnames.clone();
|
||||
let mut current_config_names = vec![
|
||||
server_ip.trim().to_string(),
|
||||
"127.0.0.1".to_string(),
|
||||
"localhost".to_string(),
|
||||
];
|
||||
server_hostnames.iter().for_each(|n| {
|
||||
current_config_names.push(n.clone());
|
||||
});
|
||||
let mut regen = true;
|
||||
if let Ok(saved_names_string) = read_to_string(&name_path).await {
|
||||
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!("password: {}", lock.password);
|
||||
|
||||
println!("Hostnames:");
|
||||
lock.hostnames.iter().for_each(|h| {
|
||||
println!("{}", h);
|
||||
});
|
||||
drop(lock);
|
||||
|
||||
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 {
|
||||
@@ -495,6 +510,9 @@ where
|
||||
ClientAction::Collab(text) => {
|
||||
println!("todo, {}", text);
|
||||
}
|
||||
ClientAction::Hostnames(hostnames) => {
|
||||
messages.push(format!("HOSTNAMES|{}", hostnames));
|
||||
}
|
||||
}
|
||||
}
|
||||
let full_message = messages.join("||");
|
||||
@@ -566,6 +584,9 @@ where
|
||||
ClientAction::Collab(text) => {
|
||||
println!("todo, {}", text);
|
||||
}
|
||||
ClientAction::Hostnames(_) => {
|
||||
messages.push("OUTPUT|Not authenticated".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
let full_message = messages.join("||");
|
||||
|
||||
@@ -10,3 +10,24 @@ rayon = "1.12.0"
|
||||
rustls = "0.23.43"
|
||||
rustls-pemfile = "2.2.0"
|
||||
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.last_check = Instant::now();
|
||||
self.login(self.password.clone())?;
|
||||
return Ok(self.client_id);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user