
skewrun v1.2.0
Active Directory 时间发现协议,供红队使用。通过 Kerberos、SMB、NTLM 和 CLDAP 进行隐秘提取。
Skewrun

skewrun 是一个用于红队的Active Directory时间发现工具包。它通过网络协议(CLDAP、SMB、NTP、Kerberos、NTLM)动态解析域控制器的时间,并通过 libfaketime(LD_PRELOAD)执行命令,欺骗被执行的二进制文件使用精确的DC时间。
这解决了Kerberos KRB_AP_ERR_SKEW(时钟偏移过大)错误,允许你从时钟与目标Windows域严重不同步的Linux攻击机上运行像Impacket或NetExec这样的工具,而无需root权限更改系统时间。
架构:库优先
从v0.9.0开始,Skewrun采用库优先架构构建:
ad-time:一个纯Rust库crate,可隐蔽地从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 环境变量,并使用 LD_PRELOAD 将 libfaketime 注入到目标命令中。
FAKETIME 限制(静态二进制文件)
LD_PRELOAD 依赖于拦截动态链接的 libc 调用(如 clock_gettime)。如果你尝试在静态编译的二进制文件(例如许多Go或Rust工具)上使用 skewrun,libfaketime 将静默失败,无法挂钩时间函数。如果检测到你正在尝试运行一个静态二进制文件,Skewrun 会发出警告。
取证噪音与规避
目标是融入标准的Windows网络流量,并最小化在DC上的取证痕迹。
无论使用哪种方法:每个出站套接字在TCP握手之前设置TTL=128并启用Nagle(TCP_NODELAY=0),匹配Windows客户端的网络栈指纹,而不是Linux默认值(TTL=64,禁用Nagle),否则被动观察者(p0f、Zeek conn.log)会标记。方法之间的延迟使用CSPRNG支持的对数正态抖动(不是平坦随机范围),并在重复失败时使用指数退避,避免了固定抖动带在连接日志中留下的均匀时间签名——参见上面的 --jitter-sigma 和 --jitter-base-ms。
| 方法 | 协议 | 端口 | OPSEC 说明(EDR/NDR 可见性) |
|---|---|---|---|
| cldap(默认) | CLDAP | UDP/389 | 极其隐蔽。普遍允许。发送标准的LDAP rootDSE 诊断查询(objectClass=* 基础搜索),与 ldapsearch、PowerShell AD cmdlet 和监控工具的基线匹配。用常见的管理员属性稀释属性列表,并随机化每个请求的属性顺序,以打破静态NDR签名。 |
| smb(默认) | SMB2 | TCP/445 | 隐蔽。从 SMB2 NEGOTIATE 响应中提取时间。与 PREAUTH_INTEGRITY_CAPABILITIES(SHA-512)协商SMB 3.1.1,匹配Windows 10/11客户端行为。 |
| ntp(默认) | SNTP | UDP/123 | 标准。原生RFC 4330。任何客户端的高度预期流量。 |
| ntlm | SMB2 | TCP/445 | 隐蔽。利用 SMB2 SESSION_SETUP 获取包含 MsvAvTimestamp 的NTLM Type 2挑战。在Type 3之前断开TCP,意味着不会生成事件ID 4625(登录失败)。模拟Windows 10/11标志。 |
| kerberos | Kerberos | TCP/88 | 嘈杂。为不存在的用户发送 AS-REQ。编码正确的双组件 sname,轮换 cname(如 admnistrator 的拼写错误),将 till 设置为Windows硬编码常量 20370913024805Z(非本地时钟算术——参见ADR-0002),随机化 nonce。总是生成事件4768/0x6(未知主体的预认证失败),无论审计策略如何都会被导出到SIEM。如果 cname 匹配已配置的蜜罐警告,可能触发蜜罐账户警报。 |
测试
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)都使用 proptest 进行了 panic 安全性的属性测试,并在CI中进行了模糊测试。BER整数编码在整个 i32 范围内验证了DER最小性和符号正确性,覆盖了RFC 4120规定的负etype值。模糊测试目标和语料库位于 fuzz/。
许可证
双许可,可选 MIT 或 Apache 2.0。