我们都习惯了 CyberChef 的常规操作,例如“From Base64”、“From Decimal”以及偶尔的魔术解码或异或。但是当我们需要执行更高级的操作时会发生什么?
Cyberchef 包含许多高级操作,这些操作通常会被人们忽略,而人们更倾向于使用 Python 脚本。很少有人知道 Cyberchef 能够执行更复杂的操作。这些操作包括流控制、寄存器和各种正则表达式功能。
在这篇文章中,我们将分解一些更高级的 CyberChef 操作,以及如何应用这些操作来开发多阶段恶意软件加载器的配置提取器。
CyberChef 高级操作示例
在深入研究之前,让我们先快速回顾一下我们将要演示的操作。
-
寄存器
-
正则表达式和捕获组
-
通过分叉和合并进行流量控制
-
合并
-
减法
-
AES 解密
在单独演示这些概念之后,我们将把它们结合起来,开发一个多阶段恶意软件样本的配置提取器。
获取样本
演示的样本可以在Malware Bazaar上找到,
SHA256:befc7ebbea2d04c14e45bd52b1db9427afce022d7e2df331779dae3dfe85bfab
高级操作1-寄存器
寄存器允许我们在 CyberChef 会话中创建变量,并在需要时引用它们。
寄存器通过正则表达式捕获组定义,允许我们创建一个具有未知值且适合代码中已知模式的变量。
如何在 CyberChef 中使用寄存器
下面我们有一个利用 AES 解密的 Powershell 脚本。
传统上,使用 CyberChef 可以轻松解码,只需手动复制出密钥值并将其粘贴到“AES 解密”操作中即可。
我们可以看到密钥被复制到 AES 解密操作中。
这种手动复制密钥的方法是有效的,但这意味着密钥是“硬编码的”,并且该配方不适用于使用相同技术的类似样本。
如果另一个样本使用不同的密钥,则需要手动更新此新密钥以使 CyberChef 配方正常工作。
寄存器示例 1
通过利用“注册”操作,我们可以开发一个正则表达式来匹配 AES 密钥的结构,然后通过寄存器变量访问它,如下$R0所示
在这种情况下,AES 密钥是一个 44 个字符的 base64 字符串,因此我们可以使用 44-46 个字符的 base64 正则表达式来提取 AES 密钥。
我们稍后可以通过 AES 解密操作中的 $R0 变量访问它。
寄存器示例 2
在同一样本的先前阶段,恶意软件利用基本减法运算从大整数数组中创建 ASCII 字符代码。
传统上,这将通过手动复制出 787 值并将其应用于减法运算来解码。
但是,如果另一个样本采用相同技术但值不同,则仍会出现问题。
更好的方法是使用与 787 值匹配的正则表达式创建另一个寄存器。
这里我们可以看到一个例子,其中寄存器被用来定位和存储 $R0 中的值 787。稍后可以通过引用 $R0 在减法运算中引用该值。
常用表达
正则表达式令人沮丧、乏味且难以学习。但它们非常强大,您绝对应该学习它们,以提高您的 Cyberchef 和恶意软件分析能力。
在该配置提取器的开发中,正则表达式被应用于10个独立的操作。
正则表达式 – 用例 1(寄存器)
正则表达式的第一次使用是在初始寄存器操作中。
在这里,我们应用了正则表达式来提取稍后作为反混淆过程的一部分使用的键值。
这里正则表达式的主要用途是一般性地捕获与解码过程相关的键,避免对值进行硬编码,并允许配方在多个样本中发挥作用。
如何使用正则表达式隔离文本
本配方中正则表达式的第二个用途是隔离包含恶意软件第二阶段的主整数数组。
第二阶段存储在一个由逗号分隔并包含在圆括号中的十进制值大数组中。
通过在正则表达式中指定这一点,我们可以提取并隔离大型数组并有效地忽略其余代码。这与手动复制数组并开始新配方不同。
这里的一个主要好处是能够隔离代码的各个部分,而无需复制和粘贴。这使您可以继续在同一个配方中工作
正则表达式 – 用例 3(附加值)
有时您需要将值附加到输出的各个行。
在这些情况下,可以使用正则表达式来捕获整行(.*),然后用相同的值(通过 $1 中引用的捕获组)替换它,后面跟着另一个值(我们的初始寄存器)。
关键用例是能够轻松捕获和附加数据,这对于稍后将在本配方中使用的减法运算符等操作至关重要。
正则表达式 – 用例 4(提取加密密钥)
我们可以利用寄存器操作中的正则表达式来提取加密密钥并将其存储在变量中。
在这里,我们可以看到存储在 $R1 寄存器内的 44 个字符的 AES 密钥。
这是有效的,因为密钥以特定格式存储在样本中。利用正则表达式可以让我们捕获这种格式(单引号内的 44 个字符 base64),而无需担心确切的值。
使用正则表达式提取 Base64 文本
可以使用正则表达式来隔离包含感兴趣内容的 base64 文本。
此特定样本将恶意软件的最终阶段存储在大型 AES 加密和 Base64 编码的 blob 中。
由于我们已经通过寄存器提取了 AES 密钥,我们可以应用正则表达式来隔离主要的 base64 blob,然后执行 AES 解密。
正则表达式 – 用例 6(提取首字符)
此示例利用 base64 解码内容的前 16 个字节为 AES 解密创建 IV。
我们可以利用正则表达式和寄存器来提取解码内容的前 16 个字节.{16}。
这使我们能够捕获 IV,然后通过寄存器引用它来执行 AES 解密。
使用正则表达式删除尾随的空字节
正则表达式可用于从数据末尾删除尾随的空字节。
这非常有用,因为有时我们只想删除数据“末尾”的空字节。而传统的“删除空字节”将删除代码中所有位置的空字节。
在此处的示例中,尾随的空字节会破坏部分解密过程。
通过应用空字节搜索, +$我们可以使用查找/替换来删除这些尾随的空字节。
在这种情况下, +将查找一个或多个空字节,并$指定这必须位于数据的末尾。
应用此操作后,尾随的空字节现已从数据末尾删除。
如何在 CyberChef 中使用叉子
分叉使我们能够分离值并独立地对每个值采取行动,就好像它们是一个单独的配方一样。
在下面的用例中,我们有一个很大的十进制值数组,我们需要从每个值中减去 787。这里的主要问题是,为了减去 787,我们需要在下面的屏幕截图中的每个十进制值后附加 787。手动执行这将是一场噩梦。
由于数据是结构化的并用逗号分隔,因此我们可以应用分叉操作,以逗号作为分割分隔符,以换行符作为合并分隔符。
拆分分隔符用于分隔数据中的值,而合并分隔符则用于定义新数据的结构。
此时,每一行新行都代表一个新的输入数据,并且所有后续操作都将独立作用于每一行。
如果我们现在应用查找替换操作,我们可以看到该操作对每一行都产生了单独影响。
如果我们在没有分叉的情况下应用相同的概念,则只有一个 787 会被添加到整个十进制数据块的末尾。
应用查找/替换后,我们可以继续应用减法运算和“从十进制”。
这将揭示解码的文本和恶意软件的下一阶段。
请注意,前面提到的“合并分隔符”纯粹是格式的问题。
解码内容后,如上图所示,您需要删除合并分隔符以确保所有解码的内容都在一起。
删除合并分隔符后,我们可以看到完整的脚本。
如何在 CyberChef 中应用合并操作
操作merge本质上是 fork 操作的“撤消”。
在使用 fork 成功解码内容后,您应该应用merge以确保可以适当地分析新内容。
如果不进行合并,所有未来的操作都只会影响单个字符,而不是整个脚本。
Cyberchef 能够通过 AES 解密操作进行 AES 解密。
要利用 AES 解密,请在恶意软件代码中查找 AES 的关键指标,并将所有变量与 AES 操作对齐。
例如,对齐 Key、Mode 和 IV。然后,将这些值插入 CyberChef。
最后,您可以使用正则表达式和寄存器有效地实现自动化,如前所示。
配置提取器演练(22 个操作)
利用所有这些技术,我们可以为 NetSupport Loader 开发一个配置提取器,其中包含 3 个独立的脚本,这些脚本都可以在同一个配方中解码。
这总共需要 22 个操作,下面将进行演示。
初始脚本使用大量十进制整数数组进行混淆。
对于每个十进制值,减去数字 787,然后将结果用作 ASCII 字符码。
要解码这个组件,我们必须
-
使用寄存器提取减法值
-
使用正则表达式提取十进制数组
-
使用分叉来分离每个小数值
-
使用正则表达式附加存储在我们的寄存器中的值 787。
-
应用减法运算来生成 ASCII 字符代码
-
应用“从十进制”来产生第二阶段
-
使用合并操作来启用第二阶段脚本的分析。
操作 1-提取减法值
可以使用寄存器操作和正则表达式来提取初始减法值。
这必须在进行额外分析和解码之前完成,以确保减法值存储在寄存器内。
操作 2-提取十进制数组
第二步是使用正则表达式和捕获组提取出主十进制数组。
捕获组确保我们隔离十进制值并忽略其周围的任何脚本内容。
此正则表达式查找[d,]长度为 1000 或更长的小数或逗号{1000,}。并且用圆括号(和包围)。
没有转义的内部括号构成捕获组。
操作 3 – 分离小数值
第三个操作利用 Fork 来分离十进制值并独立地对每个值进行操作。
Fork 在原始代码中的逗号处定义了一个分隔符,并指定了 Merge Delimiter 以n提高可读性。
操作 4 – 附加减法值
第四个操作使用正则表达式查找/替换将值 787 附加到分叉操作创建的每一行的末尾。
请注意,我们已使用(.*)来捕获原始十进制值,然后使用$1来再次访问它。$R0用于访问可以在操作 1 中创建的寄存器。
操作 5 – 减去数值
现在,我们可以在操作 4 中附加 787 的值后执行减法运算。
这将生成构成第二阶段脚本的原始 ASCII 字符代码。
请注意,我们已经指定了一个空格分隔符,因为它在运算 4 中将我们的十进制值与减法值分开。
操作 6 – 在 CyberChef 中解码 ASCII 码
我们现在可以使用“从十进制”操作来解码 ASCII 代码。
这将生成原始脚本。但是,由于我们之前的 Fork 操作,值通过换行符分隔。
操作 7-合并结果
我们现在想按照整个新剧本来演,我们不想单独演每一个角色。
因此,我们将通过应用合并操作并将先前分叉的“合并分隔符”修改为空白来撤消分叉操作。
第 2 阶段 – 带有 AES 加密的 Powershell 脚本(8 个操作)
经过 7 次操作后,我们现在发现了第二阶段 Powershell 脚本,该脚本利用 AES 加密来解开附加阶段。
下面重点介绍了此脚本中解密所需的关键点。
要解码这个阶段,我们必须能够
-
使用寄存器提取 AES 密钥
-
使用正则表达式提取 Base64 blob
-
解码 Base64 blob
-
使用寄存器提取初始化向量
-
从输出中删除 IV
-
执行 AES 解密,引用我们的寄存器
-
使用正则表达式删除尾随的 NullBytes
-
执行 GZIP 解压缩以解锁第 3 阶段
CyberChef 操作 8 – 提取 AES 密钥
我们现在必须提取 AES 密钥并使用注册操作来存储它。
我们可以通过应用寄存器并创建一个长度恰好为 44 个字符并用单引号括起来的 base64 字符正则表达式来实现这一点。(我们也可以将其调整为 42 到 46 之间的范围)
我们现在将 AES 密钥存储在$R1指定的寄存器内。
操作 9 – 提取 Base64 Blob
现在我们有了 AES 密钥,我们可以隔离包含恶意软件下一阶段的主要 base64 blob。
我们可以使用长度为 100 个或更多字符的 Base64 文本的正则表达式来执行此操作。
我们还确保将输出格式更改为“列出匹配”,因为我们只想要与正则表达式匹配的文本。
操作 10-解码 Base64
这是在主 AES 解密之前解码 Base64 blob 的简单操作。
操作 11-提取初始化向量
当前数据的前16个字节构成AES解密的初始化向量。
我们可以使用另一个注册操作来提取它,并指定.{16}从当前数据块中抓取前 16 个字符。
根据原始脚本中的这段代码,我们知道这些字节是 IV。
请注意,base64 解码后会取出前 16 个字节,然后将其设置为 IV。
操作 12 – 删除初始 16 个字节
当实际的 AES 解密过程发生时,最初的 16 个字节将被忽略。
因此,我们需要使用drop bytes长度为16, 的操作来删除它们。
我们知道情况确实如此,因为脚本从距离数据偏移量 16 的地方开始解密。
这可以通过 TransformFinalBlock 的官方文档来确认。
操作 13 – AES 解密
现在已经提取并存储了 AES 解密的密钥和 IV 到寄存器中,我们可以继续应用 AES 解密操作。
请注意,我们可以通过之前创建的 $R1 和 $R2 寄存器访问密钥和 IV。我们不需要在此处指定密钥。
还要注意,我们需要分别为密钥和 IV 指定 base64 和 utf8,因为这些是我们提取它们时的格式
我们还可以注意到选择了 ECB 模式,因为这是脚本中指定的模式。
操作 14 – 删除尾随的空字节
AES 解密后的当前数据使用 GZIP 进行压缩。
然而,由于 AES 解密后数据末尾存在一些随机空字节,Gunzip 无法执行。
操作 14 涉及使用正则表达式删除这些尾随的空字节,即“数据末尾的一个或多个空字节 +”
我们将“替换”值留空,因为我们想要删除尾随的空字节。
操作 15 – GZIP 解压缩
我们现在可以应用 Gunzip 操作来执行 GZIP 解压缩。
这将揭示恶意内容的第 3 阶段,即另一个 Powershell 脚本。
请注意,我们知道使用了 Gzip,因为它在 AES 解密过程之后的第 2 阶段中被引用。
第 3 阶段 – Powershell 脚本(7 个操作)
我们现在有第 3 阶段的 PowerShell 脚本,它利用与第 1 阶段非常相似的技术。
混淆的数据再次存储在大型十进制数组中,每个值中减去数字 4274。
请注意,在这种情况下,总共有 4 个整数数组。
要解码第 3 阶段,我们必须执行以下操作
-
使用寄存器提取减法值
-
使用正则表达式提取十进制数组
-
使用分叉来分离数组
-
使用另一个 Fork 来分隔各个十进制值
-
使用查找/替换来附加减法值
-
执行减法
-
从生成的 ASCII 代码恢复文本
操作 16 – 使用寄存器提取减法值
我们第三阶段的第一步是提取减法值并将其存储在寄存器中。
我们可以通过创建另一个寄存器并实现正则表达式来捕获值来实现这一点$SHY=4274。我们可以指定一个美元符号,后跟字符,后跟等号,后跟整数,后跟分号。
将捕获组(圆括号)应用到小数部分,因为我们想要存储并在稍后使用它。
操作 17 – 提取和隔离十进制数组
现在我们有了减法键,我们可以继续使用正则表达式来隔离十进制数组。
我们选择了一个正则表达式,该正则表达式查找包含长整数和逗号序列(至少 30 个)的圆括号。通过添加不带转义的圆括号,括号内部已转换为捕获组。
我们还选择了List Capture Groups新行来仅列出捕获的十进制值和逗号。
操作 18 – 使用分叉分离数组
我们现在可以通过应用 fork 操作来分离十进制数组。
当前数组由新行分隔,因此我们可以将其指定为分割分隔符。
为了便于阅读,我们可以将合并分隔符指定为双换行符。双换行符除了使输出更易于阅读外,没有任何作用。
操作 19 – 使用另一个分叉分隔小数值
现在我们已经隔离了数组,我们需要隔离各个整数值,以便我们可以附加减法值。
我们可以使用另一个 Fork 操作来实现这一点,指定逗号分隔符(因为这是分隔十进制值的分隔符)和换行符作为合并分隔符。同样,这个新行除了提高可读性之外什么也不做。
运算 21 – 应用减法运算
我们现在可以应用减法运算来减去上一步中附加的值。
这将恢复原始的 ASCII 字符代码,以便我们可以在下一步对其进行解码。
操作 22 – 解码 ASCII 码
将 ASCII 码恢复为其原始十进制形式后,我们可以应用十进制运算来恢复原始文本。
我们可以看到Net.Webclient字符串,尽管由于我们的分叉操作,它被新行隔开了。
最终结果 – 提取恶意 URL
现在内容已经解码,我们可以删除在操作 19 中添加的可读性步骤。
也就是说,我们可以删除Merge Delimiter添加的,以提高步骤 20 和 21 的可读性。
删除后Merge Delimiter,现在将显示四个十进制数组的输出。
视频演示
https://youtu.be/CIg4TXFJRK0
Advanced CyberChef Techniques For Malware Analysis - Detailed Walkthrough and Examples
https://www.embeeresearch.io/advanced-cyberchef-operations-netsupport/
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):CyberChef 恶意软件分析高级技术 – 详细演练和示例