Added Windows support for the bind shell

Brings in support from winpcap as npcap has a restrictive license
This commit is contained in:
Andrew Rioux 2024-01-24 19:12:45 -05:00
parent 862dc3e743
commit af5ceb66ab
Signed by: andrew.rioux
GPG Key ID: 9B8BAC47C17ABB94
10 changed files with 97 additions and 26 deletions

View File

@ -62,12 +62,13 @@
craneLib = (crane.mkLib pkgs).overrideToolchain toolchain;
src = craneLib.path ./.;
src = craneLib.cleanCargoSource (craneLib.path ./.);
windowsSrc = craneLib.path ./.;
commonArgs = {
inherit src;
strictDeps = true;
strictDeps = false;
CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static";
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
@ -82,8 +83,12 @@
};
commonWindowsArgs = commonArgs // {
src = windowsSrc;
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
SPARSE_BUILD_WINPCAP = "${winpcap}/Lib";
nativeBuildInputs = windowsBuildTools;
buildInputs = windowsBuildTools;
};
@ -94,17 +99,29 @@
sparse-05-linux-server = craneLib.buildPackage (commonArgs // {
inherit artifacts;
pname = "sparse-05-server";
pname = "sparse-05-linux-server";
cargoExtraArgs = "-p sparse-05-server --locked";
});
sparse-05-windows-server = craneLib.buildPackage (commonWindowsArgs // {
inherit windowsArtifacts;
artifacts = windowsArtifacts;
pname = "sparse-05-server";
pname = "sparse-05-windows-server";
cargoExtraArgs = "-p sparse-05-server --locked";
});
sparse-05-client = craneLib.buildPackage (commonArgs // {
inherit artifacts;
SPARSE_WINDOWS_SERVER =
"${sparse-05-windows-server}/bin/sparse-05-server.exe";
SPARSE_LINUX_SERVER =
"${sparse-05-linux-server}/bin/sparse-05-server";
pname = "sparse-05-client";
cargoExtraArgs = "-p sparse-05-client --locked";
});
sparse-c2-linux-beacon = craneLib.buildPackage (commonArgs // {
inherit artifacts;
@ -117,15 +134,18 @@
buildInputs = windowsBuildTools ++ [ rust-analyzer ];
SPARSE_BUILD_WINPCAP = "${winpcap}/Lib";
SPARSE_BUILD_LIBPCAP = "${libpcap-src}";
SPARSE_BUILD_LIBNL = "${libnl}";
};
packages = {
inherit sparse-05-linux-server sparse-05-windows-server;
inherit sparse-05-client;
inherit sparse-c2-linux-beacon;
default = sparse-c2-linux-beacon;
default = sparse-05-client;
};
});
}

View File

@ -23,7 +23,7 @@ fn main() -> std::io::Result<()> {
let mut options = CopyOptions::new();
options.copy_inside = true;
options.skip_exist = true;
copy(std::env!("SPARSE_BUILD_LIBNL"), &libnl_src, &options).expect("could not copy nl");
copy(std::env::var("SPARSE_BUILD_LIBNL").unwrap(), &libnl_src, &options).expect("could not copy nl");
let dst = autotools::Config::new(libnl_src).reconf("-vi").build();

View File

@ -17,14 +17,16 @@ use fs_extra::dir::{copy, CopyOptions};
fn main() {
if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
println!("cargo:rustc-lib-lib=pcap");
println!("cargo:rustc-link-search=native={}", std::env::var("SPARSE_BUILD_WINPCAP").unwrap());
println!("cargo:rustc-link-search=native={}/x64", std::env::var("SPARSE_BUILD_WINPCAP").unwrap());
println!("cargo:rustc-link-lib=wpcap");
} else {
let libpcap_src = format!("{}/pcap_src", std::env::var("OUT_DIR").unwrap());
let mut options = CopyOptions::new();
options.copy_inside = true;
options.skip_exist = true;
copy(std::env!("SPARSE_BUILD_LIBPCAP"), &libpcap_src, &options).expect("could not copy libpcap source code to build");
copy(std::env::var("SPARSE_BUILD_LIBPCAP").unwrap(), &libpcap_src, &options).expect("could not copy libpcap source code to build");
let dst = cmake::Config::new(&libpcap_src)
.define("BUILD_SHARED_LIBS", "OFF")

View File

@ -228,7 +228,7 @@ impl<T: Disabled> Interface<T> {
}
pub fn activate(mut self) -> error::Result<Interface<DevActivated>> {
if unsafe { ffi::pcap_activate(self.dev) } != 0 {
if unsafe { dbg!(ffi::pcap_activate(self.dev)) } != 0 {
Err(unsafe { ffi::pcap_geterr(self.dev) })?;
}

View File

@ -15,7 +15,7 @@ serde = { version = "1.0.188", features = ["derive"] }
sparse-05-common = { version = "0.1.0", path = "../sparse-05-common" }
structopt = { version = "0.3.26", features = ["paw"] }
tempfile = "3.8.0"
tokio = { version = "1.32.0", features = ["io-std", "net", "fs", "macros", "rt"] }
tokio = { version = "1.32.0", features = ["full"] }
[target.'cfg(unix)'.dependencies]
raw_tty = "0.1.0"

View File

@ -11,13 +11,13 @@ pub const SPARSE_LINUX_SERVER_BINARY: &'static [u8] =
include_bytes!("../../../../target/debug/sparse-05-server");
#[cfg(not(debug_assertions))]
pub const SPARSE_LINUX_SERVER_BINARY: &'static [u8] =
include_bytes!("../../../../target/release/sparse-05-server");
include_bytes!(std::env!("SPARSE_LINUX_SERVER"));
#[cfg(debug_assertions)]
pub const SPARSE_WINDOWS_SERVER_BINARY: &'static [u8] =
include_bytes!("../../../../target/x86_64-pc-windows-gnu/debug/sparse-05-server.exe");
#[cfg(not(debug_assertions))]
pub const SPARSE_WINDOWS_SERVER_BINARY: &'static [u8] =
include_bytes!("../../../../target/x86_64-pc-windows-gnu/release/sparse-05-server.exe");
include_bytes!(std::env!("SPARSE_WINDOWS_SERVER"));
pub async fn generate(mut name: PathBuf, port: u16, target: TargetOs) -> anyhow::Result<()> {
let mut csprng = rand::thread_rng();

View File

@ -0,0 +1 @@
windows

View File

@ -4,6 +4,7 @@ use std::path::PathBuf;
use sparse_05_common::messages::{Capabilities, OperatingSystem, TransportType};
#[derive(Debug)]
pub struct SrvCapabilities {
pub operating_system: OperatingSystem,
pub docker_container: bool,
@ -140,8 +141,12 @@ fn get_current_capabilities() -> anyhow::Result<SrvCapabilities> {
docker_breakout: false,
setuid: false,
root: userent.as_deref() == Some("Administrator"),
userent,
transport: TransportType::Udp,
userent: userent.clone(),
transport: TransportType::RawUdp, /*if userent.as_deref() == Some("Administrator") {
TransportType::RawUdp
} else {
TransportType::Udp
},*/
hostname: None,
})
}

View File

@ -19,10 +19,24 @@ impl Interface {
match ttype {
#[cfg(feature = "pcap")]
TransportType::RawUdp => {
if cfg!(target_os = "windows") {
let interfaces = pcap_sys::PcapDevIterator::new()?;
for interface in interfaces {
log::debug!("Found interface: {}", interface);
}
}
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
let interface_name = interfaces
let interface_name = if cfg!(windows) {
interfaces
.next()
.ok_or(anyhow!("could not get an ethernet interface"))?
} else {
interfaces
.find(|eth| eth.starts_with("eth") || eth.starts_with("en"))
.ok_or(anyhow!("could not get an ethernet interface"))?;
.ok_or(anyhow!("could not get an ethernet interface"))?
};
let interface = loop {
thread::sleep(std::time::Duration::from_millis(250));
@ -47,14 +61,24 @@ impl Interface {
&interface_name
));
retry!(interface.set_buffer_size(8192));
retry!(interface.set_buffer_size(1024));
retry!(interface.set_non_blocking(false));
retry!(interface.set_promisc(false));
retry!(interface.set_timeout(10));
log::debug!("Configured raw listener interface");
let interface = retry!(interface.activate());
retry!(interface.set_filter(&format!("inbound and port {port}"), true, None));
log::debug!("Activated raw listener interface");
if cfg!(windows) {
retry!(interface.set_filter(&format!("udp port {port}"), true, None));
} else {
retry!(interface.set_filter(&format!("inbound and udp port {port}"), true, None));
}
log::debug!("Updated filter for listener interface");
if interface.datalink() != pcap_sys::consts::DLT_EN10MB {
bail!("interface does not properly support ethernet");
@ -79,11 +103,11 @@ impl Interface {
pub fn split(self) -> anyhow::Result<(InterfaceSender, InterfaceReceiver)> {
match self {
#[cfg(feature = "pcap")]
Self::RawUdp(interface, _) => {
Self::RawUdp(interface, port) => {
let arc = Arc::new(interface);
Ok((
InterfaceSender::RawUdp(Arc::clone(&arc)),
InterfaceReceiver::RawUdp(arc),
InterfaceReceiver::RawUdp(arc, port),
))
}
Self::Udp(interface, port) => {
@ -129,7 +153,7 @@ impl InterfaceSender {
pub enum InterfaceReceiver {
#[cfg(feature = "pcap")]
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>, u16),
Udp(UdpSocket, u16),
}
@ -140,8 +164,19 @@ impl InterfaceReceiver {
{
match self {
#[cfg(feature = "pcap")]
Self::RawUdp(interf) => interf.listen(
Self::RawUdp(interf, port) => interf.listen(
move |_, packet| {
use packets::*;
let Ok(Layer3Pkt::IPv4Pkt(ip_pkt)) = packet.get_layer3_pkt() else {
return Ok(false);
};
let Ok(Layer4Pkt::UDP(udp_pkt)) = ip_pkt.get_layer4_packet() else {
return Ok(false);
};
log::debug!("Received packet bound for {}!", udp_pkt.dstport());
if udp_pkt.dstport() != *port {
return Ok(false);
}
let _ = (f)(packet.to_owned());
Ok(false)
},

View File

@ -20,12 +20,18 @@ mod interface;
fn main() -> anyhow::Result<()> {
simple_logger::SimpleLogger::new()
.with_level(log::LevelFilter::Off)
.with_module_level("sparse-05-server", log::LevelFilter::Info)
.with_level(log::LevelFilter::Debug)
.with_module_level("sparse-05-server", log::LevelFilter::Debug)
.init()?;
log::debug!("Debug logging enabled");
log::info!("Informational logging enabled");
log::warn!("Warning logging enabled");
let capabilities = Arc::new(capabilities::get_capabilities()?);
log::debug!("Capabilities: {:?}", capabilities);
let config_bytes = catconf::read_from_exe(CONFIG_SEPARATOR, 512)?;
if config_bytes.len() != 66 {
bail!("could not load configuration");
@ -74,6 +80,8 @@ fn main() -> anyhow::Result<()> {
let pkt = pkt.pkt();
log::debug!("Received packet!");
let Layer3Pkt::IPv4Pkt(ip_pkt) = pkt.get_layer3_pkt()? else {
todo!()
};