安全误报

简介

我们偶尔会收到 Dart 和 Flutter 应用程序中安全漏洞的错误报告,这些报告是由为其他类型的应用程序(例如,用 Java 或 C++ 编写的应用程序)构建的工具生成的。本文档提供了我们认为不正确的报告的信息,并解释了为什么这些疑虑被误放。

常见疑虑

共享对象应使用强化的函数

共享对象没有任何强化函数。强化函数针对 glibc 的常用不安全函数(如 strcpygets 等)提供缓冲区溢出检查。使用编译器选项 -D_FORTIFY_SOURCE=2 来强化函数。

当这引用已编译的 Dart 代码(例如 Flutter 应用程序中的 libapp.so 文件)时,此建议是错误的,因为 Dart 代码不会直接调用 libc 函数;所有 Dart 代码都会通过 Dart 标准库。

(通常,MobSF 在此处会得到误报,因为它会检查任何带有 _chk 后缀的函数的使用情况,但由于 Dart 根本不使用这些函数,因此它没有带有或不带有后缀的调用,因此 MobSF 将代码视为包含非强化调用。)

共享对象应使用 RELRO

未找到 libapp.so 二进制文件的 RELRO

Dart 根本不使用正常的过程链接表 (PLT) 或全局偏移表 (GOT) 机制,因此重定位只读 (RELRO) 技术对 Dart 来说并没有多大意义。

Dart 的 GOT 等效项是池指针,与 GOT 不同,它位于随机位置,因此更难利用。

原则上,在使用 Dart FFI 时,你可以创建易受攻击的代码,但正常使用 Dart FFI 也不会容易出现这些问题,假设它与本身正确使用 RELRO 的 C 代码一起使用。

共享对象应使用堆栈金丝雀值

未找到 libapp.so 二进制文件的金丝雀

此共享对象没有将堆栈金丝雀值添加到堆栈。堆栈金丝雀用于检测和防止利用覆盖返回地址。使用选项 -fstack-protector-all 来启用堆栈金丝雀。

Dart 不生成堆栈金丝雀,因为与 C++ 不同,Dart 没有堆栈分配的数组(C/C++ 中堆栈破坏的主要来源)。

在编写纯 Dart(不使用 dart:ffi)时,你已经拥有比任何 C++ 缓解措施都能提供的更强的隔离保证,仅仅是因为纯 Dart 代码是一种托管语言,其中不存在缓冲区溢出等问题。

原则上,在使用 Dart FFI 时,你可以创建易受攻击的代码,但正常使用 Dart FFI 也不会容易出现这些问题,假设它与本身正确使用堆栈金丝雀值的 C 代码一起使用。

代码应避免使用 _sscanf_strlen_fopen API

二进制文件可能包含以下不安全的 API _sscanf_strlen_fopen

报告这些问题的工具在其扫描中往往过于简单化;例如,找到具有这些名称的自定义函数并假设它们引用标准库函数。Flutter 的许多第三方依赖项具有会触发这些检查的类似名称的函数。某些情况可能是有效问题,但由于误报过多,无法从这些工具的输出中判断。

代码应使用 calloc(而非 _malloc)进行内存分配

二进制文件可能使用 _malloc 函数而非 calloc

内存分配是一个微妙的话题,在性能和抵御漏洞的弹性之间必须进行权衡。仅仅使用 malloc 并不自动表示存在安全漏洞。虽然我们欢迎针对在何种情况下使用 calloc 更可取的具体报告(见下文),但在实践中,用 calloc 统一替换所有 malloc 调用是不合适的。

iOS 二进制文件设置了运行路径搜索路径 (@rpath)

二进制文件设置了运行路径搜索路径 (@rpath)。在某些情况下,攻击者可以滥用此功能来运行任意可执行文件,以执行代码和提升权限。移除编译器选项 -rpath 以移除 @rpath

当构建应用时,运行路径搜索路径是指链接器搜索以查找应用使用的动态库 (dylib) 的路径。默认情况下,iOS 应用将其设置为 @executable_path/Frameworks,这意味着链接器应在应用包内相对于应用二进制文件的 Frameworks 目录中搜索 dylib。与大多数嵌入式框架或 dylib 一样,Flutter.framework 引擎已正确复制到此目录中。当应用运行时,它会加载库二进制文件。

Flutter 应用使用默认 iOS 构建设置 (LD_RUNPATH_SEARCH_PATHS=@executable_path/Frameworks)。

涉及 @rpath 的漏洞不适用于移动设备设置,因为攻击者无法访问文件系统,也无法随意交换这些框架。即使攻击者以某种方式能够用恶意框架替换该框架,该应用程序也会因代码签名违规而在启动时崩溃。

带有 PKCS5/PKCS7 填充的 CBC 漏洞

我们收到一些含糊不清的报告,称某些 Flutter 软件包中存在“带有 PKCS5/PKCS7 填充的 CBC 漏洞”。

据我们所知,这是由 ExoPlayer(com.google.android.exoplayer2.source.hls.Aes128DataSource 类)中的 HLS 实现触发的。HLS 是 Apple 的流媒体格式,它定义了 DRM 必须使用的加密类型;这不是漏洞,因为 DRM 不会保护用户机器或数据,而只是提供混淆以限制用户充分使用其软件和硬件的能力。

应用程序可以读写外部存储

应用程序可以读写外部存储。任何应用程序都可以读取写入外部存储的数据。

与来自任何不受信任来源的数据一样,在处理来自外部存储的数据时,您应该执行输入验证。我们强烈建议您在动态加载之前不要将可执行文件或类文件存储在外部存储中。如果您的应用程序确实从外部存储中检索可执行文件,则在动态加载之前应对文件进行签名并进行加密验证。

我们收到报告称,一些漏洞扫描工具将图像选取器插件读写外部存储的能力解释为威胁。

从本地存储中读取图像就是这些插件的目的;这不是漏洞。

应用程序使用 file.delete() 删除数据

使用 file.delete 删除文件时,仅从文件系统表中删除了对该文件的引用。该文件仍存在于磁盘上,直到其他数据覆盖它,使其容易被恢复。

一些漏洞扫描工具将相机插件从设备相机记录数据后删除临时文件解释为安全漏洞。由于视频是由用户记录并存储在用户硬件上的,因此没有实际风险。

过时的疑虑

本部分包含使用旧版 Dart 和 Flutter 时可能会看到的有效消息,但使用较新版本时应该不再看到。如果您使用旧版 Dart 或 Flutter 看到这些消息,请升级到最新稳定版本。如果您在当前稳定版本中看到这些消息,请报告它们(请参阅本文档末尾的部分)。

堆栈应设置其 NX 位

共享对象未设置 NX 位。NX 位通过将内存页标记为不可执行来提供对利用内存损坏漏洞的保护。使用选项 --noexecstack-z noexecstack 将堆栈标记为不可执行。

(MobSF 的消息具有误导性;它正在寻找堆栈是否标记为不可执行,而不是共享对象。)

在旧版 Dart 和 Flutter 中,有一个错误,ELF 生成器未发出具有 ~X 权限的 gnustack 段,但现在已修复。

报告实际疑虑

虽然自动漏洞扫描工具会报告诸如上述示例之类的误报,但我们不能排除确实存在值得更多关注的实际问题。如果您发现您认为是合法安全漏洞的问题,我们将非常感谢您报告它