Skip to content

Commit

Permalink
More additions, need to fix CI and do Windows things
Browse files Browse the repository at this point in the history
  • Loading branch information
MEhrn00 committed Feb 10, 2024
1 parent 8452859 commit 2dc256f
Show file tree
Hide file tree
Showing 21 changed files with 220 additions and 144 deletions.
2 changes: 2 additions & 0 deletions Payload_Type/thanatos/agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Payload_Type/thanatos/agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ version = "0.2.0"
##### WORKSPACE DEPENDENCIES #####
[workspace.dependencies]
base64 = "0.21.5"
cfg-if = "1"
hex-literal = "0.4.1"
rmp = "0.8.12"
rmp-serde = "1.1.2"
Expand Down
1 change: 1 addition & 0 deletions Payload_Type/thanatos/agent/cryptolib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ version.workspace = true

[dependencies]
hex-literal.workspace = true
cfg-if.workspace = true

[dependencies.sha2]
workspace = true
Expand Down
6 changes: 6 additions & 0 deletions Payload_Type/thanatos/agent/cryptolib/src/hash/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ impl Sha256 {
}
}

impl Default for Sha256 {
fn default() -> Self {
Self::new()
}
}

#[cfg(test)]
mod tests {
use super::Sha256;
Expand Down
12 changes: 3 additions & 9 deletions Payload_Type/thanatos/agent/cryptolib/src/hash/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
#[cfg(feature = "internal")]
mod internal;
pub mod internal;

#[cfg(feature = "internal")]
pub use internal::*;

//#[cfg(feature = "system")]
mod system;

//#[cfg(feature = "system")]
pub use system::*;
#[cfg(feature = "system")]
pub mod system;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ impl Sha256 {
}
}

impl Default for Sha256 {
fn default() -> Self {
Self::new()
}
}

#[cfg(test)]
mod tests {
use super::Sha256;
Expand Down
12 changes: 6 additions & 6 deletions Payload_Type/thanatos/agent/cryptolib/src/hash/system/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//#[cfg(target_os = "linux")]
//mod linux;
#[cfg(target_os = "linux")]
mod linux;

//#[cfg(target_os = "linux")]
//pub use linux::Sha256;
#[cfg(target_os = "linux")]
pub use linux::Sha256;

//#[cfg(target_os = "windows")]
#[cfg(target_os = "windows")]
mod windows;

//#[cfg(target_os = "windows")]
#[cfg(target_os = "windows")]
pub use windows::Sha256;
4 changes: 1 addition & 3 deletions Payload_Type/thanatos/agent/ffiwrappers/src/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,5 @@ pub use username::username;
pub fn libc_errno() -> i32 {
// SAFETY: `__errno_location` is a pointer to libc's errno value. This pointer
// is guaranteed to be aligned and non-NULL
let ec = unsafe { *libc::__errno_location() };

ec
unsafe { *libc::__errno_location() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod alghandle;
pub use alghandle::{BCryptAlgHandle, BCryptProvider};

mod hash;
pub use hash::*;
pub use hash::BCryptHashHandle;

pub mod algorithms;

Expand Down
76 changes: 76 additions & 0 deletions Payload_Type/thanatos/agent/ffiwrappers/src/windows/domain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use errors::ThanatosError;

use windows::{
core::PSTR,
Win32::{
Foundation::ERROR_MORE_DATA,
System::SystemInformation::{ComputerNameDnsDomain, GetComputerNameExA},
},
};

/// Get the domain name of the system
pub fn domain() -> Result<String, ThanatosError> {
let mut domainname_length = 0u32;

// Get the length of the computer's domain name.
//
// SAFETY: This will return an error from Windows which needs to be checked.
// If this is "successful", then the Windows error should contain 'ERROR_MORE_DATA'.
// This is the error code returned when the buffer is not large enough.
match unsafe {
GetComputerNameExA(
ComputerNameDnsDomain,
PSTR(std::ptr::null_mut()),
&mut domainname_length,
)
} {
// Check if 'ERROR_MORE_DATA' was returned
Err(e) if e.code() == windows::core::Error::from(ERROR_MORE_DATA).code() => (),

// Check if any other error was returned
Err(e) => return Err(ThanatosError::from_windows(e)),

// This function should never return successfully since the length is 0
_ => unreachable!(),
};

// Create a buffer for storing the domain name
//
// The length can safely be casted to a usize using as since the maximum length
// of a Windows domain name is 255 characters.
// ref: https://learn.microsoft.com/en-US/troubleshoot/windows-server/identity/naming-conventions-for-computer-domain-site-ou#dns-domain-names
let mut domainname_buffer = vec![0u8; domainname_length as usize];

// Get the computer's domain name.
//
// SAFETY: A buffer needs to be allocated for holding the domain name. The
// length of the domain was found above. The domain name length must match the
// length of the allocated buffer! An error needs to be checked in case the function fails
unsafe {
GetComputerNameExA(
ComputerNameDnsDomain,
PSTR(domainname_buffer.as_mut_ptr()),
&mut domainname_length,
)
}
.map_err(ThanatosError::from_windows)?;

// Cast the domain name length.
// The domain name length value now contains the length of the system's domain name
// without the NULL terminator.
// ref: https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getcomputernameexa
let domainname_length = domainname_length as usize;

// Convert the domain name buffer to a string
let s = String::from_utf8_lossy(&domainname_buffer[..domainname_length]);
Ok(s.into_owned())
}

#[cfg(test)]
mod tests {
#[test]
fn domainname() {
let domain = super::domain().unwrap();
dbg!(domain);
}
}
3 changes: 3 additions & 0 deletions Payload_Type/thanatos/agent/ffiwrappers/src/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ pub use hostname::hostname;
mod username;
pub use username::username;

mod domain;
pub use domain::domain;

pub mod bcrypt;
4 changes: 4 additions & 0 deletions Payload_Type/thanatos/agent/thanatos_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ version.workspace = true

[dependencies]
base64.workspace = true
cfg-if.workspace = true
rmp.workspace = true
rmp-serde.workspace = true
serde.workspace = true
Expand All @@ -35,3 +36,6 @@ path = "../utils"

[target.'cfg(target_os = "linux")'.dependencies]
dbus.workspace = true

[features]
crypto-system = ["cryptolib/system"]
30 changes: 19 additions & 11 deletions Payload_Type/thanatos/agent/thanatos_core/src/guardrails.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ use crate::native::linux::system;
#[cfg(target_os = "windows")]
use crate::native::windows::system;

cfg_if::cfg_if! {
if #[cfg(feature = "crypto-system")] {
use cryptolib::hash::system::Sha256;
} else {
use cryptolib::hash::internal::Sha256;
}
}

#[cfg(target_os = "linux")]
pub fn check_domain(domains: &Vec<[u8; 32]>) -> bool {
pub fn check_domain(domains: &[[u8; 32]]) -> bool {
let check_domains = match system::domains() {
Ok(check_domains) => check_domains,
Err(_) => return false,
Expand All @@ -17,16 +25,16 @@ pub fn check_domain(domains: &Vec<[u8; 32]>) -> bool {
}

#[cfg(target_os = "windows")]
pub fn check_domain(domains: &Vec<[u8; 32]>) -> bool {
pub fn check_domain(domains: &[[u8; 32]]) -> bool {
let domain = match system::domain() {
Ok(domain) => domain,
Err(_) => return false,
};

check_hashlist_with(domains, domain)
check_hashlist_with(domains, &domain)
}

pub fn check_hostname(hostnames: &Vec<[u8; 32]>) -> bool {
pub fn check_hostname(hostnames: &[[u8; 32]]) -> bool {
let hostname = match system::hostname() {
Ok(hostname) => hostname,
Err(_) => return false,
Expand All @@ -35,7 +43,7 @@ pub fn check_hostname(hostnames: &Vec<[u8; 32]>) -> bool {
check_hashlist_with(hostnames, &hostname)
}

pub fn check_username(usernames: &Vec<[u8; 32]>) -> bool {
pub fn check_username(usernames: &[[u8; 32]]) -> bool {
let username = match system::username() {
Ok(username) => username,
Err(_) => return false,
Expand All @@ -44,10 +52,10 @@ pub fn check_username(usernames: &Vec<[u8; 32]>) -> bool {
check_hashlist_with(usernames, &username)
}

fn check_hashlist_with(hlist: &Vec<[u8; 32]>, value: &str) -> bool {
fn check_hashlist_with(hlist: &[[u8; 32]], value: &str) -> bool {
let value = value.to_lowercase();

let mut h = cryptolib::hash::Sha256::new();
let mut h = Sha256::new();
h.update(value.as_bytes());
let result = h.finalize();
hlist.iter().any(|v| v == &result)
Expand All @@ -64,7 +72,7 @@ mod tests {
"6b0a38edbe6d724b1679bf3ba6ed862975b2403019c7a95f8257d4e840d60df1"
)];

assert!(check_hashlist_with(&hlist_with_value, &input_value));
assert!(check_hashlist_with(&hlist_with_value, input_value));
}

#[test]
Expand All @@ -75,7 +83,7 @@ mod tests {
"795b6904e54f82411df4b0e27a373a55eea3f9d66dac5a9bce1dd92f7b401da5"
)];

assert!(!check_hashlist_with(&hlist_without_value, &input_value));
assert!(!check_hashlist_with(&hlist_without_value, input_value));
}

#[test]
Expand All @@ -86,7 +94,7 @@ mod tests {
"6b0a38edbe6d724b1679bf3ba6ed862975b2403019c7a95f8257d4e840d60df1"
)];

assert!(check_hashlist_with(&hlist, &input_value));
assert!(check_hashlist_with(&hlist, input_value));
}

#[test]
Expand All @@ -101,6 +109,6 @@ mod tests {

#[test]
fn empty_domain_list() {
assert_eq!(check_hashlist_with(&Vec::new(), "foo"), false);
assert!(!check_hashlist_with(&Vec::new(), "foo"));
}
}
18 changes: 6 additions & 12 deletions Payload_Type/thanatos/agent/thanatos_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,18 @@ where
F: Fn(&'a ConfigVars<'b>),
{
let domains = config.domains();
if !domains.is_empty() {
if !guardrails::check_domain(domains) {
return;
}
if !domains.is_empty() && !guardrails::check_domain(domains) {
return;
}

let hostnames = config.hostnames();
if !hostnames.is_empty() {
if !guardrails::check_hostname(hostnames) {
return;
}
if !hostnames.is_empty() && !guardrails::check_hostname(hostnames) {
return;
}

let usernames = config.usernames();
if !usernames.is_empty() {
if !guardrails::check_username(usernames) {
return;
}
if !usernames.is_empty() && !guardrails::check_username(usernames) {
return;
}

f(config)
Expand Down
Loading

0 comments on commit 2dc256f

Please sign in to comment.