rusthound_ce/modules/
mod.rs1pub mod adcs;
3pub mod gpo;
4pub mod resolver;
5pub mod session;
6pub mod localgroup;
7
8use std::error::Error;
9
10use futures::future;
11
12use crate::api::ADResults;
13use crate::args::{CollectionMethod, Options};
14use crate::modules::adcs::probe_enterpriseca_esc8;
15use crate::modules::gpo::sysvol::collect_sysvol_targets;
16
17pub async fn run_modules(
19 common_args: &Options,
20 ad: &mut ADResults
21) -> Result<(), Box<dyn Error>> {
22
23 let cert_auth = common_args.uses_cert();
24 if cert_auth {
25 log::warn!("Certificate authentication in use: skipping SMB-based modules \
26 (sessions and GPO/SYSVOL) no SMB credentials available.");
27 }
28
29 if common_args.fqdn_resolver {
31 resolver::resolv::resolving_all_fqdn(
32 common_args.dns_tcp,
33 &common_args.name_server,
34 &mut ad.mappings.fqdn_ip,
35 &ad.computers,
36 )
37 .await;
38 }
39
40 if common_args.collection_method.does_session() && !cert_auth {
47 session::run(common_args, &ad.users, &mut ad.computers).await?;
48 }
49
50 if !matches!(common_args.collection_method, CollectionMethod::DCOnly)
59 && !matches!(common_args.collection_method, CollectionMethod::LdapOnly)
60 && !ad.enterprisecas.is_empty()
61 {
62 log::info!(
63 "Starting ESC8 web enrollment probe on {} CA(s)...",
64 ad.enterprisecas.len()
65 );
66 let targets: Vec<(String, String)> = ad
67 .enterprisecas
68 .iter()
69 .map(|ca| (ca.dns_host().to_string(), ca.caname().to_string()))
70 .collect();
71 let probes = future::join_all(targets.into_iter().map(|(host, ca_name)| {
72 tokio::task::spawn_blocking(move || probe_enterpriseca_esc8(&host, &ca_name))
73 }))
74 .await;
75 for (ca, probe) in ad.enterprisecas.iter_mut().zip(probes) {
76 match probe {
77 Ok(esc8) => ca.apply_esc8(esc8.http_enrollment_endpoints),
78 Err(join_err) => log::warn!(
79 "[adcs] ESC8 probe task for {} did not complete ({}), skipping",
80 ca.dns_host(),
81 join_err
82 ),
83 }
84 }
85 }
86
87 if common_args.collection_method.does_gpo() && !cert_auth {
90 let computer_scope = gpo::sysvol::ComputerGpoScope::from_gpos(&ad.gpos);
91 let sysvol = match collect_sysvol_targets(common_args, &computer_scope).await {
92 Ok(v) => v,
93 Err(e) => {
94 log::warn!("[gpo] SYSVOL collection failed: {e}");
95 Vec::new()
96 }
97 };
98 if !sysvol.is_empty() {
99 log::info!(
100 "[gpo] mapping {} GPO(s) to GPOChanges / UserRights",
101 sysvol.len()
102 );
103 gpo::apply_gpo(
104 &mut ad.ous,
105 &mut ad.domains,
106 &ad.users,
107 &ad.groups,
108 &mut ad.computers,
109 &sysvol,
110 &ad.mappings.dn_sid,
111 &common_args.domain
112 );
113 }
114 }
115
116 if common_args.collection_method.does_local_group() && !cert_auth {
124 localgroup::run(common_args, &ad.users, &mut ad.computers, &ad.mappings.sid_type).await?;
125 }
126
127 Ok(())
129}