导语:本文介绍了针对Remote Desktop Protocol,验证口令或者NTLM hash的实现方法,开源代码SharpRDPCheck,分享程序实现NTLM hash登录的细节,最后介绍通过日志检测RDP爆破行为的方法。
0x00 前言
在之前的文章《渗透技巧——Pass the Hash with Remote Desktop(Restricted Admin mode)》介绍了特定条件下(Server需要开启Restricted Admin mode,Client需要支持Restricted Admin mode)Pass the Hash with Remote Desktop的方法,本文将要介绍更为通用的方法(通过NTLM hash登录RDP),分析原理,开源代码,记录细节。
0x01 简介
本文将要介绍以下内容:
· 渗透测试中的需求
· 验证口令或者NTLM hash的实现方法
· C实现代码
· Python实现代码
· C sharp实现代码
0x02 渗透测试中的需求
如果是开发远程桌面服务的客户端,可供选择的方法有很多,例如通过C#调用ActiveX组件AxMSTSCLib。
详细方法可参考:https://www.codeproject.com/Articles/43705/Remote-Desktop-using-C-NET
但是在渗透测试中,我们有以下两个需求:
1.验证口令或者hash
需要满足以下条件:
可以在Windows和Linux系统上运行。
登录方式支持明文口令和NTLM hash。
命令行下使用。
2.远程登录
可以在Windows和Linux系统上运行。
登录方式支持明文口令和NTLM hash。
0x03 验证口令或者hash的实现方法
为了支持NTLM hash登录,需要对协议和加密方式有所了解。
关于RDP协议的参考资料:https://github.com/FreeRDP/FreeRDP/wiki/Reference-Documentation
1.使用Python实现(rdp_check.py)
代码地址:https://github.com/SecureAuthCorp/impacket/blob/master/examples/rdp_check.py
可以在Windows和Linux系统上运行。
登录方式支持明文口令和NTLM hash。
命令行下使用。
脚本运行前需要安装Impacket。
安装方法:pip install Impacket。
如果是在Windows系统下使用,可以将Python脚本转换成exe,编译好的exe文件下载地址:https://github.com/maaaaz/impacket-examples-windows
使用示例:明文口令验证
rdp_check.py /administrator:[email protected]
使用示例:NTLM hash验证。
rdp_check.py /[email protected] -hashes :c5a237b7e9d8e708d8436b6148a25fa1
注:hash的格式为LMHASH:NTHASH,如果只有NTLM hash,格式为 :NTHASH,需要注意:前面存在一个空格字符。
2.使用C实现(FreeRDP)
代码地址:https://github.com/FreeRDP
可以在Windows和Linux系统上运行。
登录方式支持明文口令。
命令行下使用。
如果为了支持NTLM hash登录,需要使用旧版本的FreeRDP,下载地址:https://labs.portcullis.co.uk/download/FreeRDP-pth.tar.gz
如果仅仅为了验证口令或者hash,需要修改代码,去除后续登录的功能。
关于FreeRDP的使用可参考:https://github.com/FreeRDP/FreeRDP/wiki/CommandLineInterface
3.使用C sharp实现(SharpRDPCheck)
可以在Windows系统上运行。
登录方式支持明文口令和NTLM hash。
命令行下使用。
开发过程记录:
这里无法通过调用ActiveX组件AxMSTSCLib实现,原因如下:
使用ActiveX组件AxMSTSCLib无法通过NTLM hash登录。
对命令行的支持不够友好。
所以只能参照rdp_check.py的方式,手动构造通信数据。
经过搜索,我找到了一个可供参考的代码:https://github.com/RDPUploader/RDPUploader
RDPUploader包括三个子项目,编译成功后生成两个dll和一个exe文件,不支持命令行操作,也不支持NTLM hash登录,但其中的通信过程写的很清晰。
接下来以RDPUploader为模板进行开发。
这里具体介绍一下支持NTLM hash登录的方法:
Remote Desktop Protocol在进行验证时,先将明文口令转换成NTLM hash,再进行验证。
我们首先寻找RDPUploader中从明文口令转换为NTLM hash的代码,具体内容如下:
private static byte[] nTOWFv1(string password) { if (password == null) { throw new Exception("Password parameter is required"); } return MD4.ComputeHash(Encoding.Unicode.GetBytes(password)); } private static byte[] nTOWFv2(string domain, string username, string password) { HMACT64 hmact = new HMACT64(nTOWFv1(password)); hmact.update(Encoding.Unicode.GetBytes(username.ToUpper())); hmact.update(Encoding.Unicode.GetBytes(domain)); return hmact.digest(); }
补充:NTLM hash的生成方法。
将明文口令转换成十六进制的格式。
转换成Unicode格式,即在每个字节之后添加0x00。
对Unicode字符串作MD4加密,生成32位的十六进制数字串。
这里以明文口令test123为例:
转换成十六进制的格式为74657374313233
转换成Unicode格式为7400650073007400310032003300
对字符串7400650073007400310032003300作MD4加密,结果为c5a237b7e9d8e708d8436b6148a25fa1
更多细节可参考之前的文章《Windows下的密码hash——NTLM hash和Net-NTLM hash介绍》。
这里我们可以将nTOWFv1(password)的结果输出,验证NTLM hash的生成方法是否准确,修改后的代码如下:
private static byte[] nTOWFv2(string domain, string username, string password) { byte[] a = nTOWFv1(password); string text = ""; for (int i = 0; i < a.Length; i++) { text += a[i].ToString("X2"); } Console.WriteLine(text); HMACT64 hmact = new HMACT64(a); hmact.update(Encoding.Unicode.GetBytes(username.ToUpper())); hmact.update(Encoding.Unicode.GetBytes(domain)); return hmact.digest(); }
输出的字符串为C5A237B7E9D8E708D8436B6148A25FA1,验证成功。
接下来,直接传入字符串C5A237B7E9D8E708D8436B6148A25FA1进行验证。
这里需要将hex格式的字符串转换为byte[],代码如下:
public static byte[] ConvertHexStringToBytes(string hexString) { hexString = hexString.Replace(" ", ""); if (hexString.Length % 2 != 0) { throw new ArgumentException("wrong length of ntlm hash"); } byte[] returnBytes = new byte[hexString.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) { returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); } return returnBytes; } private static byte[] nTOWFv2(string domain, string username, string password) { string text = "C5A237B7E9D8E708D8436B6148A25FA1"; byte[] byteArray = ConvertHexStringToBytes(text); HMACT64 hmact = new HMACT64(byteArray); hmact.update(Encoding.Unicode.GetBytes(username.ToUpper())); hmact.update(Encoding.Unicode.GetBytes(domain)); return hmact.digest(); }
验证成功,最后将固定字符串修改为变量传递即可实现对NTLM hash登录的支持。
完整代码已开源,地址如下:https://github.com/3gstudent/SharpRDPCheck/
可通过Visual Studio进行编译,编译的目标框架推荐使用.NET Framework 4.6,这是为了使用TLSv1.2。
否则会使用TLSv1.0,在进行登录时会失败,提示如下:
[!] Authentication Error (The decryption operation failed, see inner exception.) InnerException: System.ComponentModel.Win32Exception (0x80004005): The Local Sec urity Authority cannot be contacted
参考资料:https://docs.microsoft.com/en-us/dotnet/api/system.net.security.sslstream.authenticateasclient?redirectedfrom=MSDN&view=netframework-4.8
编译成功后在安装.NET Framework 4的Windows系统下都可以正常使用。
0x04 防御思路
对于RDP的爆破攻击,可以选择提高用户口令的强度。
对于爆破行为的检测,可以通过cmd查看其他用户通过RDP登录当前系统的日志:
wevtutil gli "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" wevtutil qe /f:text "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational"
每当Listener RDP-Tcp收到一个连接请求,将产生EventID为261的日志。
也就是说,只要收到了RDP的连接请求,无论连接是否成功,均会产生EventID为261的日志。
通过Powershell查看其他用户通过RDP登录当前系统的日志:
https://gallery.technet.microsoft.com/Remote-Desktop-Connection-3fe225cd
0x05 小结
本文介绍了针对Remote Desktop Protocol,验证口令或者NTLM hash的实现方法,开源代码SharpRDPCheck,分享程序实现NTLM hash登录的细节,最后介绍通过日志检测RDP爆破行为的方法。
本文为 3gstudent 原创稿件,授权嘶吼独家发布,如若转载,请注明原文地址