Compare commits

..

5 commits

Author SHA1 Message Date
Ahmet Kaan GÜMÜŞ
b0501ebe68 docs: 📝 readme 2025-01-05 23:52:33 +03:00
Ahmet Kaan GÜMÜŞ
5f7cd49e37 feat: 🏗️ design strategy about sudo and user changed 2024-07-10 15:43:00 +03:00
Ahmet Kaan GÜMÜŞ
674d3c6963 perf: clippy fix 2024-07-10 14:26:19 +03:00
Ahmet Kaan GÜMÜŞ
9d93e52ac5 feat: fancy prints 2024-07-09 03:55:38 +03:00
Ahmet Kaan GÜMÜŞ
ccc77a09e3 feat: Unix windows compatibility 2024-07-08 17:59:41 +03:00
6 changed files with 121 additions and 64 deletions

View file

@ -1 +1,5 @@
# rust-remote # Remote Code Execution Program
I implemented this for my remote server.
Sometimes ssh can't be possible because of NAT. That's why I add a public remote server as a relay.

View file

@ -66,10 +66,22 @@ async fn serve((ws_sender, mut ws_receiver): (WebSocketSender, WebSocketReceiver
async fn execute(payload: Payload, debug: bool) -> Option<Output> { async fn execute(payload: Payload, debug: bool) -> Option<Output> {
if debug { if debug {
println!("{:#?}", payload); payload.print();
} }
match Command::new(payload.command) let command = if cfg!(target_os = "windows") {
.args(payload.args) "cmd"
} else {
"sh"
};
let first_arg = if cfg!(target_os = "windows") {
"/C"
} else {
"-c"
};
match Command::new(command)
.arg(first_arg)
.arg(payload.args)
.output() .output()
.await .await
{ {
@ -78,7 +90,7 @@ async fn execute(payload: Payload, debug: bool) -> Option<Output> {
if debug { if debug {
eprintln!("Error: Command Execution | {}", err_val); eprintln!("Error: Command Execution | {}", err_val);
} }
return None; None
} }
} }
} }
@ -133,6 +145,10 @@ async fn send(
}, },
}; };
if debug {
report.print();
}
let report = serde_json::json!(report); let report = serde_json::json!(report);
let result = ws_sender.lock().await.send(report.to_string().into()).await; let result = ws_sender.lock().await.send(report.to_string().into()).await;
match result { match result {

View file

@ -11,23 +11,56 @@ pub enum Runner {
Server, Server,
Client, Client,
} }
impl Runner {
fn print(&self) {
println!("-------");
match self {
Runner::Server => println!("Runner = Server"),
Runner::Client => println!("Runner = Client"),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum RunnerMode { pub enum RunnerMode {
State(Runner, bool), State(Runner, bool),
} }
impl RunnerMode {
pub fn print(&self) {
match self {
RunnerMode::State(runner, debug) => {
runner.print();
println!("Debug = {}", debug);
}
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
pub ip: IpAddr, pub ip: IpAddr,
pub port: u16, pub port: u16,
} }
impl Config {
pub fn print(&self) {
println!("-------");
println!("IP = {}", self.ip);
println!("Port = {}", self.port);
}
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Payload { pub struct Payload {
pub sudo: bool, pub args: String,
pub user: String, }
pub command: String,
pub args: Vec<String>, impl Payload {
fn print(&self) {
println!("-------");
println!("args = {}", self.args);
}
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -37,3 +70,23 @@ pub struct Report {
pub stdout: String, pub stdout: String,
pub stderr: String, pub stderr: String,
} }
impl Report {
fn print(&self) {
println!("-------");
println!("Payload ↓");
self.payload.print();
println!("-------");
if !self.status.is_empty() {
println!("Status ↓ \n{}", self.status);
println!("-------");
}
if !self.stdout.is_empty() {
println!("Stdout ↓ \n{}", self.stdout);
println!("-------");
}
if !self.stderr.is_empty() {
println!("Stderr ↓ \n{}", self.stderr);
}
}
}

View file

@ -5,23 +5,27 @@ async fn main() {
println!("Hello, world!"); println!("Hello, world!");
let args = take_args(); let args = take_args();
println!("{:#?}", args);
match args { match args {
Some((runner_mode, config)) => match runner_mode { Some((runner_mode, config)) => {
RunnerMode::State(Runner::Server, false) => { runner_mode.print();
rust_remote::server::start(config, false).await config.print();
match runner_mode {
RunnerMode::State(Runner::Server, false) => {
rust_remote::server::start(config, false).await
}
RunnerMode::State(Runner::Server, true) => {
rust_remote::server::start(config, true).await
}
RunnerMode::State(Runner::Client, false) => {
rust_remote::client::start(config, false).await
}
RunnerMode::State(Runner::Client, true) => {
rust_remote::client::start(config, true).await
}
} }
RunnerMode::State(Runner::Server, true) => { }
rust_remote::server::start(config, true).await
}
RunnerMode::State(Runner::Client, false) => {
rust_remote::client::start(config, false).await
}
RunnerMode::State(Runner::Client, true) => {
rust_remote::client::start(config, true).await
}
},
None => { None => {
eprintln!("Error: Take Args"); eprintln!("Error: Take Args");
return; return;

View file

@ -10,7 +10,7 @@ use tokio::{
}; };
use tokio_tungstenite::{accept_async, tungstenite::Message, WebSocketStream}; use tokio_tungstenite::{accept_async, tungstenite::Message, WebSocketStream};
use crate::{Config, Payload}; use crate::{Config, Payload, Report};
type WebSocketSender = SplitSink<WebSocketStream<TcpStream>, Message>; type WebSocketSender = SplitSink<WebSocketStream<TcpStream>, Message>;
type WebSocketReceiver = SplitStream<WebSocketStream<TcpStream>>; type WebSocketReceiver = SplitStream<WebSocketStream<TcpStream>>;
@ -31,11 +31,22 @@ pub async fn start(config: Config, debug: bool) {
match payload_from_input(debug).await { match payload_from_input(debug).await {
Some(payload) => { Some(payload) => {
if !send(payload, ws_sender, debug).await { if !send(payload, ws_sender, debug).await {
if debug {
eprintln!("Error: Send");
}
break; break;
} }
tokio::spawn(async move { tokio::spawn(async move {
let report = receive(ws_receiver, debug).await; if let Some(report) = receive(ws_receiver, debug).await {
println!("{:#?}", report); match serde_json::from_str::<Report>(&report) {
Ok(report) => report.print(),
Err(err_val) => {
if debug {
eprintln!("Error: Deserialize | {}", err_val);
}
}
}
}
}); });
} }
None => continue, None => continue,
@ -82,38 +93,9 @@ async fn establish_connection(
} }
async fn payload_from_input(debug: bool) -> Option<Payload> { async fn payload_from_input(debug: bool) -> Option<Payload> {
println!("User"); println!("-------");
// let user = match get_input() {
// Some(input) => input,
// None => return None,
// };
let user = "tahinli".to_string();
println!("Command"); println!("Command");
match get_input(debug) { get_input(debug).map(|args| Payload { args })
Some(input) => {
let mut args: Vec<String> = input.split_ascii_whitespace().map(String::from).collect();
if args.is_empty() {
None
} else {
let mut sudo = false;
let mut command = args.remove(0);
if command == "sudo" {
if args.is_empty() {
return None;
}
sudo = true;
command = args.remove(0);
}
Some(Payload {
sudo,
user,
command,
args,
})
}
}
None => None,
}
} }
fn get_input(debug: bool) -> Option<String> { fn get_input(debug: bool) -> Option<String> {

View file

@ -4,7 +4,7 @@ use crate::{Config, Runner, RunnerMode};
pub fn take_args() -> Option<(RunnerMode, Config)> { pub fn take_args() -> Option<(RunnerMode, Config)> {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let mut runner = Runner::Server; let mut runner = Runner::Client;
let mut debug = false; let mut debug = false;
let mut ip = "127.0.0.1".to_string(); let mut ip = "127.0.0.1".to_string();
let mut port = "3444".to_string(); let mut port = "3444".to_string();
@ -13,8 +13,8 @@ pub fn take_args() -> Option<(RunnerMode, Config)> {
"--server" | "-sv" => runner = Runner::Server, "--server" | "-sv" => runner = Runner::Server,
"--client" | "-cl" => runner = Runner::Client, "--client" | "-cl" => runner = Runner::Client,
"--debug" | "-d" => debug = true, "--debug" | "-d" => debug = true,
"--ip" | "-i" => ip = args[i + 1].clone(), "--ip" | "-i" => ip.clone_from(&args[i + 1]),
"--port" | "-p" => port = args[i + 1].clone(), "--port" | "-p" => port.clone_from(&args[i + 1]),
"--help" | "-h" => { "--help" | "-h" => {
show_help(); show_help();
std::process::exit(0); std::process::exit(0);
@ -30,8 +30,6 @@ pub fn take_args() -> Option<(RunnerMode, Config)> {
} }
}; };
println!("{:#?}", ip);
let port = match port.parse::<u16>() { let port = match port.parse::<u16>() {
Ok(port) => port, Ok(port) => port,
Err(err_val) => { Err(err_val) => {
@ -52,8 +50,8 @@ fn show_help() {
println!("----------------------------------------------------------------------"); println!("----------------------------------------------------------------------");
println!(" -i -> --ip | Specifies IP Address | 127.0.0.1"); println!(" -i -> --ip | Specifies IP Address | 127.0.0.1");
println!(" -p -> --port | Specifies Port Address | 3444"); println!(" -p -> --port | Specifies Port Address | 3444");
println!(" -sv -> --server | Starts as a Server | True"); println!(" -sv -> --server | Starts as a Server | False");
println!(" -cl -> --client | Starts as a Client | False"); println!(" -cl -> --client | Starts as a Client | True");
println!(" -d -> --debug | Starts in Debug Mode | False"); println!(" -d -> --debug | Starts in Debug Mode | False");
println!(" -h -> --help | Shows Help | False"); println!(" -h -> --help | Shows Help | False");
println!("\n\n\n"); println!("\n\n\n");