mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-14 16:35:06 +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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
|
|
@ -567,6 +573,12 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
|
@ -599,6 +611,18 @@ dependencies = [
|
|||
"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]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
|
|
@ -796,6 +820,16 @@ dependencies = [
|
|||
"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]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.18"
|
||||
|
|
@ -806,12 +840,15 @@ dependencies = [
|
|||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ ssh-protocol = { path = "./ssh-protocol" }
|
|||
|
||||
tokio = { version = "1.39.2", features = ["full"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
|
||||
|
|
|
|||
114
src/main.rs
114
src/main.rs
|
|
@ -8,7 +8,7 @@ use tokio::{
|
|||
use tracing::{debug, error, info, info_span, Instrument};
|
||||
|
||||
use ssh_protocol::{
|
||||
connection::{ChannelOpen, ChannelOperationKind, ChannelRequestKind},
|
||||
connection::{ChannelOpen, ChannelOperationKind, ChannelRequest},
|
||||
transport::{self, ThreadRngRand},
|
||||
ChannelUpdateKind, ServerConnection, SshStatus,
|
||||
};
|
||||
|
|
@ -16,11 +16,16 @@ use tracing_subscriber::EnvFilter;
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> eyre::Result<()> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
|
||||
)
|
||||
.init();
|
||||
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()
|
||||
.json()
|
||||
.with_env_filter(env_filter)
|
||||
.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());
|
||||
|
||||
|
|
@ -43,7 +48,7 @@ async fn main() -> eyre::Result<()> {
|
|||
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),
|
||||
);
|
||||
|
|
@ -108,23 +113,47 @@ async fn handle_connection(
|
|||
}
|
||||
},
|
||||
ChannelUpdateKind::Request(req) => {
|
||||
match req.kind {
|
||||
ChannelRequestKind::PtyReq { .. } => {}
|
||||
ChannelRequestKind::Shell => {}
|
||||
ChannelRequestKind::Exec { command } => {
|
||||
if command == b"uname -s -v -n -r -m" {
|
||||
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()
|
||||
)));
|
||||
let success = update.number.construct_op(ChannelOperationKind::Success);
|
||||
match req {
|
||||
ChannelRequest::PtyReq { want_reply, .. } => {
|
||||
if want_reply {
|
||||
state.do_operation(success);
|
||||
}
|
||||
}
|
||||
ChannelRequestKind::Env { .. } => {}
|
||||
ChannelRequest::Shell { want_reply } => {
|
||||
if 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(
|
||||
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 { .. } => {}
|
||||
};
|
||||
if req.want_reply {
|
||||
state.do_operation(
|
||||
update.number.construct_op(ChannelOperationKind::Success),
|
||||
);
|
||||
}
|
||||
}
|
||||
ChannelUpdateKind::Data { data } => {
|
||||
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,
|
||||
}
|
||||
|
||||
pub struct ChannelRequest {
|
||||
pub want_reply: bool,
|
||||
pub kind: ChannelRequestKind,
|
||||
}
|
||||
|
||||
pub enum ChannelRequestKind {
|
||||
pub enum ChannelRequest {
|
||||
PtyReq {
|
||||
want_reply: bool,
|
||||
|
||||
term: String,
|
||||
width_chars: u32,
|
||||
height_rows: u32,
|
||||
|
|
@ -57,14 +54,23 @@ pub enum ChannelRequestKind {
|
|||
height_px: u32,
|
||||
term_modes: Vec<u8>,
|
||||
},
|
||||
Shell,
|
||||
Shell {
|
||||
want_reply: bool,
|
||||
},
|
||||
Exec {
|
||||
want_reply: bool,
|
||||
|
||||
command: Vec<u8>,
|
||||
},
|
||||
Env {
|
||||
want_reply: bool,
|
||||
|
||||
name: String,
|
||||
value: Vec<u8>,
|
||||
},
|
||||
ExitStatus {
|
||||
status: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl ChannelNumber {
|
||||
|
|
@ -85,6 +91,8 @@ pub enum ChannelOperationKind {
|
|||
Success,
|
||||
Failure,
|
||||
Data(Vec<u8>),
|
||||
Request(ChannelRequest),
|
||||
Eof,
|
||||
Close,
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +224,7 @@ impl ServerChannelsState {
|
|||
let channel = self.channel(our_channel)?;
|
||||
let peer_channel = channel.peer_channel;
|
||||
|
||||
let channel_request_kind = match request_type {
|
||||
let channel_request = match request_type {
|
||||
"pty-req" => {
|
||||
let term = packet.utf8_string()?;
|
||||
let width_chars = packet.u32()?;
|
||||
|
|
@ -233,7 +241,8 @@ impl ServerChannelsState {
|
|||
"Trying to open a terminal"
|
||||
);
|
||||
|
||||
ChannelRequestKind::PtyReq {
|
||||
ChannelRequest::PtyReq {
|
||||
want_reply,
|
||||
term: term.to_owned(),
|
||||
width_chars,
|
||||
height_rows,
|
||||
|
|
@ -244,12 +253,13 @@ impl ServerChannelsState {
|
|||
}
|
||||
"shell" => {
|
||||
info!(?our_channel, "Opening shell");
|
||||
ChannelRequestKind::Shell
|
||||
ChannelRequest::Shell { want_reply }
|
||||
}
|
||||
"exec" => {
|
||||
let command = packet.string()?;
|
||||
info!(?our_channel, command = ?String::from_utf8_lossy(command), "Executing command");
|
||||
ChannelRequestKind::Exec {
|
||||
ChannelRequest::Exec {
|
||||
want_reply,
|
||||
command: command.to_owned(),
|
||||
}
|
||||
}
|
||||
|
|
@ -259,7 +269,8 @@ impl ServerChannelsState {
|
|||
|
||||
info!(?our_channel, ?name, value = ?String::from_utf8_lossy(value), "Setting environment variable");
|
||||
|
||||
ChannelRequestKind::Env {
|
||||
ChannelRequest::Env {
|
||||
want_reply,
|
||||
name: name.to_owned(),
|
||||
value: value.to_owned(),
|
||||
}
|
||||
|
|
@ -278,10 +289,7 @@ impl ServerChannelsState {
|
|||
|
||||
self.channel_updates.push_back(ChannelUpdate {
|
||||
number: our_channel,
|
||||
kind: ChannelUpdateKind::Request(ChannelRequest {
|
||||
want_reply,
|
||||
kind: channel_request_kind,
|
||||
}),
|
||||
kind: ChannelUpdateKind::Request(channel_request),
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -312,6 +320,27 @@ impl ServerChannelsState {
|
|||
self.packets_to_send
|
||||
.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 => {
|
||||
// <https://datatracker.ietf.org/doc/html/rfc4254#section-5.3>
|
||||
self.packets_to_send
|
||||
|
|
|
|||
|
|
@ -162,16 +162,17 @@ impl ServerConnection {
|
|||
} => {
|
||||
let kex = KeyExchangeInitPacket::parse(&packet.payload)?;
|
||||
|
||||
let require_algorithm =
|
||||
|expected: &'static str, list: NameList<'_>| -> Result<&'static str> {
|
||||
if list.iter().any(|alg| alg == expected) {
|
||||
Ok(expected)
|
||||
} else {
|
||||
Err(client_error!(
|
||||
let require_algorithm = |expected: &'static str,
|
||||
list: NameList<'_>|
|
||||
-> Result<&'static str> {
|
||||
if list.iter().any(|alg| alg == expected) {
|
||||
Ok(expected)
|
||||
} else {
|
||||
Err(client_error!(
|
||||
"client does not supported algorithm {expected}. supported: {list:?}",
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let key_algorithm = require_algorithm("curve25519-sha256", kex.kex_algorithms)?;
|
||||
let server_host_key_algorithm =
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ ctors! {
|
|||
|
||||
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_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_failure(SSH_MSG_CHANNEL_FAILURE; recipient_channel: u32);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue