Skip to content

Commit

Permalink
feat: internal fields
Browse files Browse the repository at this point in the history
  • Loading branch information
= committed Nov 8, 2023
1 parent cc24d52 commit 60688bf
Show file tree
Hide file tree
Showing 24 changed files with 1,534 additions and 943 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

/.cargo/
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "u-siem"
version = "0.5.5"
version = "0.7.0"
authors = ["Samuel Garcés <samuel.garces@protonmail.com>"]
license = "MIT"
description = "A framework for building custom SIEMs"
Expand Down
2 changes: 1 addition & 1 deletion src/components/command_types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};

use crate::events::field::SiemIp;
use crate::events::ip::SiemIp;

use super::{
common::UserRole,
Expand Down
2 changes: 1 addition & 1 deletion src/components/dataset/ip_map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::super::super::events::field::SiemIp;
use crate::prelude::SiemIp;
use crate::prelude::types::LogString;
use crossbeam_channel::Sender;
use serde::Serialize;
Expand Down
2 changes: 1 addition & 1 deletion src/components/dataset/ip_map_list.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::super::super::events::field::SiemIp;
use crate::prelude::SiemIp;
use crate::prelude::types::LogString;
use crossbeam_channel::Sender;
use serde::Serialize;
Expand Down
2 changes: 1 addition & 1 deletion src/components/dataset/ip_net.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::super::super::events::field::SiemIp;
use crate::prelude::SiemIp;
use crate::prelude::types::LogString;
use crossbeam_channel::Sender;
use serde::Serialize;
Expand Down
2 changes: 1 addition & 1 deletion src/components/dataset/ip_set.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::super::super::events::field::SiemIp;
use crate::prelude::SiemIp;
use crossbeam_channel::Sender;
use serde::Serialize;
use std::collections::BTreeSet;
Expand Down
100 changes: 99 additions & 1 deletion src/events/auth.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::prelude::types::LogString;
use crate::prelude::{types::LogString, SiemLog, SiemField, SiemIp};
use serde::{Deserialize, Serialize};

use super::field_dictionary::*;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AuthEvent {
/// Login type: local, remote, upgrade (change user)
Expand Down Expand Up @@ -179,3 +181,99 @@ impl std::fmt::Display for LoginOutcome {
// fmt::Debug::fmt(self, f)
}
}


impl Into<SiemLog> for AuthEvent {
fn into(self) -> SiemLog {
let mut log = SiemLog::new("", 0, "");
log.add_field(
"host.hostname",
SiemField::Text(self.hostname),
);
log.add_field(
EVENT_OUTCOME,
SiemField::Text(LogString::Owned(self.outcome.to_string())),
);
match self.login_type {
AuthLoginType::Local(evnt) => {
log.add_field(
USER_NAME,
SiemField::User(evnt.user_name.to_string()),
);
log.add_field(
USER_DOMAIN,
SiemField::Domain(evnt.domain.to_string()),
);
}
AuthLoginType::Remote(evnt) => {
log.add_field(
USER_NAME,
SiemField::User(evnt.user_name.to_string()),
);
log.add_field(
USER_DOMAIN,
SiemField::Domain(evnt.domain.to_string()),
);
match SiemIp::from_ip_str(&evnt.source_address) {
Ok(ip) => {
log.add_field(SOURCE_IP, SiemField::IP(ip));
}
Err(_) => {}
};
log.add_field(
"source.address",
SiemField::Text(evnt.source_address),
);
}
AuthLoginType::Upgrade(evnt) => {
log.add_field(
USER_NAME,
SiemField::User(evnt.destination_user.to_string()),
);
log.add_field(
"source.user.name",
SiemField::User(evnt.source_user.to_string()),
);
log.add_field(
USER_DOMAIN,
SiemField::Domain(evnt.destination_domain.to_string()),
);
}
AuthLoginType::Validation(evnt) => {
log.add_field(
USER_NAME,
SiemField::User(evnt.user_name.to_string()),
);
match SiemIp::from_ip_str(&evnt.source_address) {
Ok(ip) => {
log.add_field("source.ip", SiemField::IP(ip));
}
Err(_) => {}
};
log.add_field(
"source.address",
SiemField::Text(evnt.source_address),
);
}
AuthLoginType::Delegation(evnt) => {
log.add_field(
USER_NAME,
SiemField::User(evnt.destination_user.to_string()),
);
log.add_field(
"source.user.name",
SiemField::User(evnt.source_user.to_string()),
);
log.add_field(
USER_DOMAIN,
SiemField::Domain(evnt.destination_domain.to_string()),
);
log.add_field(
"source.user.domain",
SiemField::Domain(evnt.source_domain.to_string()),
);
}
};
log
}
}
42 changes: 40 additions & 2 deletions src/events/dhcp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::prelude::types::LogString;
use crate::prelude::{types::LogString, SiemField, SiemLog, mac::mac_u128_to_str};

use super::field::SiemIp;
use super::{ip::SiemIp, field_dictionary::*};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -57,3 +57,41 @@ impl DhcpRecordType {
}
}
}

impl Into<SiemLog> for DhcpEvent {
fn into(self) -> SiemLog {
let mut log = SiemLog::new("", 0, "");
log.add_field(
"host.hostname",
SiemField::Text(LogString::Owned(self.hostname().to_string())),
);
log.add_field(
"server.hostname",
SiemField::Text(self.hostname),
);
log.add_field(
"client.hostname",
SiemField::Text(self.source_hostname),
);
log.add_field("client.ip", SiemField::IP(self.source_ip.clone()));
log.add_field(
"client.mac",
SiemField::Text(LogString::Owned(mac_u128_to_str(self.source_mac))),
);
log.add_field(
DHCP_RECORD_TYPE,
SiemField::from_str(self.record_type.to_string()),
);
match self.record_type {
DhcpRecordType::Assign => {}
DhcpRecordType::Release => {}
DhcpRecordType::Request => {
log.add_field(
"self.requested_ip",
SiemField::IP(self.source_ip),
);
}
};
log
}
}
40 changes: 38 additions & 2 deletions src/events/dns.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::prelude::types::LogString;
use crate::prelude::{types::LogString, SiemLog, SiemField};

use super::field::SiemIp;
use super::{ip::SiemIp, field_dictionary::*};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -91,3 +91,39 @@ impl DnsRecordType {
}
}
}
impl Into<SiemLog> for DnsEvent {
fn into(self) -> SiemLog {
let mut log = SiemLog::new("", 0, "");
log.add_field(SOURCE_IP, SiemField::IP(self.source_ip));
log.add_field(DESTINATION_IP, SiemField::IP(self.destination_ip));
match self.op_code {
DnsEventType::ANSWER => {
log.add_field(DNS_OP_CODE, SiemField::Text(LogString::Borrowed("ANSWER")));
log.add_field(
DNS_ANSWER_NAME,
SiemField::Text(self.record_name)
);
match self.data {
Some(data) => {
log.add_field(DNS_ANSWER_DATA, SiemField::from_str(data.to_string()));
}
None => {}
};
log.add_field(DNS_ANSWER_TYPE, SiemField::Text(self.record_type.as_cow()));
}
DnsEventType::QUERY => {
log.add_field(DNS_OP_CODE, SiemField::Text(LogString::Borrowed("QUERY")));

log.add_field(
DNS_QUESTION_NAME,
SiemField::Text(self.record_name)
);
log.add_field(
DNS_QUESTION_TYPE,
SiemField::Text(self.record_type.as_cow()),
);
}
};
log
}
}
89 changes: 89 additions & 0 deletions src/events/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use serde::{Serialize, Deserialize};

use super::firewall::FirewallEvent;
use super::intrusion::IntrusionEvent;
use super::log::SiemLog;
use super::webproxy::WebProxyEvent;
use super::webserver::WebServerEvent;
use super::auth::AuthEvent;
use super::dhcp::DhcpEvent;
use super::dns::DnsEvent;

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(tag = "event_type")]
pub enum SiemEvent {
/// Firewall events: connections between IPs, blocked connections...
Firewall(FirewallEvent),
/// Intrusion detection/protection systems. Ex: Suricata, Snort, OSSEC, Wazuh, NGFW...
Intrusion(IntrusionEvent),
/// Security related assessment, like the output of vulnerability scanners (Nessus) or policy enforcers (OpenSCAP). PulseSecure and Forescout can also get in this category.
Assessment,
/// Web Browsing Proxy
WebProxy(WebProxyEvent),
/// Web application servers, Adaptative Distribution Content or LoadBalancers for HTTP traffic.
///
///
/// Ex: Apache, Nginx, Tomact or IIS.
WebServer(WebServerEvent),
/// Like an antivirus, a Sandbox retrieves information about a file being malicious or not. Can be used
/// to extract filenames, hashes or other relevant information to update a dataset of known hashes and
/// trigger queries.
///
/// Ex: Wildfire, Mcafee ATD, Cuckoo...
Sandbox,
Antivirus,
/// Data Loss Prevention are devices that detect anomalous behavour related to
/// data exfiltration.
///
/// Ex: Boldon
DLP,
/// Some devices like email gateways generates a large number of logs when an email arrives: Header processing, AV scan, attachment information...
/// In those cases, each log is associated with an action using a trace ID or a transaction ID.
Partitioned,
/// Endpoint Detection and Response devices, also EPP.
EDR,
/// Mail events, as the name suggest are events generated by an email gateway. Can
/// contain threat related information if an anomaly was detected.
/// Note that some devices generate partitioned logs instead of Mail logs.
///
/// Ex: Microsoft Exchange, IronPort, Office 365...
Mail,
/// DNS requests events. To better correlate this type of events, be carefull of checking if it contains a dns_server
/// tag, because that means that the originator of the request is a Recursive DNS and not an endpoint. It normally
/// happens if the one generating the log was a firewall (Ex: Palo Alto) and not a DNS server, or if multiple DNS are
/// used in the organization, like a DNS talking to another DNS.
DNS(DnsEvent),
/// DHCP logs associating an IP with a MAC address.
DHCP(DhcpEvent),
/// Logs related to authentication, like a user trying to log in to a Router,
/// a server or any kind of system.
///
/// Ex: RDP, Windows, Linux, Mailbox login...
Auth(AuthEvent),
/// Local events related to servers or workstations, like OS failed to update,
/// antivirus outdated, log file cleaned, user or group changes (Including global or universal domain events).
/// Also events related to network devices: Changes in routing policys, Firewall rules, Shutdown out of mantaince
Endpoint,
// Unknown info that must be extracted and added to event fields. JSON format, like Windows events
Json(serde_json::Value),
// Unknown info that must be extracted and added to event fields.
#[default]
Unknown,
/// Forensic artifacts from custom parsers
Artifacts,
}

impl Into<SiemLog> for SiemEvent {
fn into(self) -> SiemLog {
match self {
SiemEvent::Firewall(fw) => fw.into(),
SiemEvent::WebProxy(v) => v.into(),
SiemEvent::DNS(v) => v.into(),
SiemEvent::Intrusion(v) => v.into(),
SiemEvent::WebServer(v) => v.into(),
SiemEvent::Auth(v) => v.into(),
SiemEvent::DHCP(v) => v.into(),
_ => SiemLog::new("", 0, "")
}
}
}
Loading

0 comments on commit 60688bf

Please sign in to comment.