
Protocolli di rilevamento dell'ora di Active Directory per red team. Estrazione furtiva tramite Kerberos, SMB, NTLM e CLDAP.

skewrun è un toolkit per la scoperta del tempo di Active Directory per red team. Risolve dinamicamente l'ora del Domain Controller tramite protocolli di rete (CLDAP, SMB, NTP, Kerberos, NTLM) ed esegue comandi tramite libfaketime (LD_PRELOAD), ingannando il binario eseguito facendogli usare l'ora esatta del DC.
Ciò risolve l'errore Kerberos KRB_AP_ERR_SKEW (Clock Skew Too Great), permettendoti di eseguire strumenti come Impacket o NetExec da una macchina di attacco Linux il cui orologio è fortemente desincronizzato dal dominio Windows di destinazione, senza richiedere privilegi di root per modificare l'ora di sistema.
A partire da v0.9.0, Skewrun è costruito con un'architettura library-first:
ad-time: Una libreria puramente Rust che estrae l'ora dai protocolli AD in modo furtivo. Può essere incorporata nativamente in altri implant o strumenti Rust.skewrun: Un binario CLI che orchestra la libreria ad-time e avvolge i processi target con libfaketime.# 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
Nota: Devi avere libfaketime installato sul sistema (es., 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(())
}
Ogni modulo di protocollo (kerberos, ntlm, cldap, smb, ntp) è indipendente ed estraibile per essere utilizzato in strumenti red team personalizzati.
Skewrun interroga il DC per calcolare l'offset esatto in microsecondi (DC_Time - Local_Time). Imposta quindi la variabile d'ambiente FAKETIME e inietta libfaketime nel comando target usando LD_PRELOAD.
LD_PRELOAD si basa sull'intercettazione delle chiamate libc collegate dinamicamente (come clock_gettime). Se tenti di usare skewrun su un binario compilato staticamente (come molti strumenti Go o Rust), libfaketime non riuscirà silenziosamente a fare hook delle funzioni temporali. Skewrun ti avviserà se rileva che stai tentando di eseguire un binario statico.
L'obiettivo è mimetizzarsi con il traffico standard di rete Windows e ridurre al minimo l'impronta forense sul DC.
Indipendentemente dal metodo utilizzato: ogni socket in uscita imposta TTL=128 e abilita Nagle (TCP_NODELAY=0) prima dell'handshake TCP, corrispondendo all'impronta dello stack di rete di un client Windows invece dei predefiniti Linux (TTL=64, Nagle disattivato) che un osservatore passivo (p0f, Zeek conn.log) altrimenti segnalerebbe. I ritardi tra i metodi utilizzano jitter log-normale basato su CSPRNG (non un intervallo casuale piatto) con backoff esponenziale su fallimenti ripetuti, evitando la firma di temporizzazione uniforme che una banda di jitter fissa lascia nei log di connessione — vedi --jitter-sigma e --jitter-base-ms sopra.
cargo test # unit + property tests
cargo +nightly fuzz run fuzz_parse_krb_error # Linux/macOS only
Tutti i parser esposti alla rete (parse_krb_error, parse_cldap_search_response, parse_ntlm_type2,
parse_negotiate_response, parse_ntp_timestamp) sono testati per sicurezza contro il panico tramite
proptest e testati con fuzzing in CI.
La codifica BER è verificata per minimalità e correttezza del segno in tutto l'intervallo i32,
coprendo valori etype negativi secondo RFC 4120.
I target di fuzzing e il corpus si trovano in fuzz/.
Dual-licensed under MIT or Apache 2.0 at your option.
| Metodo | Protocollo | Porta | Note OPSEC (Visibilità EDR/NDR) |
|---|
| cldap (Predefinito) | CLDAP | UDP/389 | Estremamente furtivo. Universalmente consentito. Invia una query diagnostica LDAP rootDSE standard (ricerca base objectClass=*), corrispondente alla baseline di ldapsearch, cmdlet PowerShell AD e strumenti di monitoraggio. Diluisce l'elenco degli attributi con attributi amministrativi comuni e randomizza l'ordine degli attributi per richiesta per rompere le firme NDR statiche. |
| smb (Predefinito) | SMB2 | TCP/445 | Furtivo. Estrae l'ora dalla risposta SMB2 NEGOTIATE. Negoziato SMB 3.1.1 con PREAUTH_INTEGRITY_CAPABILITIES (SHA-512), corrispondente al comportamento del client Windows 10/11. |
| ntp (Predefinito) | SNTP | UDP/123 | Standard. RFC 4330 nativo. Traffico altamente previsto da qualsiasi client. |
| ntlm | SMB2 | TCP/445 | Furtivo. Sfrutta SMB2 SESSION_SETUP per ottenere una sfida NTLM Type 2 contenente MsvAvTimestamp. Disconnette TCP prima del Type 3, il che significa che non viene generato nessun Event ID 4625 (Logon Failure). Emula i flag di Windows 10/11. |
| kerberos | Kerberos | TCP/88 | Rumoroso. Invia una AS-REQ per un utente inesistente. Codifica il corretto sname a due componenti, ruota cname (refusi come admnistrator), imposta till sulla costante fissa di Windows 20370913024805Z (non aritmetica dell'orologio locale — vedi ADR-0002), randomizza nonce. Genera sempre Event 4768/0x6 (errore di pre-autenticazione per principal sconosciuto) che viene esportato nel SIEM indipendentemente dalla politica di audit. Potrebbe attivare alert di account esca se cname corrisponde a un tripwire configurato. |