0x1
这是环境搭建好的页面,无法进入到底层的shell界面
使用vmware将搭建好的系统盘挂载到另外一个虚拟机上
Disk /dev/sda: 100 GiB, 107374182400 bytes, 209715200 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type : gpt
Disk identifier: 7C0CDB37-340D-4226-A8F1-FC9EBAC6D294
Device Start End Sectors Size Type
/dev/sda1 2048 4095 2048 1M BIOS boot
/dev/sda2 4096 1054719 1050624 513M EFI System
/dev/sda3 1054720 209713151 208658432 99.5G Linux filesystem
Disk /dev/mapper/groupZ-home: 6.72 GiB, 7218397184 bytes, 14098432 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/mapper/groupA-home: 4.87 GiB, 5226102784 bytes, 10207232 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/mapper/groupA-runtime: 19.46 GiB, 20891828224 bytes, 40804352 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
这里是挂载出来的所有的磁盘内容,这里直接创建三个目录挂载出来,发现了加密文件就是这三个,只需要对这三个文件进行解密即可
root@eve:~# mount /dev/mapper/groupZ-home /tmp/sda2
mount: /tmp/sda2: unknown filesystem type 'crypto_LUKS' .
root@eve:~# mount /dev/mapper/groupA-home /tmp/sda2
mount: /tmp/sda2: unknown filesystem type 'crypto_LUKS' .
root@eve:~# mount /dev/mapper/groupA-runtime /tmp/sda2
mount: /tmp/sda2: unknown filesystem type 'crypto_LUKS' .
内核启动的时有调用crypto进行加密,其中也有调用api进行解密,那么这个加密与解密的过程就在虚拟机的内存当中,现在只需要对虚拟机的内存文件进行扫描密码即可
1 .boot loader把内核以及initrd文件加载到内存的特定位置。
2 .内核判断initrd的文件格式,如果不是cpio格式,将其作为image-initrd处理。
3 .内核将initrd的内容保存在rootfs下的/initrd.image文件中。
4 .内核将/initrd.image的内容读入/dev/ram0设备中,也就是读入了一个内存盘中。
5 .接着内核以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。
6 ..如果/dev/ram0被指定为真正的根文件系统,那么内核跳至最后一步正常启动。
7 .执行initrd上的/linuxrc文件,linuxrc通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动,以及加载根文件系统。
8 ./linuxrc执行完毕,常规根文件系统被挂载
9 .如果常规根文件系统存在/initrd目录,那么/dev/ram0将从/移动到/initrd。否则如果/initrd目录不存在,/dev/ram0将被卸载。
10 .在常规根文件系统上进行正常启动过程 ,执行/sbin/init。
这里将sda1,sda2,sda3分别挂载出来其中有grub.cfg,在grub.cfg中进入Current会进入到系统A分区,这里的内容已经告诉我们需要对GroupA组当中的磁盘进行解密,因为GrpupZ是恢复工厂设置
....
menuentry "Current" {
set root=(hd0,2 ) //将GRUB的根文件系统设置为第一块的第二个分区
linux /kernel system=A rootdelay=5 console=ttyS0,115200n8 console=tty0 vm_hv_type=VMware
//采用了A/Z双分区
initrd /coreboot.img //初始内存盘的文件路径
}
menuentry "Factory Reset" {
set root=(hd0,1 )
linux /kernel system=Z noconfirm rootdelay=5 console=ttyS0,115200n8 console=tty0 vm_hv_type=VMware
initrd /coreboot.img
}
使用findaes工具对内存文件扫描获取的密钥,这里的密钥就是从系统A分区的内存中得到的
PS C:\Users\admin\Documents\Virtual Machines\ivanti> findaes.exe .\ivanti-ce6dee15.vmem
Searching .\ivanti-ce6dee15.vmem
Found AES-256 key schedule at offset 0xa511916c:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
...
Found AES-256 key schedule at offset 0xf4586070:
f1 a8 aa 2b cc 4f d4 66 53 73 eb 56 81 d7 b7 9e 65 ec 1b 8e bf b9 2f 7d 71 c7 da 8e 80 95 91 72
Found AES-128 key schedule at offset 0xf4c6a040:
e1 fc 5e b7 d8 41 58 da ba d8 eb bc f6 cd 2a 18
构造一个python脚本来对密码进行匹配
import re
import subprocess
import binascii
import os
TARGET_DEVICES = [
"/dev/mapper/groupA-home" ,
"/dev/mapper/groupA-runtime" ,
"/dev/mapper/groupZ-home"
]
def parse_keys_from_log (filepath ):
"""从 findaes 日志中提取并清洗出有效的唯一 AES 密钥"""
valid_keys = set ()
hex_pattern = re.compile (r'^([0-9a-f]{2}(?: [0-9a-f]{2})+)$' , re.IGNORECASE)
if not os.path.exists(filepath):
print (f"[-] 找不到密钥文件: {filepath} " )
return []
with open (filepath, 'r' ) as f:
for line in f:
line = line.strip()
if hex_pattern.match (line):
if '00 01 02 03' not in line:
clean_hex = line.replace(' ' , '' )
valid_keys.add(clean_hex)
return list (valid_keys)
def test_device (device, keys ):
"""针对单个设备测试所有密钥"""
if not os.path.exists(device):
print (f"[-] 警告: 目标设备 {device} 不存在,跳过。" )
return False
mapper_name = f"decrypted_{os.path.basename(device)} "
tmp_key_file = f"/tmp/test_key_{os.path.basename(device)} .bin"
print (f"\n[*] 开始测试设备: {device} (共 {len (keys)} 个候选密钥)" )
for hex_key in keys:
try :
with open (tmp_key_file, 'wb' ) as f:
f.write(binascii.unhexlify(hex_key))
cmd = [
'cryptsetup' , 'luksOpen' , device, mapper_name,
'--master-key-file' , tmp_key_file
]
result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if result.returncode == 0 :
print (f"[+] 破解成功! 设备 {device} 的 Master Key 是:" )
print (f" {hex_key} " )
print (f"[+] 已成功挂载到: /dev/mapper/{mapper_name} " )
os.remove(tmp_key_file)
return True
except Exception as e:
continue
print (f"[-] 匹配失败: 没有任何提取的密钥可以解密 {device} 。" )
if os.path.exists(tmp_key_file):
os.remove(tmp_key_file)
return False
def main ():
key_log_file = "keys.txt"
print ("[*] 正在解析内存提取的密钥日志..." )
keys = parse_keys_from_log(key_log_file)
if not keys:
print ("[-] 未能提取到有效的十六进制密钥,请检查 keys.txt 文件内容。" )
return
print (f"[*] 成功清洗并提取了 {len (keys)} 个唯一的有效候选密钥。" )
for target in TARGET_DEVICES:
test_device(target, keys)
if __name__ == "__main__" :
main()
执行脚本后成功把系统A分区的磁盘解密
root@eve:/tmp# python3 1.py
[+] 破解成功! 设备 /dev/mapper/groupA-home 的 Master Key 是:
ef6c94e31dd6093de0d3ab47beeda767a8f66285a4a46f872503462b2ae4a741
[+] 已成功挂载到: /dev/mapper/decrypted_groupA-home
[+] 破解成功! 设备 /dev/mapper/groupA-runtime 的 Master Key 是:
40b15427c2463521f5a972003b66ea905307868a4d72ff02196a31e5e7c0e489
[+] 已成功挂载到: /dev/mapper/decrypted_groupA-runtime
这里解密后将解密后的磁盘进行挂载就可以得到文件系统了
root@eve:/tmp# ls -l /tmp/sda1
total 24
drwxr-xr-x 2 675 511 4096 Oct 5 2024 boot
drwx------ 2 root root 16384 Apr 28 21:43 lost+found
drwxr-xr-x. 25 root root 4096 May 2 01:17 root
root@eve:/tmp# cd sda1/root/
root@eve:/tmp/sda1/root# ls
4.17.00-x86_64 bin boot cgroups conf data dev etc gzip home lib lib64
mnt2 modules pkg proc root run runtime sbin selinux sys tmp usr va
var webserver
拷贝一个支持相同架构的busybox,因为既要有pl脚本输出的内容,也需要后门权限 添加后门(busybox需要权限否则开机时执行不了命令)
system("/sbin/iptables -A INPUT -p tcp --dport 8383 -j ACCEPT" );
system("/home/bin/busybox telnetd -l /bin/sh -p 8383" );
配置完成后卸载已经挂载的磁盘
umount /dev/mapper/decrypted_groupA-home
umount /dev/mapper/decrypted_groupA-runtime
关闭并锁定 LUKS 加密卷
cryptsetup luksClose decrypted_groupA-home
cryptsetup luksClose decrypted_groupA-runtime
直到输出lsblk命令,所有的挂载、解密层和 LVM 逻辑卷已经完美卸载并彻底分离
root@iotseczone:/dev/mapper# lsblk
......
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 513M 0 part /boot/efi
└─sda3 8:3 0 99.5G 0 part /
sdb 8:16 0 80G 0 disk
├─sdb1 8:17 0 102M 0 part
├─sdb2 8:18 0 102M 0 part
├─sdb3 8:19 0 102M 0 part
├─sdb4 8:20 0 1K 0 part
├─sdb5 8:21 0 6.7G 0 part
│ └─groupZ-home 252:0 0 6.7G 0 lvm
├─sdb6 8:22 0 7.3G 0 part
│ ├─groupA-home 252:1 0 4.9G 0 lvm
│ └─groupA-runtime 252:2 0 19.5G 0 lvm
├─sdb7 8:23 0 17G 0 part
│ └─groupA-runtime 252:2 0 19.5G 0 lvm
├─sdb8 8:24 0 7.3G 0 part
├─sdb9 8:25 0 17G 0 part
├─sdb10 8:26 0 7.3G 0 part
└─sdb11 8:27 0 17G 0 part
发现在启动的时候系统会检查脚本文件的完整性
对关键字的搜索找到了该脚本
root@iotseczone:/tmp/sda1/root# find ./ -name "*.sh" | grep -i "integrity"
./home/bin/check_integrity.sh
check_integrity.sh脚本的流程是:
如果要绕过检测的话最直接的办法就是将stopOnError=1改为0
sh-4.2# ps -aux | grep "telnetd"
root 4147 0.0 0.0 1248 32 ? Ss 07:27 0:00 /home/bin/busybox telnetd -l /bin/sh -p 8383
root 4160 0.0 0.0 4516 3020 pts/0 S+ 07:28 0:00 grep telnetd
0x2
通过安装vmlinux-to-elf 工具将kernel文件从原始内核中恢复出完全可分析的.elf文件
root@iotseczone:/home/iotsec-zone# file ./Tools/qemu-images/powerpc/kernel.bin
./Tools/qemu-images/powerpc/kernel.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=61bc74a13bf25e025ff27033a10f7ae939c4c6f2, not stripped
在kernel文件的populate_rootfs函数中使用了基于 512 字节扇区的变异 CBC-MAC 混合加密模式
if ( initrd_start )
{
printk((unsigned int )&unk_FFFFFFFF82055898, v7, v9, v10, v11, v12);
v13 = initrd_start;
v14 = (unsigned int )(initrd_end - initrd_start);
v19 = crypto_alloc_base((__int64)&aVaes[1 ], 0 , 0 );
if ( v19 <= 18446744073709547520uLL )
{
v37[1 ] = HIDWORD(DSRAMFS_AES_KEY) ^ 0xAEEF41FE ;
v37[0 ] = DSRAMFS_AES_KEY ^ 0x99ED2BF2 ;
v37[2 ] = qword_FFFFFFFF81E00168 ^ 0x141058C7 ;
v37[3 ] = HIDWORD(qword_FFFFFFFF81E00168) ^ 0xD2ED180E ;
(*(void (__fastcall **)(unsigned __int64, _DWORD *, __int64))(v19 + 8 ))(v19, v37, 16 );
v20 = 0 ;
while ( v14 > 511 )
{
v14 -= 512LL ;
LODWORD(v38) = v20;
*(_QWORD *)((char *)&v38 + 4 ) = 0 ;
v21 = (_DWORD *)(v13 + (unsigned int )(v20 << 9 ));
v36 = v20 + 1 ;
HIDWORD(v38) = 0 ;
v22 = v21 + 128 ;
(*(void (__fastcall **)(unsigned __int64, _DWORD *, __int128 *))(v19 + 24 ))(v19, v39, &v38);
do
{
*v21 ^= v39[0 ];
v21[1 ] ^= v39[1 ];
v21[2 ] ^= v39[2 ];
v21[3 ] ^= v39[3 ];
v35 = *(_OWORD *)v21;
(*(void (__fastcall **)(unsigned __int64, _DWORD *, _DWORD *))(v19 + 24 ))(v19, v21, v21);
*v21 ^= v38;
v21[1 ] ^= DWORD1(v38);
v21[2 ] ^= DWORD2(v38);
v21[3 ] ^= HIDWORD(v38);
v21 += 4 ;
v38 = v35;
}
while ( v22 != v21 );
v20 = v36;
}
通过对代码的分析和全局变量的提取,生成了一个解密脚本来解密加载到initrd当中的coreboot.img文件,这里的脚本作者就不提供了,希望大家可以根据密钥以及代码可以理解到该如何去解密这个coreboot.img,不是很难!
使用脚本将coreboot.img解密
root@iotseczone:/home/iotsec-zone# python3 1.py
[*] 正在装载终极密钥...
[*] 固件总大小: 40962505 字节
[*] 共探测到 80004 个完整 512 字节扇区,准备实施变异解密...
[*] 检测到尾部 457 字节未对齐数据,按照内核逻辑跳过解密直接追加。
[++++++++++ 内核级还原完成! ++++++++++]
[+] 明文已保存至: coreboo_decrypted.img
[+] 嗅探结果: 标准 GZIP,可直接解压!
解压后成功得到文件系统,查找密钥关键字
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# find ./ -name "*key*"
./etc/lvmkey
查看密钥字节数以及使用十六进制查看它的本身
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# wc -c ./etc/lvmkey
16 ./etc/lvmkey
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# hexdump -C ./etc/lvmkey
00000000 6e 1b d1 c3 48 70 bd 72 d2 31 bd 75 53 7e 6c c3 |n...Hp.r.1.uS~l.|
00000010
当这个密钥在内存当中的时候是32字节,这里却是16字节, 根据关键字对/etc/lvmkey进行搜索发现了在lvm-shlib文件当中luksFormat会生成32字节主卷密钥(这里也体现了cbc混合加密模式,它结合了 AES 加密算法、CBC 工作模式、ESSIV 初始化向量生成技术和 SHA256 哈希算法)
AES:一种对称加密算法
CBC:分组密码工作模式
ESSIV:通过扇区的比那好生成IV的方法 IV:是SN被hash经过加密的结果
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# grep -rnw ./ -e "/etc/lvmkey"
./bin/lvm-shlib:118: echo "y" | $encrypt -q --cipher aes-cbc-essiv:sha256 --key-file /etc/lvmkey luksFormat ${device}
它会在底层调用Linux内核的/dev/urandom,真随机数生成器抓取32字节的极高熵随机数作为硬盘的终极密码
dd if =/dev/zero of=test.img bs=1M count=10
strace -e trace=openat,open,getrandom cryptsetup -q luksFormat test.img
这里通过对进程的跟踪也可以证实这一点
...
Enter passphrase for test.img:
openat(AT_FDCWD, "/usr/lib/ssl/openssl.cnf" , O_RDONLY) = 3
openat(AT_FDCWD, "/dev/urandom" , O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/dev/random" , O_RDONLY|O_NONBLOCK|O_CLOEXEC) = 4
...
+++ exited with 0 +++
使用密钥解锁尝试一下,并把解密后的文件系统挂载出来也是完整的文件系统
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root/etc# cryptsetup luksOpen /dev/mapper/groupA-home pulse_data --key-file /home/iotsec-zone/_123.extracted/cpio-root/etc/lvmkey
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# ls /dev/mapper/
control groupA-home groupA-runtime groupZ-home pulse_data
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# mount /dev/mapper/pulse_data /tmp/sda/
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# ls /tmp/sda/
boot lost+found root
root@iotseczone:/home/iotsec-zone/_123.extracted/cpio-root# ls /tmp/sda/root/
4.17.00-x86_64 bin boot cgroups conf data dev etc gzip home lib lib64 mnt2 modules pkg proc root run runtime sbin selinux sys tmp usr va var webserver
[招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!
最后于 2026-6-4 14:21
被Kris1337编辑
,原因: