![YARP 作为 Cobalt Strike C2 重定向器 YARP 作为 Cobalt Strike C2 重定向器](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/03/2-1710117339.gif)
YARP:另一个反向代理是 Microsoft 开发的一个 .NET 库,旨在在 ASP.NET Core 基础架构之上运行。YARP 的预期用例是位于后端和前端服务之间,以提供反向代理和负载平衡服务。这篇博文的内容是展示它如何也可以用作 C2 重定向器。我确信您会问的一个问题是为什么 YARP 而不是 Apache 或 Nginx 之类的东西,对此我并没有真正的答案。我想到的唯一原因是 ASP.NET Core 更容易部署到 AWS Lambda 和 Azure Functions 等无服务器云服务。从架构上讲,这使得可以通过站点到站点 VPN 轻松托管 C2 服务器的本地和代理流量,特别是在通过 IaC 进行部署时。除此之外,我只是想尝试一下。
![YARP 作为 Cobalt Strike C2 重定向器 YARP 作为 Cobalt Strike C2 重定向器](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/03/6-1710117340.jpeg)
创建一个新的空 ASP.NET Core 项目并添加 NuGet 包的项目引用Yarp.ReverseProxy。然后添加YARP中间件:
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("YARP"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();
第 4 行命令 YARP 从 加载其配置appsettings.json,这对于 ASP.NET Core 来说是惯用的。您还可以在代码中配置 YARP,但这种方法为部署提供了更大的灵活性。因此,这实际上就是我们需要编写的所有 C# 代码。添加一个名为“YARP”的新部分到appsettings.json. 请注意,部分名称必须与您在上面的调用中输入的名称相匹配GetSection()。
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Urls": "http://0.0.0.0:80", <-- bind YARP to port 80
"AllowedHosts": "*",
"YARP": {
-- YARP config here --
}
}
作为开始并在高层次上演示 YARP 的一种方法,我们将每个请求代理到 C2 服务器。大部分配置是定义“路由”和“集群”。“路由”是一种根据传入 HTTP 请求的路径、方法、主机、标头或查询参数来匹配传入 HTTP 请求的方法。除非与定义的路由匹配,否则 YARP 不会代理请求。“集群”定义了匹配的 HTTP 请求应被代理到的目的地。
在这里,我有一个示例 HTTP C2 侦听器设置到 Beacon-HTTP towww.nickelviper.com和api.nickelviper.com。两者都解析为35.176.76.62– YARP 实例的公共 IP。
基本的 YARP 配置可能如下所示:
"YARP": {
"Routes": {
"yolo": {
"ClusterId": "teamserver",
"Match": {
"Path": "{**catch-all}",
"Hosts": [
"api.nickelviper.com",
"www.nickelviper.com"
]
}
}
},
"Clusters": {
"teamserver": {
"Destinations": {
"http-yarp": {
"Address": "http://172.31.3.178"
}
}
}
}
}
这告诉 YARP 任何包含Host 标头api.nickelviper.com或www.nickelviper.com在 Host 标头中的 HTTP 请求都应该代理到http://172.31.3.178. 这是 YARP 实例可访问的 C2 服务器的内部 IP 地址。默认的 ASP.NET Core 日志记录会将 HTTP 请求打印到控制台,但您也可以使用其他日志记录解决方案(例如 Serilog)并将它们发送到更有用的地方,例如RedELK。
info: Yarp.ReverseProxy.Forwarder.HttpForwarder[9]
Proxying to http://172.31.3.178/cx HTTP/2 RequestVersionOrLower
info: Yarp.ReverseProxy.Forwarder.HttpForwarder[56]
Received HTTP/1.1 response 200.
Beacon 将签入并正常运行。
为了防止任何任意 HTTP 请求通过,可以收紧路由策略,以更紧密地匹配基于 C2 流量配置文件的预期。本示例中运行的配置文件使用对和 的GET请求执行签入;信标元数据在标头中传输。它使用请求将数据发送回. 标题适用于两者。/cx/pushCookiePOST/submit.php?id=<bid>User-AgentMozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)
GET 的两条路由如下所示:
"checkin-1": {
"ClusterId": "teamserver",
"Match": {
"Methods": [
"GET"
],
"Path": "/cx",
"Hosts": [
"api.nickelviper.com",
"www.nickelviper.com"
],
"Headers": [
{
"Name": "User-Agent",
"Values": [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)"
]
},
{
"Name": "Cookie",
"Values": [],
"Mode": "Exists"
}
]
}
},
"checkin-2": {
"ClusterId": "teamserver",
"Match": {
"Methods": [
"GET"
],
"Path": "/push",
"Hosts": [
"api.nickelviper.com",
"www.nickelviper.com"
],
"Headers": [
{
"Name": "User-Agent",
"Values": [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)"
]
},
{
"Name": "Cookie",
"Values": [],
"Mode": "Exists"
}
]
}
}
我们不知道元数据 cookie 的值,因为每个信标的值都不同,所以我只是检查它是否存在。其他模式包括“HeaderPrefix”和“Contains”,它们可以帮助匹配更具体的情况(例如,如果 C2 配置文件包含我们可以查找的静态前缀和/或后缀)。如果未指定模式(与 User-Agent 标头一样),则默认为“Exact”。
POST 的路由可能如下所示:
"post-data": {
"ClusterId": "teamserver",
"Match": {
"Methods": [
"POST"
],
"Path": "/submit.php",
"Hosts": [
"api.nickelviper.com",
"www.nickelviper.com"
],
"Headers": [
{
"Name": "User-Agent",
"Values": [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)"
]
}
],
"QueryParameters": [
{
"Name": "id",
"Values": [],
"Mode": "Exists"
}
]
}
}
与元数据 cookie 一样,我们不会知道 Beacon ID 的确切值,因此我们只需检查查询参数是否存在。这还支持“前缀”和“包含”模式。
尝试以与配置的路由不匹配的方式访问端点将返回 404 – 但这是由 YARP 而不是 C2 服务器提供的。可以添加额外的“包罗万象”规则来代理未知请求,以达到欺骗和/或恶意攻击的目的。在第一个示例中,我展示了代理到团队服务器的所有内容。您可以添加指向合法网站的其他集群:
"Clusters": {
"teamserver": {...},
"google": {
"Destinations": {
"google": {
"Address": "https://www.google.com"
}
}
}
}
然后是一个新的包罗万象的规则:
"catch-all": {
"ClusterId": "google",
"Match": {
"Path": "{**catch-all}"
}
}
但显然,最好的办法是重新编写 URL,以便 Rick Roll 爱管闲事的人知道。这可以使用 YARP 的“转换”来完成。
"rick-roll": {
"ClusterId": "youtube",
"Match": {
"Path": "{**catch-all}"
},
"Transforms": [
{
"PathSet": "/watch"
},
{
"QueryValueParameter": "v",
"Set": "dQw4w9WgXcQ"
}
]
}
我对 YARP 的体验非常愉快,尽管我预计大多数人会更愿意坚持他们的 Apache/Nginx 重写规则。如果直接内置到基于 .NET 的 C2 中,该包可能会具有更多实用性。
感谢您抽出
![YARP 作为 Cobalt Strike C2 重定向器 YARP 作为 Cobalt Strike C2 重定向器](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/03/10-1710117343.gif)
.
![YARP 作为 Cobalt Strike C2 重定向器 YARP 作为 Cobalt Strike C2 重定向器](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/03/4-1710117343.gif)
.
![YARP 作为 Cobalt Strike C2 重定向器 YARP 作为 Cobalt Strike C2 重定向器](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/03/8-1710117343.gif)
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):YARP 作为 Cobalt Strike C2 重定向器