环境感知与证据发现
在此次调查中,我们获得了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.png、cure.txt、gunman.png、Helena.txt、outbreak.png和test.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