数字取证分析:追踪Zeta End攻击事件中的恶意软件与数据泄露

3 阅读11分钟

环境感知与证据发现

在此次调查中,我们获得了Zeta-9研究人员Dr. Frankenstein Code工作站的取证镜像。

值得注意的是,此工作站安装了Wing FTP Server,这让我立刻联想到了CVE-2025-47812(Wing FTP Server的RCE漏洞)。但根据“腐烂云”调查中发现的ClickFix攻击模式,Dr. Frankenstein Code可能成为了该攻击的受害者,因此这很可能是误导我们的线索。

此工作站上也有Dr. Helena的账户,但我们的主要关注点是Dr. Frankenstein Code。

现在,我将使用以下工具解析Windows事件日志文件夹、USN日志、MFT和预读取文件,为调查做准备。

命令:

EvtxECmd.exe -d "C:\Users\BTLOTest\Desktop\Artefacts\C\Windows\System32\winevt\logs" --csv . --csvf log_timeline.csv

命令:

MFTECmd.exe -f C:\Users\BTLOTest\Desktop\Artefacts\C\$Extend\$J -m C:\Users\BTLOTest\Desktop\Artefact\C\$MFT --csv C:\Users\BTLOTest\Desktop

命令:

PECmd.exe -d C:\Users\BTLOTest\Desktop\Artefacts\C\Windows\prefetch --csv c:\Users\BTLOTest\Desktop

调查过程

Q1) 调查人员发现Dr. Frankenstein访问了一个被入侵的Zeta-9网页,该网页是攻击者进入秘密部门网络的初始入口。他是在什么时候访问该页面的?

从“腐烂云”调查中我们已经知道,攻击者篡改了组织网站 (zeta9-research-portal.azurewebsites.net/) 来托管恶意的filefix命令。我们需要查找Dr. Frankenstein访问此网站的浏览器历史记录。

我们可以看到Dr. Frankenstein在 2025-09-27 11:17:33 访问了被篡改的网站。这应该作为我们事件时间线的起点,并重点关注此后发生的任何可疑事件。

答案: 2025-09-27 11:17:33

Q2) 在查看共享文档时,Frankenstein unknowingly ran a payload delivered via the site. What is the name of the Powershell script he was tricked into executing?

现在我们需要查看组织网站的网页存档,复制命令以揭示在被入侵的工作站上执行了什么操作。

可以看到,当此命令被输入到文件资源管理器地址栏时,提供的Gist URL上托管的PowerShell脚本将被执行。此执行导致攻击者获得了工作站初始访问权限。

答案: Microsoft.PowerShell.DataV4Adapter.ps1

Q3) 根据受害者被诱骗执行载荷的方式,识别攻击者使用的确切技术名称。

我们已发现这里使用的技术是“filefix”,答案很简单。

答案: filefix

Q4) 当Frankenstein被诱骗在其系统上执行恶意命令后,导致了shellcode的执行,从而使攻击者完全控制了其机器。该shellcode的MD5哈希值是多少?

现在我们来分析脚本。可以看到它有一个$compressedBase64变量,存储了一个base64编码的blob,该blob将被解码并解压(gunzip)以获得另一个PowerShell脚本,并通过Invoke-Expression执行它。

我们可以使用CyberChef解码并解压该base64 blob,得到另一个PowerShell脚本,其中包含另一个base64 blob(存储在$ETPvFICDa变量中)。为了获取解密后的脚本,我们需要先对其进行反转,然后再进行base64解码。

这应该是最终的脚本。它会从另一个Gist URL获取shellcode,将其从十六进制转换为原始字节,解压(gunzip),最后与0xFF进行异或操作,得到最终的shellcode,准备注入并执行。

为了获得此shellcode的MD5值,我们需要复制脚本中的步骤。但这里有一个关键点:作者A1l4m要求我们在计算MD5哈希之前,先将原始shellcode转换回十六进制并移除空白字符。

答案: d3cf756ebbdf7b015a2ee4e154b638ee

Q5) 由于shellcode运行,Frankenstein的机器回连到一个命令与控制(C2)主机。请提供外部IP和端口。

有多种方法可以找到答案。第一种是运行shellcode,同时让Process Monitor捕获powershell进程发出的任何连接。第二种方法是在沙箱中重现filefix攻击,如any.run报告中所示,powershell.exe回连的IP和端口是 35.158.153.237:34651

答案: 35.158.153.237:34651

Q6) C2连接成功后,攻击者运行了一个简单命令来确认身份和环境。他们执行了哪个命令来枚举机器?

我们可以查看预读取文件时间线,了解Dr. Frankenstein访问被篡改网站后发生的情况。可以看到whoami.exe随后被执行,接着是多次rclone.exe执行,以及公共用户主文件夹下的runtimebroker.exe。这确认了攻击者在获得工作站访问权限后,首先执行了whoami以确认身份,然后使用rclone从云端传输工具。

答案: whoami

Q7) 获得访问权限后不久,入侵者更改了PowerShell的执行策略。该修改具体发生在何时?

我们可以使用注册表浏览器查看Dr. Frankenstein的NTUSER.dat配置单元下的ExecutionPolicy注册表项。记录显示,在 2025-09-27 11:19:49,攻击者将此用户的执行策略更改为“Unrestricted”,这将允许在此用户下运行任何脚本。

答案: 2025-09-27 11:19:49

Q8) 为了在重启后仍能存活,攻击者放置了一个辅助可执行文件。用于持久化的可执行文件的完整文件系统路径是什么?

我们已经发现RunTimeBroker.exe在rclone和PowerShell之后被执行。将此文件的哈希提交到VirusTotal。

VirusTotal显示此可执行文件是一个Sliver植入物。因此,攻击者放置二进制文件以维持持久性是合理的,因为初始访问是通过ClickFix获得的。

答案: C:\Users\Public\RunTimeBroker.exe

Q9) 攻击者使用了哪个工具来获取该持久化二进制文件?

现在让我们通过USN日志查找此文件的来源。我们已经发现它可能来自rclone,而USN日志证实了这一点:它最初以rclone临时文件的名称创建,然后重命名为原始名称(sapi.cpl),接着重命名为RunTimeBroker.exe,最后移动到C:\Users\Public\

答案: rclone

Q10) 持久化机制实际是在何时建立的(即,触发可执行文件的内容是何时写入的)?

这个问题相当棘手。从预读取文件中,我们看到每次PowerShell执行后,Sliver植入物都会被执行,这让我确信持久化与PowerShell有关。

查看USN日志,在事件时间范围内的 2025-09-27 11:35:08,PowerShell配置文件被编辑。这证实了攻击者编辑了PowerShell配置文件,以便每次加载PowerShell配置文件时(通常在PowerShell启动时)执行Sliver植入物。

答案: 2025-09-27 11:35:08

Q11) 持久化二进制文件联系了哪个C2服务器(IP:端口)?

有两种方法可以找到答案。第一种是运行该恶意文件,同时让进程监控工具捕获其网络连接,结果是连接到 63.178.44.21:8838。另一种方法是回到VirusTotal,可以看到它联系了相同的IP地址和端口,这个端口非常规,因此很可能是反向shell连接端口。

答案: 63.178.44.21:8838

Q12) 识别恶意文件用于命令和控制通信的框架。

是Sliver。

答案: sliver

Q13) 一旦入侵者确认了持续访问,他们便开始无惧断连地探索秘密部门的网络。他们下载了一个包含其外泄工具集的ZIP文件。请提供该ZIP文件的MD5哈希值。

首先,我们需要确定ZIP文件是什么以及它是如何下载到工作站的。使用USN日志,我们看到CUREKiller.zip是通过certutil下载的,其中包含5个文件。

遗憾的是,我们没有相关的certutil工件,因此必须使用位于C:\Users\Dr.FrankensteinCode\AppData\Local\Microsoft\Windows\WebCache的Web缓存。我们可以看到它缓存了请求下载CUREKiller.zip文件的HTTP请求。那么如何获取此文件的哈希呢?

我们可以取x-ms-blob-content-md5的值,该值用于在传输过程中验证blob的完整性。我们需要将其从base64转换回来,再转换为十六进制,最终得到此文件的MD5。

答案: b289a7f5fd8bcb22e5452d4fe3e57174

Q14) 最终,对手从侦察转向了数据窃取。用于外泄的可执行文件确切是在何时运行的?

从预读取时间线中,我们看到KillTheCure.exe(被认为是用于外泄的可执行文件)在 2025-09-27 15:49:58 执行,随后是sdelete,用于安全删除此工作站上的6个不同文件。同时,我们看到Exfiltrated_data.zip是在KillTheCure.exe执行期间创建的。

答案: 2025-09-27 15:49:58

Q15) 用于外泄的远程主机的IP地址是什么?

我们需要获取CUREKiller.zip文件并对KillTheCure.exe二进制文件进行逆向工程。假设攻击者使用同样的技巧来托管此ZIP文件,我们如何获得“unique_id”呢?它比预期的更简单,就在添加?符号参数之前的URL末尾。

这意味着我们现在可以从 https://github.com/user-attachments/files/22441452/CUREKiller.zip 下载ZIP文件。

我们现在可以使用任何工具反编译该可执行文件。可以看到,在执行时,它会搜索执行该文件的用户的“下载”和“桌面”文件夹中的.png.jpg文件,将它们移动到临时文件夹,打包为Exfiltrated_data.zip,然后嵌入到BetterCallSaul.png文件中,接着使用sdelete删除原始文件,再删除所有临时文件。最后,它通过HTTP POST请求将BetterCallSaul.png发送到 /upload 路径,目标IP为 36.157.123.216

答案: 36.157.123.216

Q16) 攻击者窃取并删除了秘密部门网络中的关键文件。列出被窃取的文件并按字母顺序排序。

在外泄可执行文件执行期间,桌面文件夹中有6个.png.txt文件:confidential.pngcure.txtgunman.pngHelena.txtoutbreak.pngtest.txt

答案: confidential.png, cure.txt, gunman.png, Helena.txt, outbreak.png, test.txt

Q17) 当攻击者用于外泄的主要C2端点失败时,他们转向了另一种工具以继续进行外泄。作为备用方案使用了什么工具?

我们已经知道攻击者使用rclone投放Sliver C2,因此它也可以用作同步/上传外泄文件的备用方案。调查机器中的Chrome浏览器历史记录也显示我们从MEGA下载了BetterCallSaul.png

现在我们需要确认这一点。从rclone配置文件中获取MEGA凭证,但密码是加密的。由于rclone是开源的,有多种工具可以解密rclone密文。现在我已经得到了两个用户的明文密码。

我登录了每个MEGA账户,第一个账户没什么意思,但第二个账户确认了图像文件也使用rclone克隆到了这里!

除此之外,我们还可以在这里看到Sliver植入物、netcat二进制文件以及预期的Wing FTP Server RCE利用脚本。

答案: rclone

Q18) 为了使用备用工具,攻击者需要云访问权限。他们在系统上存储了凭证。请提供他们使用的该账户的电子邮件和密码。

答案: 00darksideofme00+2@gmail.com:Necrobyte001123!

Q19) 关键文件‘cure.txt’在已擦除的数据中!恢复被认为是可能的——如果你能恢复它,请提交该文件的MD5哈希值。调查人员已使用上一个问题的凭证登录了攻击者的云,并将一份外泄内容的副本存储在本地:C:\users\BTLOtest\Downloads

由于我们拥有外泄二进制文件和图像文件,我将使用以下由ChatGPT生成的脚本从图像中提取ZIP文件。

# extractor.py
# 需要: Pillow (PIL)
# 用法: python extractor.py hidden.png recovered.bin
import sys
from PIL import Image
import zlib
import struct

def read_rgba_bytes(png_path):
    img = Image.open(png_path)
    img = img.convert("RGBA")
    data = img.tobytes() # 行主序 RGBA
    return data

def extract(png_path, out_path):
    data = read_rgba_bytes(png_path)
    # C 代码将头部+载荷直接写入 RGBA 字节。
    # 所以 'data' 的前16个字节是头部。
    if len(data) < 16:
        raise ValueError("PNG 太小或不包含嵌入数据。")
    header = data[:16]
    crc32_field, key_field_lo, orig_size = struct.unpack("<I Q I", header)
    # key_field_lo 的低4字节包含4字节的密钥。
    key = struct.pack("<Q", key_field_lo)[:4] # 小端序的前4字节
    original_size = orig_size
    encrypted = data[16:16+original_size]
    if len(encrypted) < original_size:
        raise ValueError("PNG 未包含完整的载荷(被截断)。")

    # 验证 CRC32:C函数使用了 crc32(0,..) 然后 crc32(prev, &v71, 12)
    # 这实际上是对从v71开始的12字节块(密钥+大小)进行CRC32计算。
    # 重新创建12字节块:
    block12 = key + b'\x00\x00\x00\x00' + struct.pack("<I", original_size)
    check_crc = zlib.crc32(block12) & 0xFFFFFFFF
    if check_crc != crc32_field:
        print("警告:CRC 不匹配(载荷完整性检查失败)。")
    # 使用4字节密钥重复进行异或解密
    key_bytes = key
    out = bytearray()
    for i, be in enumerate(encrypted):
        out.append(be ^ key_bytes[i % 4])
    with open(out_path, "wb") as f:
        f.write(out)
    print(f"已将 {len(out)} 字节写入 {out_path}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("用法: python extractor.py hidden.png recovered.bin")
        sys.exit(1)
    extract(sys.argv[1], sys.argv[2])

现在我们应该能够解压它,并最终获得 CURE.txt 文件的哈希值。

答案: d81c7ad96edfb8e183613f579f105578

Q20) 在完成前面的步骤后,攻击者开始清除痕迹。对手删除了各种工件(工具、事件日志、注册表项)。包含初始访问命令的注册表项是何时被清除的?

我们知道攻击者利用filefix攻击诱骗Dr. Frankenstein,那么可能记录该命令的注册表项是TypedPaths。由于它已被清除,最后一次写入的时间戳揭示了清除发生的时间。

答案: 2025-09-28 02:20:47

Q21) 最后,攻击者清除了Windows事件日志以掩盖其踪迹。清除了多少个日志文件?

最后,我们可以看到攻击者执行了wevutil来清除5个不同的日志。

答案: 5 CSD0tFqvECLokhw9aBeRqpNzLTXFlojmzFn6OlyTg9UXZ0dCc3IqMwPPOCk+emZ/oAuwo2O7jNMHv+zJ33baH8aQ+ivLF+CDSeSprl7jJFW7Dv0AQXifCEy09e8T4mdA+GAFE50D8NTzCRRiyWK6A9R86LNDCkLq3J39y8vAiRE0n5aaCrMdbXIJlvX+mDCd