介绍

#

我们偶尔会收到关于 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 的情况提交具体报告(见下文),但实际上统一将所有 malloc 调用替换为 calloc 是不合适的。

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

#

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

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

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

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

CBC 与 PKCS5/PKCS7 填充漏洞

#

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

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

应用可以读写外部存储

#

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

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

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

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

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

#

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

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

已过时的问题

#

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

栈应设置 NX 位

#

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

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

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

报告实际问题

#

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