你以为上传一张iPhone拍的HEIC照片到网站后台,只是点一下"上传"按钮那么简单?Fortbridge研究团队最近完成的一次实验,可能会让你对这张照片彻底改观——他们仅仅通过一张看似普通的HEIC图片,就在WordPress服务器的PHP-FPM进程里执行了自己的代码。整个过程没有登录密码泄露,没有Web应用防火墙告警,甚至服务器上的一切日志看起来都平平无奇。这不是科幻电影里的桥段,而是一条已经被完整验证的攻击链。
先说清楚一件事:这个漏洞并不是WordPress代码本身的问题,而是藏在它背后那条容易被忽视的"图片处理流水线"里。当用户把HEIC、HEIF或者AVIF格式的图片上传到WordPress媒体库时,系统通常会调用ImageMagick对图片进行尺寸裁剪,生成缩略图和各种规格的衍生图。而ImageMagick又是通过libheif这个库来解析HEIC文件的。问题,就出在这个libheif身上。
整个攻击面其实相当隐蔽。漏洞编号为GHSA-x8r2-mggj-j6wr,影响的是libheif的未压缩图像解码器。恶意图片可以在文件头中声明两个颜色通道,并且故意让这两个通道拥有不同的字节宽度。解码器在为一个通道分配内存时,用的是较小的宽度计算空间,写入数据时却使用了较大的宽度——就像一个只能装10升水的桶,硬要塞进去15升水,多出来的5升水势必会溢出到桶外面。这些溢出的攻击者可控字节,就会覆盖掉内存中相邻的数据结构。
关键在于,溢出的数据会改写一个C++对象引用,进而在解码器进行清理操作时,劫持一次虚函数调用。稍微有点编程基础的人都知道,虚函数表指针(vptr)一旦被控制,程序接下来跳到哪个函数去执行,就完全由攻击者说了算。换句话说,图片解析器本身成了攻击者的"傀儡",它原本该走的清理流程,被悄无声息地替换成了攻击者精心设计的指令路径。
不过,想要在现代Linux服务器上稳定地利用这个漏洞,并不是一件容易的事。如今的操作系统普遍启用了地址空间布局随机化(ASLR),程序运行时内存中的关键地址每次都不一样,攻击者很难提前知道该往哪里跳。Fortbridge的聪明之处在于,他们把整个攻击拆成了两个阶段。第一阶段,先上传一张专门构造的"信息泄露"图片,然后下载WordPress处理完成后的JPEG缩略图,对图片像素进行分析。你可能想不到,这些像素里竟然携带着泄露出来的内存信息——足以让攻击者识别出服务器上运行的libheif具体版本、内存布局特征。拿到这些情报之后,再上传第二张精心定制的触发图片,命中率就大幅提升了。
测试结果足以让人警醒。在实验环境中,全新的Ubuntu PHP-FPM父进程8个里有6个被成功执行了代码,Debian环境下22个父进程成功了24个(实际上是在24次尝试中成功了22次)。执行代码所用的是PHP-FPM服务账户的权限,实验中正是www-data这个账户。也就是说,攻击者一旦得手,就可以直接以Web服务的身份在服务器上为所欲为——读写文件、连接数据库、横向移动,几乎畅通无阻。
需要强调的是,这条攻击链并不是所有WordPress站点都暴露在风险之中,目前也属于实验室验证性质的攻击,并非已经席卷全球的恶意软件疫情。Fortbridge也没有测试未登录访客的匿名上传场景,攻击的前提条件是攻击者拥有一个具备upload_files权限的账号,通常对应作者及以上角色。但这并不意味着你可以高枕无忧——一旦网站允许多人注册投稿,或者某个作者账号被钓鱼盗用,这条路径就是真实存在的。研究团队验证的两组环境配置也很有代表性:一组是Ubuntu 26.04搭配WordPress 7.1.1、PHP-FPM 8.5.4、ImageMagick 7.1.2.18和libheif 1.21.2;另一组是Debian 13搭配WordPress 7.0、PHP-FPM 8.4.24、ImageMagick 7.1.1.43和libheif 1.19.8。这两个软件栈在国内云主机和VPS上都非常常见。
那么,作为网站管理者,现在应该做什么?最直接有效的动作,就是立即升级libheif。GHSA-x8r2-mggj-j6wr影响1.18.0到1.23.2之间的所有版本,官方已经在1.23.3版本中修复了这个问题。另一个相关的信息泄露漏洞GHSA-2jg2-4ch7-h545也在1.23.2版本中得到了修补。这里有一个很多人容易忽略的细节:你以为更新了系统软件包就安全了吗?不一定。很多服务器上的ImageMagick是自行编译安装的,它加载的libheif版本未必和系统包管理器里的版本一致。建议管理员用ldd或者类似工具,实际检查一下ImageMagick进程加载的到底是哪个so文件,版本号是多少,别做"以为修好了"的冤大头。
如果你的网站根本不需要接受HEIC或者AVIF格式——这占了绝大多数WordPress站点——那么最省事的防御措施就是在进入原生解码之前就拦截这些文件格式,从源头上掐断攻击路径。对于有更高安全要求的业务,还可以在自行编译的libheif中直接移除未压缩编解码器支持,把不受信任的媒体处理放进隔离的低权限服务中运行,限制服务器的出站网络访问,并且把数据库密码、API密钥这类敏感配置严格隔离在图片处理进程之外。
应急响应方面也有值得留意的信号。如果你发现服务器上的PHP-FPM工作进程在HEIC文件上传之后频繁异常退出,同时伴随HTTP 503错误响应,那就要打起十二分精神了。尤其当这些HEIC文件中包含unci、iden、crop、overlay或者grid这类结构标签时,基本可以判定有人在踩点或者已经开始了利用尝试。有安全团队还可以关注一下Fortbridge在验证过程中留下的入侵指标——验证链会在代码执行成功后生成一个名为rce-proof.txt的文件,这可以作为排查历史日志和文件系统时的重要线索。
其实回头来看,这次事件最值得深思的并不是某个具体漏洞,而是它暴露出来的一类系统性风险:服务器端的图片处理流程,长期以来都是被安全审查遗忘的角落。从早年间的WordPress Imagick上传漏洞,到最近接二连三的ImageMagick远程代码执行案例,都在反复提醒我们同一个道理——只要数据会被转换成另一种格式,这个转换过程本身就是危险的边界。一张图片背后,可能藏着一整套解码器、内存分配器、虚函数表的精密世界,而攻击者对这个世界的理解,往往比防守方深刻得多。
图片上传不该再被视为一种"无害的用户行为"。在今天这个时代,每一张进入服务器的图片,都应该像对待一段可执行代码那样,保持必要的警惕。