TryHackMe-红队-22_混淆 | 签名规避

Signature Evasion

了解如何使用与工具无关的现代方法破解签名并规避常见的 AV。

这个房间是混淆原则的继承者;如果您还没有完成,我们强烈建议您在此房间之前完成它。

在这个房间里,我们将了解什么是签名以及如何找到它们,然后尝试按照不可知论的思维过程来打破它们。为了更深入地研究并打击启发式签名,我们还将讨论更高级的代码概念和“恶意软件最佳实践”。

签名识别

在识别签名时,无论是手动还是自动,我们必须采用迭代过程来确定签名从哪个字节开始。通过递归地将编译的二进制文件分成两半并对其进行测试,我们可以粗略估计字节范围以进一步研究。

我们可以使用linux命令head来切割payload可执行文件

head --bytes 29 example.exe > half.exe

循环该过程,直到找到确切的会被标记为恶意的部分

这种方式有个致命的缺点就是慢

自动化签名识别

ThreatCheck

ThreatCheck是DefenderCheck的一个分支,可以说是三者中最广泛使用/最可靠的。为了识别可能的签名,ThreatCheck 利用多个防病毒引擎来攻击拆分编译的二进制文件,并报告它认为存在错误字节的位置。

对于我们的用途,我们只需要提供一个文件和一个可选的引擎;但是,在处理 AMSI 时,我们将主要使用 AMSITrigger(Anti-M alware S Can Interface),我们将在本任务的后面讨论。

C:\>ThreatCheck.exe -f Downloads\Grunt.bin -e AMSI

AMSITrigger

AMSITrigger将利用AMSI引擎和扫描功能,针对提供的PowerShell脚本,并报告它认为需要警报的任何特定代码部分。

C:\> .\amsitrigger.exe -i bypass.ps1 -f 3

静态代码签名

一旦我们确定了一个麻烦的签名,我们需要决定如何处理它。根据签名的强度和类型,可以使用混淆原则中所述的简单混淆来破解它,或者可能需要特定的调查和补救措施。在此任务中,我们的目标是提供几种解决方案来修复函数中存在的静态签名。

拆分和合并对象

拆分或合并对象所需的方法与混淆原则中所述的串联目标非常相似。

这个概念背后的前提相对容易,我们希望创建一个新的对象函数,它可以在保持先前功能的同时破坏签名。

删除和隐藏可识别信息

删除可识别信息背后的核心概念类似于模糊处理原则中所述的变量名称。在此任务中,我们更进一步,专门将其应用于任何对象(包括方法和类)中的已识别签名。

基于静态属性的签名

各种检测引擎或分析师可能会考虑不同的指标,而不是字符串或静态签名来促进他们的假设。签名可以附加到多个文件属性,包括文件哈希、熵、作者、名称或其他可单独或结合使用的可识别信息。这些属性通常用于规则集,如 YARA 或 Sigma。

文件hash

在处理已签名或闭源应用程序时,我们必须使用位翻转。

位翻转是一种常见的加密攻击,它将通过翻转和测试每个可能的位来改变给定的应用程序,直到找到可行的位。通过翻转一个可行的位,它将更改应用程序的签名和哈希,同时保持所有功能。

从IBM开始,熵被定义为“文件中数据的随机性,用于确定文件是否包含隐藏数据或可疑脚本”。EDR 和其他扫描程序通常利用熵来识别潜在的可疑文件或导致整体恶意分数。

熵对于混淆脚本可能会有问题,特别是在模糊变量或函数等可识别信息时。

为了降低熵,我们可以用随机选择的英语单词替换随机标识符。例如,我们可以将变量从 q234uf更改为 nature

行为签名

现代引擎仍可能观察二进制文件的行为和功能。这给攻击者带来了许多问题,这些问题无法通过简单的混淆来解决。

如防病毒简介中所述,现代防病毒引擎将采用两种常用方法来检测行为:观察导入和挂钩已知的恶意调用。

导入表可以提供对二进制文件功能的大量见解,这可能对对手有害。但是,如果需要分配函数地址,我们如何防止我们的函数出现在 IAT 中?

如前所述,thunk 表并不是获取函数地址指针的唯一方法。我们还可以利用 API 调用从导入库本身获取函数地址。此技术称为动态加载,可用于避免 IAT 并最大程度地减少 Windows 加载程序的使用。

在高层次上,我们可以将 C 语言中的动态加载分解为四个步骤,

  1. 定义调用的结构
  2. 获取调用地址所在的模块的句柄
  3. 获取调用的进程地址
  4. 使用新创建的调用

首先定义一个结构

// 1. Define the structure of the call
typedef BOOL (WINAPI* myNotGetComputerNameA)(
	LPSTR   lpBuffer,
	LPDWORD nSize
);

接着使用LoadLibrary加载kernel32

HMODULE hkernel32 = LoadLibraryA("kernel32.dll");

使用GetProcAddress获取GetComputerNameA的函数地址

myNotGetComputerNameA notGetComputerNameA = (myNotGetComputerNameA) GetProcAddress(hkernel32, "GetComputerNameA");

最后就可以直接调用notGetComputerNameA

全部整合起来

简单复习这里我就不贴代码了,因为跟房间上面教导的一致

  1. 不存在可疑的库调用 — 动态加载
  2. 没有泄漏的函数或变量名称 — 低熵的同时将函数、变量名修改为其他无意义单词
  3. 文件哈希与原始哈希不同 — 位翻转
  4. 二进制绕过常见的防病毒引擎

你可能感兴趣的:(TryHackMe,红队,签名规避,免杀,windows)