01、简介
针对域用户密码攻击,攻击者通常都会使用两种攻击方式进行测试,即:暴力破解(Brute Force)和密码喷洒(Password Spraying)。
暴力破解(Brute Force)攻击,攻击者通过利用大量猜测和穷举的方式来尝试获取用户口令的攻击方式。
密码喷洒(Password Spraying)攻击,针对不同的用户账户使用一两个通用密码进行自动化密码猜测,以此来避免单个账户连续密码猜测被锁定,提高密码猜测的成功率。
暴力破解与密码喷洒的区别在于,暴力破解(Brute Force)攻击是固定用户名,快速检查大量密码进行匹配。而密码喷洒(Password Spraying)攻击则是固定密码,遍历用户名进行验证。
02、攻击过程
在Windows中,最常见的两种认证体系便是NTLM认证和Kerberos认证,针对登录认证过程中产生的日志进行分析,制定对应的检测规则。
(1)基于NTLM认证进行暴力破解
NTLM是一种网络认证协议,支持多种协议,例如:SMB、LDAP、HTTP等。AD域本身就是LDAP的一个应用实例,这里我们通过LDAP服务爆破域用户密码。
域用户暴力破解(Brute Force)攻击示例:
Windows安全日志:
开启审核策略,Windows安全日志会产生相应的审核日志,帐户登录失败,事件ID为2625,账户登录成功,事件ID为4624。
事件ID:4625 登录失败,日志里包含尝试登录的账号名称和域、登录类型和登录进程、登录的计算机名和登录IP地址。
事件ID:4624 登录成功,包括登录的用户名和域、登录类型、登录进程、身份验证包、登录的计算机名和登录IP地址。
(2)基于Kerberos预身份验证进行密码喷洒
Kerberos相比于NTLM而言,Kerberos的认证过程会相对复杂一些。
域用户密码喷洒(Password Spraying)攻击示例:
smartbrute.py brute -bU user.txt -bp abc123! kerberos -d evil.com
Windows安全日志:
开启审核策略,Windows安全日志会产生Kerberos身份验证服务的日志,
事件ID:4768,每次密钥分发中心颁发 Kerberos 票证授予票证 (TGT) 时,都会生成此事件,如果 TGT 问题失败,则会看到“ 结果代码 ”字段不等于“0x0”的失败事件。事件ID为4668表示已请求 Kerberos 身份验证票证 (TGT),事件ID为4771表示Kerberos 预身份验证失败。
域用户不存在,会产生一条事件ID为4768(审核失败)的日志记录。
域用户存在,密码错误,会产生一条事件ID为4771(审核失败)的日志记录。
域用户存在,密码正确,会产生两条事件ID为4768(审核成功),一条事件ID为4769(审核成功)的日志记录
03、攻击检测
通过模拟环境产生攻击事件,以攻击日志构建规则,提取关键特征,实时检测攻击行为。
(1)暴力破解(Brute Force)检测策略:在五分钟内,单一用户的密码登录失败次数超过10
index=ad EventCode=4624 OR EventCode=4625 bypass | bucket _time span=5m | stats min(_time) as start_time max(_time) as end_time count(eval('EventCode'==4625)) as count_failure count(eval('EventCode'==4624)) as count_success values(dest) as dest by match_user src| nomv dest| eval start_time=strftime(start_time,"%Y-%m-%d %H:%M:%S") | eval end_time=strftime(end_time,"%Y-%m-%d %H:%M:%S")|search count_failure>10 count_success>=0| eval message="在"+start_time+"到"+end_time+"时间段内,IP:"+src+ " User:"+match_user+"对内部地址( "+dest+" )进行暴力破解,失败:"+count_failure+" 次,成功:"+count_success+" 次" | table start_time end_time src dest match_user message
(2)密码喷洒(Password Spraying)检测策略:在五分钟内,单一来源IP认证失败错误超过50
index=ad EventCode=4771 host=WIN-DC01 user!="*$" | bucket _time span=5m | stats min(_time) as start_time max(_time) as end_time count values(user) as user by Client_Address dest | nomv user | eval start_time=strftime(start_time,"%Y-%m-%d %H:%M:%S") | eval end_time=strftime(end_time,"%Y-%m-%d %H:%M:%S")|search count>=0| eval message="在"+start_time+"到"+end_time+"时间段内,IP地址:"+Client_Address+ "对以下账号:"+user+"进行密码喷洒,认证失败:"+count+"次" | table start_time end_time dest user message