Skip to main content

rusthound_ce/modules/
mod.rs

1//! List of RustHound add-on modules
2pub mod adcs;
3pub mod gpo;
4pub mod resolver;
5pub mod sessions;
6
7use std::error::Error;
8
9use rayon::prelude::*;
10
11use crate::api::ADResults;
12use crate::args::{CollectionMethod, Options};
13use crate::modules::adcs::probe_enterpriseca_esc8;
14use crate::modules::gpo::sysvol::collect_sysvol_targets;
15
16/// Function to run all modules requested
17pub async fn run_modules(common_args: &Options, ad: &mut ADResults) -> Result<(), Box<dyn Error>> {
18    // [MODULE - RESOLVER] Resolve FQDN to IP address.
19    if common_args.fqdn_resolver {
20        resolver::resolv::resolving_all_fqdn(
21            common_args.dns_tcp,
22            &common_args.name_server,
23            &mut ad.mappings.fqdn_ip,
24            &ad.computers,
25        )
26        .await;
27    }
28
29    // [MODULE - SESSIONS] Just does user session collection
30    // <https://github.com/g0h4n/HasSession-rs>
31    //
32    // - SRVSVC / NetrSessionEnum - inbound SMB sessions (client IP + username).
33    // - WKSSVC / NetrWkstaUserEnum - users with an active logon context on the machine.
34    // - WINREG / HKEY_USERS - SIDs of loaded profile hives (= logged-on users).
35    if common_args.collection_method.does_sessions() {
36        sessions::run(common_args, &ad.users, &mut ad.computers).await?;
37    }
38
39    // [MODULE - ESC8] Web enrollment probe on all enterprise CAs.
40    // Skipped in DCOnly mode (no direct machine connections allowed).
41    // Uses rayon to probe all CAs in parallel (each probe has a 5 s timeout).
42    if !matches!(common_args.collection_method, CollectionMethod::DCOnly)
43        && !matches!(common_args.collection_method, CollectionMethod::LdapOnly)
44        && !ad.enterprisecas.is_empty()
45    {
46        log::info!(
47            "Starting ESC8 web enrollment probe on {} CA(s)...",
48            ad.enterprisecas.len()
49        );
50        ad.enterprisecas.par_iter_mut().for_each(|ca| {
51            let esc8 = probe_enterpriseca_esc8(ca.dns_host());
52            ca.apply_esc8(esc8.http_enrollment_endpoints);
53        });
54    }
55
56    // [MODULE - GPO SYSVOL] read GptTmpl.inf / Groups.xml off the DC SYSVOL share.
57    // <#47 Privileges> and <#56 LocalGroup>. DC-side I/O, so it also runs in DCOnly.
58    if common_args.collection_method.does_gpo() {
59        let computer_scope = gpo::sysvol::ComputerGpoScope::from_gpos(&ad.gpos);
60        let sysvol = match collect_sysvol_targets(common_args, &computer_scope).await {
61            Ok(v) => v,
62            Err(e) => {
63                log::warn!("[gpo] SYSVOL collection failed: {e}");
64                Vec::new()
65            }
66        };
67        if !sysvol.is_empty() {
68            log::info!(
69                "[gpo] mapping {} GPO(s) to GPOChanges / UserRights",
70                sysvol.len()
71            );
72            gpo::apply_gpo(
73                &mut ad.ous,
74                &mut ad.domains,
75                &ad.users,
76                &ad.groups,
77                &mut ad.computers,
78                &sysvol,
79                &ad.mappings.dn_sid,
80            );
81        }
82    }
83
84    // Other modules need to be add here...
85    Ok(())
86}