mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-16 09:25:04 +01:00
many improvements
This commit is contained in:
parent
7a129eba2e
commit
193f762ae9
6 changed files with 188 additions and 46 deletions
37
Cargo.lock
generated
37
Cargo.lock
generated
|
|
@ -291,6 +291,12 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -567,6 +573,12 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -599,6 +611,18 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.122"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.8"
|
version = "0.10.8"
|
||||||
|
|
@ -796,6 +820,16 @@ dependencies = [
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-serde"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.18"
|
version = "0.3.18"
|
||||||
|
|
@ -806,12 +840,15 @@ dependencies = [
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
|
"tracing-serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,4 @@ ssh-protocol = { path = "./ssh-protocol" }
|
||||||
|
|
||||||
tokio = { version = "1.39.2", features = ["full"] }
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
|
||||||
|
|
|
||||||
106
src/main.rs
106
src/main.rs
|
|
@ -8,7 +8,7 @@ use tokio::{
|
||||||
use tracing::{debug, error, info, info_span, Instrument};
|
use tracing::{debug, error, info, info_span, Instrument};
|
||||||
|
|
||||||
use ssh_protocol::{
|
use ssh_protocol::{
|
||||||
connection::{ChannelOpen, ChannelOperationKind, ChannelRequestKind},
|
connection::{ChannelOpen, ChannelOperationKind, ChannelRequest},
|
||||||
transport::{self, ThreadRngRand},
|
transport::{self, ThreadRngRand},
|
||||||
ChannelUpdateKind, ServerConnection, SshStatus,
|
ChannelUpdateKind, ServerConnection, SshStatus,
|
||||||
};
|
};
|
||||||
|
|
@ -16,11 +16,16 @@ use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> eyre::Result<()> {
|
async fn main() -> eyre::Result<()> {
|
||||||
|
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
|
||||||
|
|
||||||
|
if std::env::var("FAKESSH_JSON_LOGS").is_ok_and(|v| v != "0") {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.json()
|
||||||
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
|
.with_env_filter(env_filter)
|
||||||
)
|
|
||||||
.init();
|
.init();
|
||||||
|
} else {
|
||||||
|
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||||
|
}
|
||||||
|
|
||||||
let addr = std::env::var("FAKESSH_LISTEN_ADDR").unwrap_or_else(|_| "0.0.0.0:2222".to_owned());
|
let addr = std::env::var("FAKESSH_LISTEN_ADDR").unwrap_or_else(|_| "0.0.0.0:2222".to_owned());
|
||||||
|
|
||||||
|
|
@ -43,7 +48,7 @@ async fn main() -> eyre::Result<()> {
|
||||||
error!(?err, "error handling connection");
|
error!(?err, "error handling connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(data = ?String::from_utf8_lossy(&total_sent_data), "Finished connection");
|
info!(stdin = ?String::from_utf8_lossy(&total_sent_data), "Finished connection");
|
||||||
}
|
}
|
||||||
.instrument(span),
|
.instrument(span),
|
||||||
);
|
);
|
||||||
|
|
@ -108,23 +113,47 @@ async fn handle_connection(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChannelUpdateKind::Request(req) => {
|
ChannelUpdateKind::Request(req) => {
|
||||||
match req.kind {
|
let success = update.number.construct_op(ChannelOperationKind::Success);
|
||||||
ChannelRequestKind::PtyReq { .. } => {}
|
match req {
|
||||||
ChannelRequestKind::Shell => {}
|
ChannelRequest::PtyReq { want_reply, .. } => {
|
||||||
ChannelRequestKind::Exec { command } => {
|
if want_reply {
|
||||||
if command == b"uname -s -v -n -r -m" {
|
state.do_operation(success);
|
||||||
state.do_operation(update.number.construct_op(ChannelOperationKind::Data(
|
|
||||||
b"Linux nixos 6.6.35 #1-NixOS SMP PREEMPT_DYNAMIC Fri Jun 21 12:38:50 UTC 2024 x86_64\r\n".to_vec()
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChannelRequestKind::Env { .. } => {}
|
ChannelRequest::Shell { want_reply } => {
|
||||||
};
|
if want_reply {
|
||||||
if req.want_reply {
|
state.do_operation(success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChannelRequest::Exec {
|
||||||
|
want_reply,
|
||||||
|
command,
|
||||||
|
} => {
|
||||||
|
if want_reply {
|
||||||
|
state.do_operation(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = execute_command(&command);
|
||||||
state.do_operation(
|
state.do_operation(
|
||||||
update.number.construct_op(ChannelOperationKind::Success),
|
update
|
||||||
|
.number
|
||||||
|
.construct_op(ChannelOperationKind::Data(result.stdout)),
|
||||||
|
);
|
||||||
|
state.do_operation(update.number.construct_op(
|
||||||
|
ChannelOperationKind::Request(ChannelRequest::ExitStatus {
|
||||||
|
status: result.status,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
state.do_operation(
|
||||||
|
update.number.construct_op(ChannelOperationKind::Eof),
|
||||||
|
);
|
||||||
|
state.do_operation(
|
||||||
|
update.number.construct_op(ChannelOperationKind::Close),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
ChannelRequest::ExitStatus { .. } => {}
|
||||||
|
ChannelRequest::Env { .. } => {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
ChannelUpdateKind::Data { data } => {
|
ChannelUpdateKind::Data { data } => {
|
||||||
let is_eof = data.contains(&0x03 /*EOF, Ctrl-C*/);
|
let is_eof = data.contains(&0x03 /*EOF, Ctrl-C*/);
|
||||||
|
|
@ -158,3 +187,46 @@ async fn handle_connection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ProcessOutput {
|
||||||
|
status: u32,
|
||||||
|
stdout: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const UNAME_SVNRM: &[u8] =
|
||||||
|
b"Linux ubuntu 5.15.0-105-generic #115-Ubuntu SMP Mon Apr 15 09:52:04 UTC 2024 x86_64\r\n";
|
||||||
|
const UNAME_A: &[u8] =
|
||||||
|
b"Linux ubuntu 5.15.0-105-generic #115-Ubuntu SMP Mon Apr 15 09:52:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux\r\n";
|
||||||
|
const CPUINFO_UNAME_A: &[u8] = b" 4 AMD EPYC 7282 16-Core Processor\r\n\
|
||||||
|
Linux vps2 5.15.0-105-generic #115-Ubuntu SMP Mon Apr 15 09:52:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux\r\n";
|
||||||
|
|
||||||
|
fn execute_command(command: &[u8]) -> ProcessOutput {
|
||||||
|
let Ok(command) = std::str::from_utf8(command) else {
|
||||||
|
return ProcessOutput {
|
||||||
|
status: 1,
|
||||||
|
stdout: b"what the hell".to_vec(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
match command {
|
||||||
|
"uname -s -v -n -r -m" => ProcessOutput {
|
||||||
|
status: 0,
|
||||||
|
stdout: UNAME_SVNRM.to_vec(),
|
||||||
|
},
|
||||||
|
"uname -a" => ProcessOutput {
|
||||||
|
status: 0,
|
||||||
|
stdout: UNAME_A.to_vec(),
|
||||||
|
},
|
||||||
|
"cat /proc/cpuinfo|grep name|cut -f2 -d':'|uniq -c ; uname -a" => ProcessOutput {
|
||||||
|
status: 0,
|
||||||
|
stdout: CPUINFO_UNAME_A.to_vec(),
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let argv0 = command.split_ascii_whitespace().next().unwrap_or("");
|
||||||
|
|
||||||
|
ProcessOutput {
|
||||||
|
status: 127,
|
||||||
|
stdout: format!("bash: line 1: {argv0}: command not found\r\n").into_bytes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,10 @@ pub enum ChannelOpen {
|
||||||
Session,
|
Session,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChannelRequest {
|
pub enum ChannelRequest {
|
||||||
pub want_reply: bool,
|
|
||||||
pub kind: ChannelRequestKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ChannelRequestKind {
|
|
||||||
PtyReq {
|
PtyReq {
|
||||||
|
want_reply: bool,
|
||||||
|
|
||||||
term: String,
|
term: String,
|
||||||
width_chars: u32,
|
width_chars: u32,
|
||||||
height_rows: u32,
|
height_rows: u32,
|
||||||
|
|
@ -57,14 +54,23 @@ pub enum ChannelRequestKind {
|
||||||
height_px: u32,
|
height_px: u32,
|
||||||
term_modes: Vec<u8>,
|
term_modes: Vec<u8>,
|
||||||
},
|
},
|
||||||
Shell,
|
Shell {
|
||||||
|
want_reply: bool,
|
||||||
|
},
|
||||||
Exec {
|
Exec {
|
||||||
|
want_reply: bool,
|
||||||
|
|
||||||
command: Vec<u8>,
|
command: Vec<u8>,
|
||||||
},
|
},
|
||||||
Env {
|
Env {
|
||||||
|
want_reply: bool,
|
||||||
|
|
||||||
name: String,
|
name: String,
|
||||||
value: Vec<u8>,
|
value: Vec<u8>,
|
||||||
},
|
},
|
||||||
|
ExitStatus {
|
||||||
|
status: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelNumber {
|
impl ChannelNumber {
|
||||||
|
|
@ -85,6 +91,8 @@ pub enum ChannelOperationKind {
|
||||||
Success,
|
Success,
|
||||||
Failure,
|
Failure,
|
||||||
Data(Vec<u8>),
|
Data(Vec<u8>),
|
||||||
|
Request(ChannelRequest),
|
||||||
|
Eof,
|
||||||
Close,
|
Close,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,7 +224,7 @@ impl ServerChannelsState {
|
||||||
let channel = self.channel(our_channel)?;
|
let channel = self.channel(our_channel)?;
|
||||||
let peer_channel = channel.peer_channel;
|
let peer_channel = channel.peer_channel;
|
||||||
|
|
||||||
let channel_request_kind = match request_type {
|
let channel_request = match request_type {
|
||||||
"pty-req" => {
|
"pty-req" => {
|
||||||
let term = packet.utf8_string()?;
|
let term = packet.utf8_string()?;
|
||||||
let width_chars = packet.u32()?;
|
let width_chars = packet.u32()?;
|
||||||
|
|
@ -233,7 +241,8 @@ impl ServerChannelsState {
|
||||||
"Trying to open a terminal"
|
"Trying to open a terminal"
|
||||||
);
|
);
|
||||||
|
|
||||||
ChannelRequestKind::PtyReq {
|
ChannelRequest::PtyReq {
|
||||||
|
want_reply,
|
||||||
term: term.to_owned(),
|
term: term.to_owned(),
|
||||||
width_chars,
|
width_chars,
|
||||||
height_rows,
|
height_rows,
|
||||||
|
|
@ -244,12 +253,13 @@ impl ServerChannelsState {
|
||||||
}
|
}
|
||||||
"shell" => {
|
"shell" => {
|
||||||
info!(?our_channel, "Opening shell");
|
info!(?our_channel, "Opening shell");
|
||||||
ChannelRequestKind::Shell
|
ChannelRequest::Shell { want_reply }
|
||||||
}
|
}
|
||||||
"exec" => {
|
"exec" => {
|
||||||
let command = packet.string()?;
|
let command = packet.string()?;
|
||||||
info!(?our_channel, command = ?String::from_utf8_lossy(command), "Executing command");
|
info!(?our_channel, command = ?String::from_utf8_lossy(command), "Executing command");
|
||||||
ChannelRequestKind::Exec {
|
ChannelRequest::Exec {
|
||||||
|
want_reply,
|
||||||
command: command.to_owned(),
|
command: command.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -259,7 +269,8 @@ impl ServerChannelsState {
|
||||||
|
|
||||||
info!(?our_channel, ?name, value = ?String::from_utf8_lossy(value), "Setting environment variable");
|
info!(?our_channel, ?name, value = ?String::from_utf8_lossy(value), "Setting environment variable");
|
||||||
|
|
||||||
ChannelRequestKind::Env {
|
ChannelRequest::Env {
|
||||||
|
want_reply,
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
value: value.to_owned(),
|
value: value.to_owned(),
|
||||||
}
|
}
|
||||||
|
|
@ -278,10 +289,7 @@ impl ServerChannelsState {
|
||||||
|
|
||||||
self.channel_updates.push_back(ChannelUpdate {
|
self.channel_updates.push_back(ChannelUpdate {
|
||||||
number: our_channel,
|
number: our_channel,
|
||||||
kind: ChannelUpdateKind::Request(ChannelRequest {
|
kind: ChannelUpdateKind::Request(channel_request),
|
||||||
want_reply,
|
|
||||||
kind: channel_request_kind,
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -312,6 +320,27 @@ impl ServerChannelsState {
|
||||||
self.packets_to_send
|
self.packets_to_send
|
||||||
.push_back(Packet::new_msg_channel_data(peer, &data));
|
.push_back(Packet::new_msg_channel_data(peer, &data));
|
||||||
}
|
}
|
||||||
|
ChannelOperationKind::Request(req) => {
|
||||||
|
let packet = match req {
|
||||||
|
ChannelRequest::PtyReq { .. } => todo!("pty-req"),
|
||||||
|
ChannelRequest::Shell { .. } => todo!("shell"),
|
||||||
|
ChannelRequest::Exec { .. } => todo!("exec"),
|
||||||
|
ChannelRequest::Env { .. } => todo!("env"),
|
||||||
|
ChannelRequest::ExitStatus { status } => {
|
||||||
|
Packet::new_msg_channel_request_exit_status(
|
||||||
|
peer,
|
||||||
|
b"exit-status",
|
||||||
|
false,
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.packets_to_send.push_back(packet);
|
||||||
|
}
|
||||||
|
ChannelOperationKind::Eof => {
|
||||||
|
self.packets_to_send
|
||||||
|
.push_back(Packet::new_msg_channel_eof(peer));
|
||||||
|
}
|
||||||
ChannelOperationKind::Close => {
|
ChannelOperationKind::Close => {
|
||||||
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
||||||
self.packets_to_send
|
self.packets_to_send
|
||||||
|
|
|
||||||
|
|
@ -162,8 +162,9 @@ impl ServerConnection {
|
||||||
} => {
|
} => {
|
||||||
let kex = KeyExchangeInitPacket::parse(&packet.payload)?;
|
let kex = KeyExchangeInitPacket::parse(&packet.payload)?;
|
||||||
|
|
||||||
let require_algorithm =
|
let require_algorithm = |expected: &'static str,
|
||||||
|expected: &'static str, list: NameList<'_>| -> Result<&'static str> {
|
list: NameList<'_>|
|
||||||
|
-> Result<&'static str> {
|
||||||
if list.iter().any(|alg| alg == expected) {
|
if list.iter().any(|alg| alg == expected) {
|
||||||
Ok(expected)
|
Ok(expected)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ ctors! {
|
||||||
|
|
||||||
fn new_msg_channel_eof(SSH_MSG_CHANNEL_EOF; recipient_channel: u32);
|
fn new_msg_channel_eof(SSH_MSG_CHANNEL_EOF; recipient_channel: u32);
|
||||||
fn new_msg_channel_close(SSH_MSG_CHANNEL_CLOSE; recipient_channel: u32);
|
fn new_msg_channel_close(SSH_MSG_CHANNEL_CLOSE; recipient_channel: u32);
|
||||||
|
|
||||||
|
fn new_msg_channel_request_exit_status(SSH_MSG_CHANNEL_REQUEST; recipient_channel: u32, kind_exit_status: string, false_: bool, exit_status: u32);
|
||||||
|
|
||||||
fn new_msg_channel_success(SSH_MSG_CHANNEL_SUCCESS; recipient_channel: u32);
|
fn new_msg_channel_success(SSH_MSG_CHANNEL_SUCCESS; recipient_channel: u32);
|
||||||
fn new_msg_channel_failure(SSH_MSG_CHANNEL_FAILURE; recipient_channel: u32);
|
fn new_msg_channel_failure(SSH_MSG_CHANNEL_FAILURE; recipient_channel: u32);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue