
Протоколы обнаружения времени Active Directory для red teams. Скрытое извлечение через Kerberos, SMB, NTLM и CLDAP.

skewrun — это набор инструментов для обнаружения времени Active Directory для красных команд. Он динамически определяет время контроллера домена с помощью сетевых протоколов (CLDAP, SMB, NTP, Kerberos, NTLM) и выполняет команды через libfaketime (LD_PRELOAD), заставляя выполняемый бинарник использовать точное время DC.
Это решает ошибку Kerberos KRB_AP_ERR_SKEW (Clock Skew Too Great), позволяя запускать такие инструменты, как Impacket или NetExec, с атакующей машины Linux, часы которой сильно рассинхронизированы с целевым доменом Windows, без необходимости прав root для изменения системного времени.
Начиная с v0.9.0, Skewrun построен на архитектуре, ориентированной на библиотеку:
ad-time: Чистая библиотека на Rust, которая незаметно извлекает время из протоколов AD. Она может быть нативно встроена в другие импланты или инструменты на Rust.skewrun: CLI-бинарник, который оркестрирует библиотеку ad-time и оборачивает целевые процессы с помощью 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
Примечание: На вашей системе должен быть установлен libfaketime (например, 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(())
}
Каждый модуль протокола (kerberos, ntlm, cldap, smb, ntp) независим и может быть извлечен для использования в пользовательских инструментах красных команд.
Skewrun опрашивает DC для вычисления точного микросекундного смещения (DC_Time - Local_Time). Затем он устанавливает переменную окружения FAKETIME и внедряет libfaketime в целевую команду с помощью LD_PRELOAD.
LD_PRELOAD полагается на перехват динамически связываемых вызовов libc (например, clock_gettime). Если вы попытаетесь использовать skewrun на статически скомпилированном бинарнике (например, многих инструментах на Go или Rust), libfaketime молча не сможет перехватить функции времени. Skewrun предупредит вас, если обнаружит, что вы пытаетесь запустить статический бинарник.
Цель — слиться со стандартным сетевым трафиком Windows и минимизировать форензический след на DC.
Независимо от используемого метода: каждый исходящий сокет устанавливает TTL=128 и включает Nagle (TCP_NODELAY=0) до рукопожатия TCP, соответствуя отпечатку сетевого стека клиента Windows вместо стандартных для Linux (TTL=64, Nagle выключен), которые в противном случае были бы отмечены пассивным наблюдателем (p0f, Zeek conn.log). Задержки между методами используют логнормальный джиттер на основе CSPRNG (не плоский случайный диапазон) с экспоненциальной задержкой при повторных сбоях, избегая равномерной временной сигнатуры, которую фиксированный диапазон джиттера оставляет в журналах соединений — см. --jitter-sigma и --jitter-base-ms выше.
cargo test # unit + property tests
cargo +nightly fuzz run fuzz_parse_krb_error # Linux/macOS only
Все парсеры, работающие с сетью (parse_krb_error, parse_cldap_search_response, parse_ntlm_type2, parse_negotiate_response, parse_ntp_timestamp) проходят property-тестирование на безопасность паники с помощью proptest и fuzz-тестирование в CI. Кодирование целых чисел BER проверяется на минимальность DER и корректность знака во всем диапазоне i32, включая отрицательные значения etype согласно RFC 4120. Цели для фаззинга и корпус находятся в fuzz/.
Двойная лицензия: MIT или Apache 2.0 на ваш выбор.
| Метод | Протокол | Порт | Заметки по OPSEC (Видимость EDR/NDR) |
|---|
| cldap (По умолчанию) | CLDAP | UDP/389 | Чрезвычайно скрытный. Повсеместно разрешен. Отправляет стандартный диагностический запрос LDAP rootDSE (базовый поиск objectClass=*), что соответствует поведению ldapsearch, командлетов AD PowerShell и инструментов мониторинга. Разбавляет список атрибутов общими административными атрибутами и рандомизирует порядок атрибутов в каждом запросе, чтобы сломать статические сигнатуры NDR. |
| smb (По умолчанию) | SMB2 | TCP/445 | Скрытный. Извлекает время из ответа SMB2 NEGOTIATE. Согласовывает SMB 3.1.1 с PREAUTH_INTEGRITY_CAPABILITIES (SHA-512), что соответствует поведению клиента Windows 10/11. |
| ntp (По умолчанию) | SNTP | UDP/123 | Стандартный. Нативный RFC 4330. Очень ожидаемый трафик от любого клиента. |
| ntlm | SMB2 | TCP/445 | Скрытный. Использует SMB2 SESSION_SETUP для получения NTLM Type 2 Challenge, содержащего MsvAvTimestamp. Разрывает TCP до Type 3, то есть не генерируется Event ID 4625 (Сбой входа). Эмулирует флаги Windows 10/11. |
| kerberos | Kerberos | TCP/88 | Шумный. Отправляет AS-REQ для несуществующего пользователя. Кодирует корректный двухкомпонентный sname, вращает cname (опечатки типа admnistrator), устанавливает till в жестко заданную константу Windows 20370913024805Z (не локальная арифметика часов — см. ADR-0002), рандомизирует nonce. Всегда генерирует Event 4768/0x6 (сбой предварительной аутентификации для неизвестного субъекта), который экспортируется в SIEM независимо от политики аудита. Может вызывать оповещения о приманках, если cname соответствует настроенной ловушке. |