
Active Directory-Protokolle zur Zeiterkennung für Red Teams. Heimliche Extraktion über Kerberos, SMB, NTLM und CLDAP.

skewrun ist ein Active Directory-Zeiterkennungstoolkit für Red Teams. Es löst die Zeit des Domain-Controllers dynamisch über Netzwerkprotokolle (CLDAP, SMB, NTP, Kerberos, NTLM) auf und führt Befehle über libfaketime (LD_PRELOAD) aus, wodurch das ausgeführte Binary dazu verleitet wird, die exakte DC-Zeit zu verwenden.
Dies löst den Kerberos-Fehler KRB_AP_ERR_SKEW (Clock Skew Too Great), sodass Sie Tools wie Impacket oder NetExec von einem Linux-Angriffsrechner ausführen können, dessen Uhr stark von der Ziel-Windows-Domäne desynchronisiert ist, ohne dass Root-Rechte zum Ändern der Systemzeit erforderlich sind.
Seit v0.9.0 ist Skewrun als Library-First-Architektur aufgebaut:
ad-time: Eine reine Rust-Bibliotheks-Crate, die die Zeit aus AD-Protokollen heimlich extrahiert. Sie kann nativ in andere Rust-Implantate oder -Tools eingebettet werden.skewrun: Ein CLI-Binary, das die ad-time-Bibliothek orchestriert und Zielprozesse mit libfaketime umschließt.# Pre-built static binary (no Rust toolchain required)
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
# From crates.io
cargo install skewrun
# From source
git clone https://github.com/JVBotelho/skewrun && cd skewrun && cargo build --release
Hinweis: Sie müssen libfaketime auf Ihrem System installiert haben (z.B. apt-get install libfaketime).
# Default behavior (tries CLDAP -> SMB -> NTP)
skewrun 10.10.10.100 -- impacket-getTGT -dc-ip 10.10.10.100 domain.local/user:pass
# Force specific methods
skewrun 10.10.10.100 -m cldap,ntlm,kerberos -- netexec smb 10.10.10.100
# Just print the offset (useful for shell scripting)
skewrun 10.10.10.100 --print-offset
# Offline mode: supply a known offset manually
skewrun --offset "+3.450s" -- impacket-getTGT ...
# Tune inter-method jitter (default: sigma=0.4, base=8000ms; sigma=0 disables jitter)
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!("DC offset: {} µs", offset_us);
Ok(())
}
Jedes Protokollmodul (kerberos, ntlm, cldap, smb, ntp) ist unabhängig und kann für den Einsatz in benutzerdefinierten Red-Team-Tools extrahiert werden.
Skewrun fragt den DC ab, um den genauen Mikrosekunden-Offset (DC_Time - Local_Time) zu berechnen. Anschließend setzt es die Umgebungsvariable FAKETIME und injiziert libfaketime mit LD_PRELOAD in den Zielbefehl.
LD_PRELOAD basiert darauf, dynamisch gelinkte libc-Aufrufe (wie clock_gettime) abzufangen. Wenn Sie versuchen, skewrun auf einem statisch kompilierten Binary (wie vielen Go- oder Rust-Tools) zu verwenden, wird libfaketime die Zeitfunktionen stillschweigend nicht hooken. Skewrun wird Sie warnen, wenn es erkennt, dass Sie versuchen, ein statisches Binary auszuführen.
Das Ziel ist es, sich in den standardmäßigen Windows-Wire-Traffic einzufügen und den forensischen Fußabdruck auf dem DC zu minimieren.
Unabhängig von der verwendeten Methode: Jeder ausgehende Socket setzt TTL=128 und aktiviert Nagle (TCP_NODELAY=0) vor dem TCP-Handshake, was dem Netzwerk-Stack-Fingerabdruck eines Windows-Clients entspricht und nicht den Linux-Standardwerten (TTL=64, Nagle aus), die ein passiver Beobachter (p0f, Zeek conn.log) andernfalls markieren würde. Verzögerungen zwischen den Methoden verwenden CSPRNG-gestütztes log-normales Jitter (kein flacher Zufallsbereich) mit exponentiellem Backoff bei wiederholten Fehlern, wodurch die gleichmäßige Timing-Signatur vermieden wird, die ein festes Jitter-Band in Verbindungsprotokollen hinterlässt — siehe --jitter-sigma und --jitter-base-ms oben.
cargo test # unit + property tests
cargo +nightly fuzz run fuzz_parse_krb_error # Linux/macOS only
Alle netzwerkorientierten Parser (parse_krb_error, parse_cldap_search_response, parse_ntlm_type2, parse_negotiate_response, parse_ntp_timestamp) werden mit proptest auf Panik-Sicherheit getestet und in CI fuzz-getestet. Die BER-Integer-Kodierung wird auf DER-Minimalität und Vorzeichenkorrektheit über den gesamten i32-Bereich überprüft, wobei negative etype-Werte gemäß RFC 4120 abgedeckt werden. Fuzz-Targets und Corpus befinden sich in fuzz/.
Dual-lizenziert unter MIT oder Apache 2.0 nach Ihrer Wahl.
| Methode | Protokoll | Port | OPSEC-Notizen (EDR/NDR-Sichtbarkeit) |
|---|
| cldap (Standard) | CLDAP | UDP/389 | Extrem heimlich. Allgemein erlaubt. Sendet eine standardmäßige LDAP-rootDSE-Diagnoseabfrage (objectClass=*-Basissuche), die der Baseline von ldapsearch, PowerShell-AD-Cmdlets und Überwachungstools entspricht. Verdünnt die Attributliste mit gängigen Admin-Attributen und randomisiert die Attributreihenfolge pro Anfrage, um statische NDR-Signaturen zu brechen. |
| smb (Standard) | SMB2 | TCP/445 | Heimlich. Extrahiert die Zeit aus der SMB2 NEGOTIATE-Antwort. Verhandelt SMB 3.1.1 mit PREAUTH_INTEGRITY_CAPABILITIES (SHA-512), was dem Windows 10/11-Clientverhalten entspricht. |
| ntp (Standard) | SNTP | UDP/123 | Standard. Natives RFC 4330. Hoch erwarteter Traffic von jedem Client. |
| ntlm | SMB2 | TCP/445 | Heimlich. Nutzt SMB2 SESSION_SETUP aus, um eine NTLM Type 2 Challenge mit MsvAvTimestamp zu erhalten. Trennt die TCP-Verbindung vor Type 3, sodass keine Ereignis-ID 4625 (Anmeldefehler) generiert wird. Emuliert Windows 10/11-Flags. |
| kerberos | Kerberos | TCP/88 | Laut. Sendet ein AS-REQ für einen nicht existierenden Benutzer. Kodiert einen korrekten zweiteiligen sname, rotiert cname (Tippfehler wie admnistrator), setzt till auf die Windows-hartcodierte Konstante 20370913024805Z (keine lokale Uhrenarithmetik — siehe ADR-0002), randomisiert nonce. Generiert immer Ereignis 4768/0x6 (Pre-Authentifizierungsfehler für unbekannten Principal), das unabhängig von der Überwachungsrichtlinie an SIEM exportiert wird. Kann Honey-Account-Warnungen auslösen, wenn der cname mit einem konfigurierten Tripwire übereinstimmt. |