mirror of
https://github.com/Astatin3/unshell-nodes-rs.git
synced 2026-06-08 16:18:08 -06:00
Move files around, add UI
This commit is contained in:
+62
@@ -0,0 +1,62 @@
|
||||
use slint::{ModelRc, VecModel};
|
||||
use std::error::Error;
|
||||
use unshell_rs_lib::config::listeners::ListenerConfig;
|
||||
|
||||
pub struct Unshell_Gui;
|
||||
|
||||
slint::include_modules!();
|
||||
impl Unshell_Gui {
|
||||
pub fn start() -> Result<Self, Box<dyn Error>> {
|
||||
let ui = AppWindow::new()?;
|
||||
|
||||
// ui.
|
||||
|
||||
let ui_handle = ui.as_weak();
|
||||
ui.on_tab_clicked(move |index| {
|
||||
let ui = ui_handle.unwrap();
|
||||
ui.set_current_tab(index);
|
||||
trace!("Tab {} selected", index);
|
||||
});
|
||||
|
||||
ui.set_app_info({
|
||||
(String::new()
|
||||
+ "Unshell\n"
|
||||
+ "Version "
|
||||
+ env!("CARGO_PKG_VERSION")
|
||||
+ "\n\n View the source code at:\n https://github.com/astatin3/unshell-rs")
|
||||
.into()
|
||||
});
|
||||
|
||||
let listeners: Vec<ListenerConfig> = vec![ListenerConfig::Tcp {
|
||||
enabled: true,
|
||||
name: "test".to_string(),
|
||||
remote_host: "127.0.0.1".to_string(),
|
||||
port: 25565,
|
||||
layers: Vec::new(),
|
||||
}];
|
||||
|
||||
ui.set_listeners(ModelRc::new(VecModel::from(
|
||||
listeners
|
||||
.iter()
|
||||
.map(|l| match l {
|
||||
ListenerConfig::Tcp {
|
||||
enabled,
|
||||
name,
|
||||
remote_host,
|
||||
port,
|
||||
layers,
|
||||
} => UITcpListener {
|
||||
enabled: *enabled,
|
||||
name: name.clone().into(),
|
||||
remote_host: remote_host.clone().into(),
|
||||
port: *port as i32,
|
||||
},
|
||||
})
|
||||
.collect::<Vec<UITcpListener>>(),
|
||||
)));
|
||||
|
||||
ui.run()?;
|
||||
|
||||
Ok(Self {})
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
use crate::layers::Layer;
|
||||
use base64;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Base64;
|
||||
|
||||
impl Layer for Base64 {
|
||||
fn encode(&mut self, data: &[u8]) -> Vec<u8> {
|
||||
#[allow(deprecated)]
|
||||
base64::encode(str::from_utf8(data).unwrap()).into_bytes()
|
||||
}
|
||||
|
||||
fn decode(&mut self, data: &[u8]) -> Vec<u8> {
|
||||
#[allow(deprecated)]
|
||||
base64::decode(str::from_utf8(data).unwrap()).unwrap()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
pub trait Layer {
|
||||
fn encode(&mut self, data: &[u8]) -> Vec<u8>;
|
||||
fn decode(&mut self, data: &[u8]) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub mod base64;
|
||||
|
||||
pub use base64::Base64;
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
pub mod layers;
|
||||
pub mod listeners;
|
||||
pub mod networkers;
|
||||
pub mod packets;
|
||||
pub mod payload;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod gui;
|
||||
mod server;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
pub struct Client<C> {
|
||||
pub stream: C,
|
||||
}
|
||||
|
||||
impl<C> Client<C> {
|
||||
pub fn new(stream: C) -> Self {
|
||||
Self { stream }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
mod client;
|
||||
mod server;
|
||||
|
||||
pub use server::Listener;
|
||||
@@ -1,49 +0,0 @@
|
||||
use log::{info, trace, warn};
|
||||
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
listeners::client::{self, Client},
|
||||
networkers::{Connection, ServerTrait},
|
||||
packets::Packet,
|
||||
};
|
||||
|
||||
pub struct Listener<S, C> {
|
||||
pub server: Arc<Mutex<S>>,
|
||||
pub clients: Arc<Mutex<Vec<Client<C>>>>,
|
||||
}
|
||||
|
||||
impl<S, C> Listener<S, C> {
|
||||
pub fn new(server: S) -> Self {
|
||||
Self {
|
||||
server: Arc::new(Mutex::new(server)),
|
||||
clients: Arc::new(Mutex::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_listener(&mut self) -> Result<(), Box<dyn std::error::Error>>
|
||||
where
|
||||
S: ServerTrait<C>,
|
||||
C: Connection + 'static,
|
||||
S::Error: std::error::Error + 'static,
|
||||
C::Error: std::error::Error + 'static,
|
||||
{
|
||||
loop {
|
||||
let mut conn_lock = self.server.lock().unwrap();
|
||||
|
||||
match conn_lock.accept() {
|
||||
Ok(conn) => {
|
||||
let mut clients_lock = self.clients.lock().unwrap();
|
||||
clients_lock.push(Client::new(conn));
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to accept connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::trace;
|
||||
use slint::{ModelRc, VecModel};
|
||||
use unshell_rs_lib::{
|
||||
config::listeners::ListenerConfig,
|
||||
listeners::Listener,
|
||||
networkers::{ServerTrait, TCPServer},
|
||||
};
|
||||
|
||||
/// The default port that this program looks for
|
||||
pub static DEFAULT_SERVICE_PORT: u16 = 13370;
|
||||
/// The default website port that this program looks for
|
||||
pub static DEFAULT_WEB_PORT: u16 = 8082;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "unshell-rs")]
|
||||
#[command(about = "Slick reverse shell tool in rust", long_about = None)]
|
||||
struct Args {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Commands {
|
||||
/// Run as a service, and potentially hosting a website
|
||||
#[command(arg_required_else_help = true)]
|
||||
Serve {
|
||||
/// Only listen for command clients locally
|
||||
#[arg(short, long, default_value_t = false)]
|
||||
local: bool,
|
||||
|
||||
/// Port listen to for command clients
|
||||
#[arg(short, long, default_value_t = DEFAULT_SERVICE_PORT)]
|
||||
service_port: u16,
|
||||
// /// Port to listen for website traffic (0 is disabled)
|
||||
// #[arg(short, long, default_value_t = DEFAULT_SERVICE_PORT)]
|
||||
// web_port: u16,
|
||||
},
|
||||
Gui {
|
||||
/// Listen for command clients remotely aswell
|
||||
#[arg(short, long, default_value_t = true)]
|
||||
remote: bool,
|
||||
|
||||
/// Port listen to for command clients
|
||||
#[arg(short, long, default_value_t = DEFAULT_SERVICE_PORT)]
|
||||
service_port: u16,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
pretty_env_logger::init();
|
||||
let args = Args::parse();
|
||||
|
||||
match args.command {
|
||||
Commands::Gui {
|
||||
remote,
|
||||
service_port,
|
||||
} => {}
|
||||
Commands::Serve {
|
||||
local,
|
||||
service_port,
|
||||
// web_port,
|
||||
} => {}
|
||||
}
|
||||
|
||||
// let mut server = Listener::new(TCPServer::bind("0.0.0.0:3000")?);
|
||||
|
||||
// server.run_listener()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/// This is the lowset-level data transmission type
|
||||
|
||||
pub trait Connection: Send + Sync {
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn read(&mut self) -> Result<String, Self::Error>;
|
||||
fn write(&mut self, data: &str) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
pub trait ServerTrait<C: Connection> {
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn accept(&mut self) -> Result<C, Self::Error>;
|
||||
fn bind(address: &str) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub trait ClientTrait<C: Connection> {
|
||||
type Error: std::fmt::Debug;
|
||||
|
||||
fn connect(address: &str) -> Result<C, Self::Error>;
|
||||
}
|
||||
|
||||
mod tcp;
|
||||
|
||||
pub use tcp::TCPClient;
|
||||
pub use tcp::TCPConnection;
|
||||
pub use tcp::TCPServer;
|
||||
@@ -1,57 +0,0 @@
|
||||
use std::{
|
||||
io::{self, BufRead, BufReader, Write},
|
||||
net::{TcpListener, TcpStream},
|
||||
};
|
||||
|
||||
use crate::networkers::{ClientTrait, Connection, ServerTrait};
|
||||
|
||||
pub struct TCPConnection {
|
||||
stream: TcpStream,
|
||||
reader: BufReader<TcpStream>,
|
||||
}
|
||||
|
||||
impl Connection for TCPConnection {
|
||||
type Error = io::Error;
|
||||
|
||||
fn read(&mut self) -> Result<String, Self::Error> {
|
||||
let mut line = String::new();
|
||||
self.reader.read_line(&mut line)?;
|
||||
Ok(line.trim_end().to_string())
|
||||
}
|
||||
|
||||
fn write(&mut self, data: &str) -> Result<(), Self::Error> {
|
||||
writeln!(self.stream, "{}", data)?;
|
||||
self.stream.flush()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TCPServer {
|
||||
listener: TcpListener,
|
||||
}
|
||||
|
||||
impl ServerTrait<TCPConnection> for TCPServer {
|
||||
type Error = io::Error;
|
||||
|
||||
fn accept(&mut self) -> Result<TCPConnection, Self::Error> {
|
||||
let (stream, _) = self.listener.accept()?;
|
||||
let reader = BufReader::new(stream.try_clone()?);
|
||||
Ok(TCPConnection { stream, reader })
|
||||
}
|
||||
|
||||
fn bind(address: &str) -> Result<Self, Self::Error> {
|
||||
let listener = TcpListener::bind(address)?;
|
||||
Ok(Self { listener })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TCPClient;
|
||||
|
||||
impl ClientTrait<TCPConnection> for TCPClient {
|
||||
type Error = io::Error;
|
||||
|
||||
fn connect(address: &str) -> Result<TCPConnection, Self::Error> {
|
||||
let stream = TcpStream::connect(address)?;
|
||||
let reader = BufReader::new(stream.try_clone()?);
|
||||
Ok(TCPConnection { stream, reader })
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod sysinfo;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Packet {
|
||||
Heartbeat,
|
||||
Sysinfo(sysinfo::Sysinfo),
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Sysinfo {
|
||||
hostname: String,
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
networkers::{ClientTrait, Connection},
|
||||
packets::Packet,
|
||||
};
|
||||
|
||||
// Generic client function
|
||||
pub fn run_client<C, Cl>(address: &str) -> Result<(), Box<dyn std::error::Error>>
|
||||
where
|
||||
Cl: ClientTrait<C>,
|
||||
C: Connection + 'static,
|
||||
Cl::Error: std::error::Error + 'static,
|
||||
C::Error: std::error::Error + 'static,
|
||||
{
|
||||
let recv_conn = Arc::new(Mutex::new(Cl::connect(address)?));
|
||||
let transmit_vec: Arc<Mutex<Vec<Packet>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let transmit_conn = Arc::clone(&recv_conn);
|
||||
let transmit_vec_clone = Arc::clone(&transmit_vec);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
let mut transmit_vec_lock = transmit_vec.lock().unwrap();
|
||||
if transmit_vec_lock.len() > 0 {
|
||||
let mut conn_lock = recv_conn.lock().unwrap();
|
||||
if let Ok(json) = serde_json::to_string(&transmit_vec_lock.pop().unwrap()) {
|
||||
conn_lock.write(&json).expect("Failed to send packet!");
|
||||
}
|
||||
} else {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
let mut conn_lock = transmit_conn.lock().unwrap();
|
||||
let data = conn_lock.read();
|
||||
drop(conn_lock);
|
||||
match data {
|
||||
Ok(data_json) => {
|
||||
if data_json.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let packet = serde_json::from_str::<Packet>(data_json.as_str());
|
||||
println!("{:?}", packet);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error reading, {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop {
|
||||
// let mut input = String::new();
|
||||
// stdin.read_line(&mut input)?;
|
||||
// let input = input.trim();
|
||||
|
||||
// if input == "quit" {
|
||||
// conn.write(input)?;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if !input.is_empty() {
|
||||
// conn.write(input)?;
|
||||
|
||||
// match conn.read() {
|
||||
// Ok(response) => println!("Server: {}", response),
|
||||
// Err(e) => {
|
||||
// eprintln!("Failed to read response: {:?}", e);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Reference in New Issue
Block a user