1use serde_json::value::Value;
2use serde::{Deserialize, Serialize};
3use colored::Colorize;
4use ldap3::SearchEntry;
5use log::{info, debug, trace};
6use std::collections::HashMap;
7use std::error::Error;
8
9use crate::enums::{OBJECT_SID_RE1, SID_PART1_RE1};
10use crate::objects::common::{LdapObject, Session, AceTemplate, Member, SPNTarget, LocalGroup, Link, DCRegistryData};
11use crate::utils::date::{convert_timestamp,string_to_epoch};
12use crate::utils::crypto::convert_encryption_types;
13use crate::enums::acl::parse_ntsecuritydescriptor;
14use crate::enums::secdesc::LdapSid;
15use crate::enums::sid::sid_maker;
16use crate::enums::uacflags::get_flag;
17
18use super::common::UserRight;
19
20#[derive(Debug, Clone, Deserialize, Serialize, Default)]
22pub struct Computer {
23 #[serde(rename = "Properties")]
24 properties: ComputerProperties,
25 #[serde(rename = "Aces")]
26 aces: Vec<AceTemplate>,
27 #[serde(rename = "ObjectIdentifier")]
28 object_identifier: String,
29 #[serde(rename = "IsDeleted")]
30 is_deleted: bool,
31 #[serde(rename = "IsACLProtected")]
32 is_acl_protected: bool,
33 #[serde(rename = "ContainedBy")]
34 contained_by: Option<Member>,
35
36 #[serde(rename = "PrimaryGroupSID")]
37 primary_group_sid: String,
38 #[serde(rename = "AllowedToDelegate")]
39 allowed_to_delegate: Vec<Member>,
40 #[serde(rename = "AllowedToAct")]
41 allowed_to_act: Vec<Member>,
42 #[serde(rename = "HasSIDHistory")]
43 has_sid_history: Vec<String>,
44 #[serde(rename = "DumpSMSAPassword")]
45 dump_smsa_password: Vec<Member>,
46
47 #[serde(rename = "Sessions")]
48 sessions: Session,
49 #[serde(rename = "PrivilegedSessions")]
50 privileged_sessions: Session,
51 #[serde(rename = "RegistrySessions")]
52 registry_sessions: Session,
53 #[serde(rename = "LocalGroups")]
54 local_groups: Vec<LocalGroup>,
55 #[serde(rename = "UserRights")]
56 users_rights: Vec<UserRight>,
57 #[serde(rename = "DCRegistryData")]
58 dcregistry_data: DCRegistryData,
59
60 #[serde(rename = "IsDC")]
61 is_dc: bool,
62 #[serde(rename = "UnconstrainedDelegation")]
63 unconstrained_delegation: bool,
64 #[serde(rename = "DomainSID")]
65 domain_sid: String,
66
67 #[serde(rename = "Status")]
68 status: Option<String>,
69}
70
71impl Computer {
72 pub fn new() -> Self {
74 Self { ..Default::default() }
75 }
76
77 pub fn properties(&self) -> &ComputerProperties {
79 &self.properties
80 }
81 pub fn object_identifier(&self) -> &String {
82 &self.object_identifier
83 }
84 pub fn allowed_to_act(&self) -> &Vec<Member> {
85 &self.allowed_to_act
86 }
87
88 pub fn allowed_to_act_mut(&mut self) -> &mut Vec<Member> {
90 &mut self.allowed_to_act
91 }
92
93 pub fn parse(
96 &mut self,
97 result: SearchEntry,
98 domain: &str,
99 dn_sid: &mut HashMap<String, String>,
100 sid_type: &mut HashMap<String, String>,
101 fqdn_sid: &mut HashMap<String, String>,
102 fqdn_ip: &mut HashMap<String, String>,
103 domain_sid: &str,
104 schema_guid_map: &HashMap<String, String>,
105 ) -> Result<(), Box<dyn Error>> {
106 let result_dn: String = result.dn.to_uppercase();
107 let result_attrs: HashMap<String, Vec<String>> = result.attrs;
108 let result_bin: HashMap<String, Vec<Vec<u8>>> = result.bin_attrs;
109
110 debug!("Parse computer: {result_dn}");
112
113 for (key, value) in &result_attrs {
115 trace!(" {key:?}:{value:?}");
116 }
117 for (key, value) in &result_bin {
119 trace!(" {key:?}:{value:?}");
120 }
121
122 let mut computer = Computer::new();
124
125 self.properties.domain = domain.to_uppercase();
127 self.properties.distinguishedname = result_dn;
128 self.properties.enabled = true;
129 self.domain_sid = domain_sid.to_string();
130
131 let mut sid: String = "".to_owned();
132 let mut group_id: String = "".to_owned();
133 for (key, value) in &result_attrs {
135 match key.as_str() {
136 "name" => {
137 let name = &value[0];
138 let email = format!("{}.{}",name.to_owned(),domain);
139 self.properties.name = email.to_uppercase();
140 }
141 "sAMAccountName" => {
142 self.properties.samaccountname = value[0].to_owned();
143 }
144 "dNSHostName" => {
145 self.properties.name = value[0].to_uppercase();
146 }
147 "description" => {
148 self.properties.description = Some(value[0].to_owned());
149 }
150 "operatingSystem" => {
151 self.properties.operatingsystem = value[0].to_owned();
152 }
153 "lastLogon" => {
171 let lastlogon = &value[0].parse::<i64>().unwrap_or(0);
172 if lastlogon.is_positive() {
173 let epoch = convert_timestamp(*lastlogon);
174 self.properties.lastlogon = epoch;
175 }
176 }
177 "lastLogonTimestamp" => {
178 let lastlogontimestamp = &value[0].parse::<i64>().unwrap_or(0);
179 if lastlogontimestamp.is_positive() {
180 let epoch = convert_timestamp(*lastlogontimestamp);
181 self.properties.lastlogontimestamp = epoch;
182 }
183 }
184 "pwdLastSet" => {
185 let pwdlastset = &value[0].parse::<i64>().unwrap_or(0);
186 if pwdlastset.is_positive() {
187 let epoch = convert_timestamp(*pwdlastset);
188 self.properties.pwdlastset = epoch;
189 }
190 }
191 "whenCreated" => {
192 let epoch = string_to_epoch(&value[0])?;
193 if epoch.is_positive() {
194 self.properties.whencreated = epoch;
195 }
196 }
197 "servicePrincipalName" => {
198 let mut result: Vec<String> = Vec::new();
200 for value in &result_attrs["servicePrincipalName"] {
201 result.push(value.to_owned());
202 }
203 self.properties.serviceprincipalnames = result;
204 }
205 "userAccountControl" => {
206 let uac = &value[0].parse::<u32>().unwrap();
208 let uac_flags = get_flag(*uac);
209 for flag in uac_flags {
211 if flag.contains("AccountDisable") {
212 self.properties.enabled = false;
213 };
214 if flag.contains("TrustedForDelegation") {
217 self.properties.unconstraineddelegation = true;
218 self.unconstrained_delegation = true;
219 };
220 if flag.contains("TrustedToAuthForDelegation") {
221 self.properties.trustedtoauth = true;
222 };
223 if flag.contains("PasswordNotRequired") {
224 self.properties.passwordnotreqd = true;
225 };
226 if flag.contains("DontExpirePassword") {
227 self.properties.pwdneverexpires = true;
228 };
229 if flag.contains("ServerTrustAccount") {
230 self.properties.is_dc = true;
231 self.is_dc = true;
232 }
233 }
234 }
235 "msDS-AllowedToDelegateTo" => {
236 let mut vec_members2: Vec<Member> = Vec::new();
240 for objet in value {
241 let mut member_allowed_to_delegate = Member::new();
242 let split = objet.split("/");
243 let fqdn = split.collect::<Vec<&str>>()[1];
244 let mut checker = false;
245 for member in &vec_members2 {
246 if member.object_identifier().contains(fqdn.to_uppercase().as_str()) {
247 checker = true;
248 }
249 }
250 if !checker {
251 *member_allowed_to_delegate.object_identifier_mut() = fqdn.to_uppercase().to_owned().to_uppercase();
252 *member_allowed_to_delegate.object_type_mut() = "Computer".to_owned();
253 vec_members2.push(member_allowed_to_delegate.to_owned());
254 }
255 }
256 self.allowed_to_delegate = vec_members2;
258 }
259 "ms-Mcs-AdmPwd" => {
261 info!(
264 "Your user can read LAPS password on {}: {}",
265 &result_attrs["name"][0].yellow().bold(),
266 &result_attrs["ms-Mcs-AdmPwd"][0].yellow().bold()
267 );
268 self.properties.haslaps = true;
269 }
270 "ms-Mcs-AdmPwdExpirationTime" => {
271 self.properties.haslaps = true;
273 }
274 "msLAPS-Password" => {
276 info!(
277 "Your user can read LAPS password on {}: {:?}",
278 &result_attrs["name"][0].yellow().bold(),
279 &value[0].yellow().bold()
280 );
281 self.properties.haslaps = true;
282 }
283 "msLAPS-EncryptedPassword" => {
284 info!(
285 "Your user can read uncrypted LAPS password on {} please check manually to decrypt it!",
286 &result_attrs["name"][0].yellow().bold()
287 );
288 self.properties.haslaps = true;
289 }
290 "msLAPS-PasswordExpirationTime" => {
291 self.properties.haslaps = true;
293 }
294 "primaryGroupID" => {
295 group_id = value[0].to_owned();
296 }
297 "IsDeleted" => {
298 self.is_deleted = true;
299 }
300 "msDS-SupportedEncryptionTypes" => {
301 self.properties.supportedencryptiontypes = convert_encryption_types(value[0].parse::<i32>().unwrap_or(0));
302 }
303 _ => {}
304 }
305 }
306
307 for (key, value) in &result_bin {
309 match key.as_str() {
310 "objectSid" => {
311 sid = sid_maker(LdapSid::parse(&value[0]).unwrap().1, domain);
313 self.object_identifier = sid.to_owned();
314
315 for domain_sid in OBJECT_SID_RE1.captures_iter(&sid) {
316 self.properties.domainsid = domain_sid[0].to_owned().to_string();
317 }
318 }
319 "nTSecurityDescriptor" => {
320 let relations_ace = parse_ntsecuritydescriptor(
322 &mut computer,
323 &value[0],
324 "Computer",
325 &result_attrs,
326 &result_bin,
327 domain,
328 schema_guid_map,
329 );
330 self.aces = relations_ace;
331 }
332 "msDS-AllowedToActOnBehalfOfOtherIdentity" => {
333 let relations_ace = parse_ntsecuritydescriptor(
336 &mut computer,
337 &value[0],
338 "Computer",
339 &result_attrs,
340 &result_bin,
341 domain,
342 schema_guid_map,
343 );
344 let mut vec_members_allowtoact: Vec<Member> = Vec::new();
345 let mut allowed_to_act = Member::new();
346 for delegated in relations_ace {
347 if *delegated.right_name() == "GenericAll" {
350 *allowed_to_act.object_identifier_mut() = delegated.principal_sid().to_string();
351 vec_members_allowtoact.push(allowed_to_act.to_owned());
352 continue
353 }
354 }
355 self.allowed_to_act = vec_members_allowtoact;
356 }
357 _ => {}
358 }
359 }
360
361 #[allow(irrefutable_let_patterns)]
363 if let id = group_id {
364 if let Some(part1) = SID_PART1_RE1.find(&sid) {
365 self.primary_group_sid = format!("{}{}", part1.as_str(), id);
366 } else {
367 eprintln!("[!] Regex did not match any part of the SID");
368 }
369 }
370
371 dn_sid.insert(
373 self.properties.distinguishedname.to_string(),
374 self.object_identifier.to_string(),
375
376 );
377 sid_type.insert(
379 self.object_identifier.to_string(),
380 "Computer".to_string(),
381 );
382
383 fqdn_sid.insert(
384 self.properties.name.to_string(),
385 self.object_identifier.to_string(),
386 );
387
388 fqdn_ip.insert(
389 self.properties.name.to_string(),
390 String::from(""),
391 );
392
393 Ok(())
396 }
397}
398
399impl LdapObject for Computer {
400 fn to_json(&self) -> Value {
402 serde_json::to_value(self).unwrap()
403 }
404
405 fn get_object_identifier(&self) -> &String {
407 &self.object_identifier
408 }
409 fn get_is_acl_protected(&self) -> &bool {
410 &self.is_acl_protected
411 }
412 fn get_aces(&self) -> &Vec<AceTemplate> {
413 &self.aces
414 }
415 fn get_spntargets(&self) -> &Vec<SPNTarget> {
416 panic!("Not used by current object.");
417 }
418 fn get_allowed_to_delegate(&self) -> &Vec<Member> {
419 &self.allowed_to_delegate
420 }
421 fn get_links(&self) -> &Vec<Link> {
422 panic!("Not used by current object.");
423 }
424 fn get_contained_by(&self) -> &Option<Member> {
425 &self.contained_by
426 }
427 fn get_child_objects(&self) -> &Vec<Member> {
428 panic!("Not used by current object.");
429 }
430 fn get_haslaps(&self) -> &bool {
431 &self.properties.haslaps
432 }
433
434 fn get_aces_mut(&mut self) -> &mut Vec<AceTemplate> {
436 &mut self.aces
437 }
438 fn get_spntargets_mut(&mut self) -> &mut Vec<SPNTarget> {
439 panic!("Not used by current object.");
440 }
441 fn get_allowed_to_delegate_mut(&mut self) -> &mut Vec<Member> {
442 &mut self.allowed_to_delegate
443 }
444
445 fn set_is_acl_protected(&mut self, is_acl_protected: bool) {
447 self.is_acl_protected = is_acl_protected;
448 self.properties.isaclprotected = is_acl_protected;
449 }
450 fn set_aces(&mut self, aces: Vec<AceTemplate>) {
451 self.aces = aces;
452 }
453 fn set_spntargets(&mut self, _spn_targets: Vec<SPNTarget>) {
454 }
456 fn set_allowed_to_delegate(&mut self, allowed_to_delegate: Vec<Member>) {
457 self.allowed_to_delegate = allowed_to_delegate;
458 }
459 fn set_links(&mut self, _links: Vec<Link>) {
460 }
462 fn set_contained_by(&mut self, contained_by: Option<Member>) {
463 self.contained_by = contained_by;
464 }
465 fn set_child_objects(&mut self, _child_objects: Vec<Member>) {
466 }
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize, Default)]
472pub struct ComputerProperties {
473 domain: String,
474 name: String,
475 distinguishedname: String,
476 domainsid: String,
477 isaclprotected: bool,
478 highvalue: bool,
479 samaccountname: String,
480 haslaps: bool,
481 description: Option<String>,
482 whencreated: i64,
483 enabled: bool,
484 unconstraineddelegation: bool,
485 trustedtoauth: bool,
486 lastlogon: i64,
487 lastlogontimestamp: i64,
488 pwdlastset: i64,
489 passwordnotreqd: bool,
490 pwdneverexpires: bool,
491 serviceprincipalnames: Vec<String>,
492 operatingsystem: String,
493 sidhistory: Vec<String>,
494 supportedencryptiontypes: Vec<String>,
495 #[serde(skip_serializing)]
496 is_dc: bool
497}
498
499impl ComputerProperties {
500 pub fn name(&self) -> &String {
502 &self.name
503 }
504 pub fn unconstraineddelegation(&self) -> &bool {
505 &self.unconstraineddelegation
506 }
507 pub fn enabled(&self) -> &bool {
508 &self.enabled
509 }
510 pub fn get_is_dc(&self) -> &bool {
511 &self.is_dc
512 }
513}