跳至主要内容

安全误报

简介

#

我们偶尔会收到关于 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 时,您可以创建易受攻击的代码,但假设它与本身正确使用 RELRO 的 C 代码一起使用,则 Dart FFI 的正常使用也不会容易受到这些问题的影响。

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

#

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

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

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

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

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

代码应避免使用 _sscanf_strlen_fopen API

#

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

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

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

#

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

内存分配是一个细致入微的话题,需要在性能和对漏洞的抵御能力之间做出权衡。仅仅使用 malloc 并不自动表示存在安全漏洞。虽然我们欢迎针对使用 calloc 比较好的情况的具体报告(请参见下文),但在实践中,统一将所有 malloc 调用替换为 calloc 将是不合适的。

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

#

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

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

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

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

使用 PKCS5/PKCS7 填充的 CBC 漏洞

#

我们收到了模糊的报告,称某些 Flutter 包中存在“带有 PKCS5/PKCS7 填充的 CBC 漏洞”。

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

应用可以读取和写入外部存储

#

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

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

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

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

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

#

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

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

过时的关注点

#

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

栈应将其 NX 位设置为已设置

#

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

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

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

报告真实问题

#

虽然自动化漏洞扫描工具会报告诸如上述示例之类的误报,但我们不能排除存在需要引起更多关注的实际问题。如果您发现您认为是合法安全漏洞的问题,我们恳请您报告。