
Protocoles de découverte temporelle Active Directory pour les red teams. Extraction furtive via Kerberos, SMB, NTLM et CLDAP.

skewrun est une boîte à outils de découverte temporelle Active Directory pour les red teams. Elle résout dynamiquement l'heure du contrôleur de domaine via des protocoles réseau (CLDAP, SMB, NTP, Kerberos, NTLM) et exécute des commandes via libfaketime (LD_PRELOAD), trompant le binaire exécuté pour qu'il utilise l'heure exacte du DC.
Cela résout l'erreur Kerberos KRB_AP_ERR_SKEW (Écart d'horloge trop grand), vous permettant d'exécuter des outils comme Impacket ou NetExec depuis une machine d'attaque Linux dont l'horloge est fortement désynchronisée du domaine Windows cible, sans nécessiter de privilèges root pour modifier l'heure système.
Depuis la v0.9.0, Skewrun est conçu avec une architecture orientée bibliothèque :
ad-time : Une crate de bibliothèque Rust pure qui extrait l'heure des protocoles AD de manière furtive. Elle peut être intégrée nativement dans d'autres implants ou outils Rust.skewrun : Un binaire CLI qui orchestre la bibliothèque ad-time et encapsule les processus cibles avec libfaketime.# Binaire statique précompilé (pas besoin de l'environnement Rust)
wget https://github.com/JVBotelho/skewrun/releases/latest/download/skewrun-x86_64-linux-musl
chmod +x skewrun-x86_64-linux-musl
sudo mv skewrun-x86_64-linux-musl /usr/local/bin/skewrun
# Depuis crates.io
cargo install skewrun
# Depuis les sources
git clone https://github.com/JVBotelho/skewrun && cd skewrun && cargo build --release
Remarque : Vous devez avoir libfaketime installé sur votre système (par exemple, apt-get install libfaketime).
# Comportement par défaut (essaie CLDAP -> SMB -> NTP)
skewrun 10.10.10.100 -- impacket-getTGT -dc-ip 10.10.10.100 domain.local/user:pass
# Forcer des méthodes spécifiques
skewrun 10.10.10.100 -m cldap,ntlm,kerberos -- netexec smb 10.10.10.100
# Afficher uniquement le décalage (utile pour les scripts shell)
skewrun 10.10.10.100 --print-offset
# Mode hors ligne : fournir un décalage connu manuellement
skewrun --offset "+3.450s" -- impacket-getTGT ...
# Régler la gigue inter-méthodes (par défaut : sigma=0.4, base=8000ms ; sigma=0 désactive la gigue)
skewrun 10.10.10.100 --jitter-sigma 0.2 --jitter-base-ms 5000 -- impacket-getTGT ...
use ad_time::protocols::cldap::CldapSource;
use ad_time::time_src::TimeSource;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let src = CldapSource;
let addr = "10.10.10.100:389".parse()?;
let offset_us = src.fetch(addr, Duration::from_secs(3))?;
println!("Décalage DC : {} µs", offset_us);
Ok(())
}
Chaque module de protocole (kerberos, ntlm, cldap, smb, ntp) est indépendant et extractible pour être utilisé dans des outils de red team personnalisés.
Skewrun interroge le DC pour calculer le décalage exact en microsecondes (Heure_DC - Heure_Locale). Il définit ensuite la variable d'environnement FAKETIME et injecte libfaketime dans la commande cible via LD_PRELOAD.
LD_PRELOAD repose sur l'interception des appels libc liés dynamiquement (comme clock_gettime). Si vous essayez d'utiliser skewrun sur un binaire compilé statiquement (comme de nombreux outils Go ou Rust), libfaketime ne pourra pas accrocher les fonctions temporelles. Skewrun vous avertira s'il détecte que vous tentez d'exécuter un binaire statique.
L'objectif est de se fondre dans le trafic réseau standard de Windows et de minimiser l'empreinte forensique sur le DC.
Indépendamment de la méthode utilisée : chaque socket sortant définit TTL=128 et active Nagle (TCP_NODELAY=0) avant la poignée de main TCP, correspondant à l'empreinte de la pile réseau d'un client Windows au lieu des valeurs par défaut Linux (TTL=64, Nagle désactivé) qu'un observateur passif (p0f, Zeek conn.log) signalerait autrement. Les délais entre les méthodes utilisent une gigue log-normale basée sur CSPRNG (pas une plage aléatoire uniforme) avec un backoff exponentiel en cas d'échecs répétés, évitant la signature de temporisation uniforme qu'une bande de gigue fixe laisse dans les journaux de connexion — voir --jitter-sigma et --jitter-base-ms ci-dessus.
cargo test # tests unitaires + de propriétés
cargo +nightly fuzz run fuzz_parse_krb_error # Linux/macOS uniquement
Tous les analyseurs réseau (parse_krb_error, parse_cldap_search_response, parse_ntlm_type2, parse_negotiate_response, parse_ntp_timestamp) sont testés pour la sécurité contre les paniques via proptest et soumis à des tests de fuzzing dans l'IC. L'encodage BER des entiers est vérifié pour la minimalité DER et la correction du signe sur toute la plage i32, couvrant les valeurs négatives d'etype selon la RFC 4120. Les cibles de fuzzing et les corpus se trouvent dans fuzz/.
Sous double licence MIT ou Apache 2.0 à votre choix.
| Méthode | Protocole | Port | Notes OPSEC (Visibilité EDR/NDR) |
|---|
| cldap (Par défaut) | CLDAP | UDP/389 | Extrêmement furtive. Autorisée universellement. Envoie une requête de diagnostic LDAP rootDSE standard (objectClass=*), correspondant à la ligne de base de ldapsearch, des cmdlets PowerShell AD et des outils de surveillance. Dilue la liste d'attributs avec des attributs d'administration courants et randomise l'ordre des attributs par requête pour briser les signatures NDR statiques. |
| smb (Par défaut) | SMB2 | TCP/445 | Furtive. Extrait l'heure de la réponse SMB2 NEGOTIATE. Négocie SMB 3.1.1 avec PREAUTH_INTEGRITY_CAPABILITIES (SHA-512), correspondant au comportement des clients Windows 10/11. |
| ntp (Par défaut) | SNTP | UDP/123 | Standard. RFC 4330 native. Trafic très attendu de la part de tout client. |
| ntlm | SMB2 | TCP/445 | Furtive. Exploite SMB2 SESSION_SETUP pour obtenir un challenge NTLM Type 2 contenant MsvAvTimestamp. Déconnecte TCP avant le Type 3, ce qui signifie aucun Event ID 4625 (Échec de connexion) n'est généré. Émule les indicateurs Windows 10/11. |
| kerberos | Kerberos | TCP/88 | Bruyante. Envoie un AS-REQ pour un utilisateur inexistant. Encode un sname à deux composants correct, fait varier le cname (fautes de frappe comme admnistrator), définit till sur la constante fixe Windows 20370913024805Z (pas d'arithmétique d'horloge locale — voir ADR-0002), randomise le nonce. Génère toujours un événement 4768/0x6 (échec de pré-authentification pour un principal inconnu) qui est exporté vers le SIEM indépendamment de la politique d'audit. Peut déclencher des alertes de comptes leurres si le cname correspond à un tripwire configuré. |