refactor for test.

This commit is contained in:
ichiichi11
2020-10-07 00:53:19 +09:00
parent 3f257a52be
commit c3feb1eca2

View File

@@ -40,22 +40,47 @@ impl Security {
}
pub fn disp(&self) {
if self.total_admin_logons > 0 {
println!("total_admin_logons:{}", self.total_admin_logons);
println!("admin_logons:{:?}", self.admin_logons);
println!("multiple_admin_logons:{:?}\n\n", self.multiple_admin_logons);
self.fmt_admin_logons().and_then(Security::print_console);
self.fmt_passspray().and_then(Security::print_console);
}
fn fmt_admin_logons(&self) -> Option<Vec<String>> {
if self.total_admin_logons < 1 {
return Option::None;
}
let exceed_failed_logons = self.total_failed_logons > self.max_failed_logons;
let exist_failed_account = self.account_2_failedcnt.keys().count() as i32 > 1;
if exceed_failed_logons && exist_failed_account {
println!("High number of total logon failures for multiple accounts");
println!(
"Total accounts: {}",
self.account_2_failedcnt.keys().count()
);
println!("Total logon failures: {}\n\n", self.total_failed_logons);
let mut msges: Vec<String> = Vec::new();
msges.push(format!("total_admin_logons:{}", self.total_admin_logons));
msges.push(format!("admin_logons:{:?}", self.admin_logons));
msges.push(format!(
"multiple_admin_logons:{:?}\n\n",
self.multiple_admin_logons
));
return Option::Some(msges);
}
fn fmt_passspray(&self) -> Option<Vec<String>> {
let exceed_failed_logons = self.total_failed_logons <= self.max_failed_logons;
let exist_failed_account = self.account_2_failedcnt.keys().count() as i32 <= 1;
if exceed_failed_logons || exist_failed_account {
return Option::None;
}
let mut msges: Vec<String> = Vec::new();
msges.push(format!(
"High number of total logon failures for multiple accounts"
));
msges.push(format!(
"Total accounts: {}",
self.account_2_failedcnt.keys().count()
));
msges.push(format!(
"Total logon failures: {}\n\n",
self.total_failed_logons
));
return Option::Some(msges);
}
pub fn detection(
@@ -67,13 +92,25 @@ impl Security {
) {
self.process_created(&event_id, &event_data);
self.se_debug_privilege(&event_id, &event_data);
self.account_created(&event_id, &event_data);
self.add_member_security_group(&event_id, &event_data);
self.account_created(&event_id, &event_data)
.and_then(Security::print_console);
self.add_member_security_group(&event_id, &event_data)
.and_then(Security::print_console);
self.failed_logon(&event_id, &event_data);
self.sensitive_priviledge(&event_id, &event_data);
self.attempt_priviledge(&event_id, &event_data);
self.pass_spray(&event_id, &event_data);
self.audit_log_cleared(&event_id, &user_data);
self.sensitive_priviledge(&event_id, &event_data)
.and_then(Security::print_console);
self.attempt_priviledge(&event_id, &event_data)
.and_then(Security::print_console);
self.pass_spray(&event_id, &event_data)
.and_then(Security::print_console);
self.audit_log_cleared(&event_id, &user_data)
.and_then(Security::print_console);
}
fn print_console(v: Vec<String>) -> Option<Vec<String>> {
v.iter().for_each(|s| println!("{}", s));
println!("\n");
return Option::Some(v);
}
fn process_created(&mut self, event_id: &String, _event_data: &HashMap<String, String>) {
@@ -138,20 +175,24 @@ impl Security {
}
// account craeted:OK
fn account_created(&mut self, event_id: &String, event_data: &HashMap<String, String>) {
fn account_created(
&mut self,
event_id: &String,
event_data: &HashMap<String, String>,
) -> Option<Vec<String>> {
if event_id != "4720" {
return;
return Option::None;
}
println!("New User Created");
println!(
"Username: {}",
event_data.get("TargetUserName").unwrap_or(&self.empty_str)
);
println!(
"User SID:: {}\n\n",
event_data.get("TargetSid").unwrap_or(&self.empty_str)
);
let mut msges: Vec<String> = Vec::new();
msges.push("New User Created".to_string());
let username = event_data.get("TargetUserName").unwrap_or(&self.empty_str);
msges.push(format!("Username: {}", username));
let sid = event_data.get("TargetSid").unwrap_or(&self.empty_str);
msges.push(format!("TargetSid: {}", sid));
return Option::Some(msges);
}
// add member to security group
@@ -159,31 +200,30 @@ impl Security {
&mut self,
event_id: &String,
event_data: &HashMap<String, String>,
) {
) -> Option<Vec<String>> {
// check if group is Administrator, may later expand to all groups
if event_data.get("TargetUserName").unwrap_or(&self.empty_str) != "Administrators" {
return;
return Option::None;
}
// A member was added to a security-enabled (global|local|universal) group.
let mut msges: Vec<String> = Vec::new();
if event_id == "4728" {
println!("User added to global Administrators group");
msges.push("User added to global Administrators group".to_string());
} else if event_id == "4732" {
println!("User added to local Administrators group");
msges.push("User added to local Administrators group".to_string());
} else if event_id == "4756" {
println!("User added to universal Administrators group");
msges.push("User added to universal Administrators group".to_string());
} else {
return;
return Option::None;
}
println!(
"Username: {}",
event_data.get("TargetUserName").unwrap_or(&self.empty_str)
);
println!(
"User SID:: {}\n\n",
event_data.get("TargetSid").unwrap_or(&self.empty_str)
);
let username = event_data.get("TargetUserName").unwrap_or(&self.empty_str);
msges.push(format!("Username: {}", username));
let sid = event_data.get("TargetSid").unwrap_or(&self.empty_str);
msges.push(format!("TargetSid: {}", sid));
return Option::Some(msges);
}
// An account failed to log on.:OK
@@ -203,31 +243,42 @@ impl Security {
}
// Sensitive Privilege Use (Mimikatz)
fn sensitive_priviledge(&mut self, event_id: &String, event_data: &HashMap<String, String>) {
fn sensitive_priviledge(
&mut self,
event_id: &String,
event_data: &HashMap<String, String>,
) -> Option<Vec<String>> {
if event_id != "4673" {
return;
return Option::None;
}
self.total_sensitive_privuse += 1;
let mut msges: Vec<String> = Vec::new();
// use == operator here to avoid multiple log notices
if self.max_total_sensitive_privuse == self.total_sensitive_privuse {
println!("Sensititive Privilege Use Exceeds Threshold");
println!(
"Username: {}",
event_data.get("SubjectUserName").unwrap_or(&self.empty_str)
);
println!(
"Domain Name: {}\n\n",
event_data
.get("SubjectDomainName")
.unwrap_or(&self.empty_str)
);
if self.max_total_sensitive_privuse != self.total_sensitive_privuse {
return Option::None;
}
msges.push("Sensititive Privilege Use Exceeds Threshold".to_string());
let username = event_data.get("SubjectUserName").unwrap_or(&self.empty_str);
msges.push(format!("Username: {}", username));
let domainname = event_data
.get("SubjectDomainName")
.unwrap_or(&self.empty_str);
msges.push(format!("Domain Name: {}", domainname));
return Option::Some(msges);
}
fn attempt_priviledge(&mut self, event_id: &String, event_data: &HashMap<String, String>) {
fn attempt_priviledge(
&mut self,
event_id: &String,
event_data: &HashMap<String, String>,
) -> Option<Vec<String>> {
if event_id != "4674" {
return;
return Option::None;
}
// "%%1539" means WRITE_DAC(see detail: https://docs.microsoft.com/ja-jp/windows/security/threat-protection/auditing/event-4663)
@@ -237,23 +288,32 @@ impl Security {
.to_uppercase();
let accessname = event_data.get("AccessMask").unwrap_or(&self.empty_str);
if servicename != r"C:\WINDOWS\SYSTEM32\SERVICES.EXE" || accessname != "%%1539" {
return;
return Option::None;
}
println!("Possible Hidden Service Attempt");
println!("User requested to modify the Dynamic Access Control (DAC) permissions of a sevice, possibly to hide it from view.");
let mut msges: Vec<String> = Vec::new();
msges.push("Possible Hidden Service Attempt".to_string());
msges.push("User requested to modify the Dynamic Access Control (DAC) permissions of a sevice, possibly to hide it from view.".to_string());
let username = event_data.get("SubjectUserName").unwrap_or(&self.empty_str);
println!("User: {}", username);
msges.push(format!("User: {}", username));
let servicename = event_data.get("ObjectName").unwrap_or(&self.empty_str);
println!("Target service: {}", servicename);
println!("WRITE_DAC\n\n");
msges.push(format!("Target service: {}", servicename));
msges.push("WRITE_DAC".to_string());
return Option::Some(msges);
}
// A logon was attempted using explicit credentials.
fn pass_spray(&mut self, event_id: &String, event_data: &HashMap<String, String>) {
fn pass_spray(
&mut self,
event_id: &String,
event_data: &HashMap<String, String>,
) -> Option<Vec<String>> {
if event_id != "4648" {
return;
return Option::None;
}
let targetusername = event_data.get("TargetUserName").unwrap_or(&self.empty_str);
@@ -263,7 +323,7 @@ impl Security {
// check targetuser's attempt count.
if self.passspray_2_user.get(targetusername).unwrap_or(&0) <= &self.max_passspray_login {
return;
return Option::None;
}
// check exceeded targetuser count.
@@ -273,7 +333,7 @@ impl Security {
.filter(|value| value > &&self.max_passspray_login)
.count() as i32;
if spray_uniq_user <= self.max_passspray_uniquser {
return;
return Option::None;
}
let usernames: String = self.passspray_2_user.keys().fold(
@@ -285,37 +345,51 @@ impl Security {
},
);
println!("Distributed Account Explicit Credential Use (Password Spray Attack)");
println!("The use of multiple user account access attempts with explicit credentials is ");
println!("an indicator of a password spray attack.");
println!("Target Usernames: {}", usernames.trim());
println!(
"Accessing Username: {}",
event_data.get("SubjectUserName").unwrap_or(&self.empty_str)
let mut msges: Vec<String> = Vec::new();
msges.push(
"Distributed Account Explicit Credential Use (Password Spray Attack)".to_string(),
);
println!(
"Accessing Host Name: {}\n\n",
event_data
.get("SubjectDomainName")
.unwrap_or(&self.empty_str)
msges.push(
"The use of multiple user account access attempts with explicit credentials is "
.to_string(),
);
msges.push("an indicator of a password spray attack.".to_string());
msges.push(format!("Target Usernames: {}", usernames.trim()));
let access_username = event_data.get("SubjectUserName").unwrap_or(&self.empty_str);
msges.push(format!("Accessing Username: {}", access_username));
let access_hostname = event_data
.get("SubjectDomainName")
.unwrap_or(&self.empty_str);
msges.push(format!("Accessing Host Name: {}", access_hostname));
// reset
self.passspray_2_user = HashMap::new();
return Option::Some(msges);
}
fn audit_log_cleared(&mut self, event_id: &String, user_data: &Option<event::UserData>) {
fn audit_log_cleared(
&mut self,
event_id: &String,
user_data: &Option<event::UserData>,
) -> Option<Vec<String>> {
if event_id != "1102" {
return;
return Option::None;
}
println!("Audit Log Clear");
println!("The Audit log was cleared.");
let mut msges: Vec<String> = Vec::new();
msges.push("Audit Log Clear".to_string());
msges.push("The Audit log was cleared.".to_string());
let username = user_data
.as_ref()
.and_then(|u| u.log_file_cleared.as_ref())
.and_then(|l| l.subject_user_name.as_ref());
println!("Security ID: {}\n\n", username.unwrap_or(&self.empty_str));
msges.push(format!(
"Security ID: {}",
username.unwrap_or(&self.empty_str)
));
return Option::Some(msges);
}
}