乐于分享
好东西不私藏

一张图片就能黑掉你的电脑——LogoFAIL漏洞到底怎么攻破BIOS的

一张图片就能黑掉你的电脑——LogoFAIL漏洞到底怎么攻破BIOS的

一张图片就能黑掉你的电脑——LogoFAIL漏洞到底怎么攻破BIOS的

你以为开机Logo只是一张图?解析这张图的代码跑在DXE阶段,权限比操作系统还高。如果有人在这张图里藏了恶意代码,你的杀毒软件还睡着呢。

📖 本文速览

  • 2023年曝光的LogoFAIL漏洞(CVE-2023-40230):通过一张精心构造的JPEG图片,在操作系统启动前攻破BIOS
  • 攻击目标不是安全模块,而是开机Logo的图片解析器——一个几乎没人审计的代码路径
  • 多家OEM厂商中招,根因是自研JPEG解码器缺乏边界检查
  • 本文从BIOS工程师视角拆解完整攻击链:Logo加载 → 解析溢出 → 代码执行 → 持久化植入

一、🎯 开机Logo——固件里最不起眼的攻击面

按下电源键,屏幕上弹出品牌Logo,你从来没多看过它一眼。

但如果你是BIOS工程师,你应该多看两眼。因为显示这个Logo的代码,跑在DXE阶段——这时候CPU已经切到保护模式、内存初始化完毕、可以跑C代码了,但操作系统还没加载,所有安全软件都还没启动。

换句话说:Logo解析代码运行在一个没有任何防护的特权环境里。

Logo显示的大致流程:

BDS阶段  → 从Firmware Volume或ESP分区读取Logo文件    → 判断格式(BMP/JPEG/PNG)      → 调用对应解码器        → 转换像素格式          → Blt到FrameBuffer            → 屏幕显示

核心代码位置:MdeModulePkg/Logo/Logo.c

// 简化版Logo加载逻辑EFI_STATUS LoadLogo(IN IMAGE_ENTRY *Image) {    // 从Firmware Volume读取Logo图片    Status = GetSectionFromFv(Image, &LogoBuffer, &LogoSize);    // 判断格式,调对应的解码器    if (IsBMP(LogoBuffer)) {        DecodeBMP(LogoBuffer, LogoSize, &Pixels);    } else if (IsJPEG(LogoBuffer)) {        DecodeJPEG(LogoBuffer, LogoSize, &Pixels);  // ← 攻击点    }    // 画出像素    GraphicsOutput->Blt(GraphicsOutput, Pixels, ...);}

问题来了:这个JPEG解码器是谁写的?安全审计过吗?

答案是——大部分OEM用的是第三方图形库或自研解码器,几乎没人做过安全审计。大家都觉得"就是个显示图片的功能,能出什么问题?"

LogoFAIL的回答是:能出大问题。


二、💥 CVE-2023-40230:一张图的精准打击

2023年12月,安全研究团队Binarly REsearch在Black Hat Europe上公布了LogoFAIL漏洞集。其中CVE-2023-40230是最典型的一个:

某些OEM固件的JPEG解码器存在堆缓冲区溢出,通过精心构造的JPEG图片可以在DXE阶段获得任意代码执行。

打个比方:你家的门锁是银行级别的(Secure Boot),但后门有个狗洞(Logo解析器),谁都能钻进来。

攻击路径非常直接:

第1步:把恶意JPEG写入ESP分区(EFI System Partition)第2步:修改NVRAM变量,指向恶意Logo文件路径        (某些OEM连路径都硬编码了,直接放到 \EFI\OEM\Logo\bootlogo.jpg 就行)第3步:重启——固件在DXE阶段"加载Logo",解析→溢出→Shellcode执行第4步:攻击者的代码获得DXE权限,比操作系统还高一级

为什么ESP分区可写?因为Windows下ESP默认不挂载,但用一行命令就能挂上:

mountvol S: /S        # 挂载ESP到S盘copy evil.jpg S:\EFI\Boot\logo.jpg

更离谱的是,某些OEM连NVRAM都不用改——Logo路径在固件里硬编码,直接读取\EFI\OEM\Logo\bootlogo.jpg。攻击者不需要研究怎么改NVRAM,把恶意文件放对路径就行。


三、🔍 为什么图形解析是软肋?

我做BIOS代码审查时,图形相关的代码是最容易被跳过的模块。原因很简单:它不涉及安全功能,评审者觉得"就是显示个图而已"。

但实际上,图形解析库的复杂度和风险远超想象:

格式
解析复杂度
常见实现
攻击面
BMP
低(几乎就是像素数组)
自研
小
JPEG
中(Huffman解码、IDCT)
libjpeg-turbo / 自研
大
PNG
高(zlib解压、过滤)
libpng / 自研
很大
GIF
中(LZW解码)
自研
大
BMP (RLE)
中(RLE解码)
自研
中

自研的图形解析器几乎一定有bug。libjpeg-turbo这种成熟的开源库相对安全——但OEM需要在固件包里集成它,而固件包的ROM空间寸土寸金,很多OEM选择自己写个简陋的JPEG解码器——省空间,但要命。

这就像你为了省钱不装防盗窗,结果小偷从窗户进来了。


四、⛓️ 从Logo文件到代码执行的完整攻击链

攻击者要实现代码执行需要过四关:

第一关:触发溢出

构造一张"合法"的JPEG文件——能通过基本的文件头检查,但在Huffman表或量化表中嵌入超长数据。简陋的解码器不会检查表的大小上限。

正常JPEG的Huffman表:256个槽位恶意JPEG的Huffman表:声称有16383个条目自研解码器的处理:直接读,不检查上限 → 堆溢出

第二关:控制执行流

溢出覆盖返回地址或函数指针。DXE阶段的调用栈比较固定(没有ASLR,没有栈随机化),攻击者可以通过分析固件镜像确定精确偏移。

这跟传统软件漏洞利用的不同之处:固件里没有ASLR、没有DEP、没有Stack Cookie。一旦溢出,攻击者几乎可以100%控制执行流。

第三关:Payload执行

Shellcode跑起来后能做什么?常见目标:

  • 写一个恶意UEFI驱动进NVRAM
    ,下次启动自动加载
  • 篡改Secure Boot的db/dbx变量
    ,让合法签名失效
  • 注入OS Loader的hook
    ,在加载Windows前植入内核级后门
  • 直接写SPI Flash
    ——对,DXE阶段Flash是可写的,写入后重启也清不掉

第四关:恢复Logo显示

高级攻击者不会让屏幕蓝屏或卡死——那样太明显。溢出后会恢复Logo的正常显示,用户完全感知不到。

你按下电源键,看到熟悉的品牌Logo,正常进系统。没有任何异常。但你的BIOS已经被植入了后门。


五、📋 Binarly的真实发现:比你想象的更糟

Binarly团队在2023年详细研究了几家OEM的Logo解析器,发现的问题五花八门:

厂商
解析器
漏洞
严重程度
厂商A
自研BMP
颜色表大小字段未校验,int溢出导致4字节分配后拷贝几千字节
严重
厂商B
自研JPEG
Huffman表条目数从文件读取,上限没检查,能读到16383
严重
厂商C
libpng(2009版)
至少20个已知CVE,从未升级
严重
厂商D
自研JPEG
量化表精度字段未校验,导致越界写
高危

最离谱的是:同一个OEM的不同型号产品,有的用libjpeg-turbo(安全),有的用自研解码器(不安全)。因为不同项目组独立开发,没统一规范。你买的上一代产品是安全的,下一代反而变不安全了。


六、🛡️ 防御:不是换个图的问题

短期止血

  • 把所有自研Logo解析器换成成熟的开源库(libjpeg-turbo / libpng)
  • Logo文件只能从固件卷(FV)加载,禁止从ESP分区读取
  • 解析前验证文件大小、图像尺寸的上限

中期加固

  • PEI/DXE阶段的代码启用栈保护(Stack Cookie / Stack Guard)
  • 图形解析代码跑在隔离的执行环境中(类似SMM的sandbox)
  • 启用Intel CET(Control-flow Enforcement Technology),硬件级阻止ROP攻击

长期方案

  • 固件的驱动程序模型改进——Logo驱动崩溃不应该影响安全策略
  • UEFI规范增加"不可信数据处理模块"的隔离要求
  • OEM建立统一的第三方库管理规范、统一版本、统一审计

七、💡 老兵忠告

1. 别信任何来自固件外部的输入。

Logo文件也是外部输入——它可能来自用户替换、OEM定制工具修改、甚至供应链环节植入。任何"这只是个数据文件"的想法,都是攻击者的机会。

2. 图形库的安全审计要比安全模块更严格。

因为解析复杂数据格式的代码天然更容易出bug。一个JPEG解码器的代码量可能比你整个Secure Boot实现还多。

3. 测试时别只测"正常图片"。

用AFL等fuzz工具生成畸形图片往Logo路径塞,看固件会不会崩。如果崩了,恭喜你发现了一个潜在CVE。

4. 最简单的防御:只用BMP。

BMP是像素数组,几乎不需要解析。如果你家BIOS不需要花哨的开机动画,把JPEG/PNG的支持关掉。简单即安全。


八、🎯 LogoFAIL教给了行业什么

LogoFAIL教给行业最重要的一课:

固件的攻击面不只在安全模块里——任何处理外部数据的代码都是攻击面。

你花三年打磨Secure Boot,精心设计信任链,结果被一张JPEG图片打穿了。

这笑话不好笑。但它是真的。


📌 固件笔记 · 笔记本BIOS老兵实战记录

相关学习资料