在Android开发中,经常需要将少量简单类型数据保存在本地,如:用户设置。这些需要保存的数据可能一两个字符串,像这样的数据一般选择使用SharedPreferences来保存。
一般通过getSharedPreferences()进行信息获取,于此同时一起出现的还会有edit(),putstring()函数

而这种做法会将所有getSharedPreference的字符串都明文存储在安卓机子本身的/data/data/<packagename>/shared_prefs/key.xml文件中,并且所有用户可读
-rw-rw-r--
数据库
数据库SQLite
sqlite数据库通过openOrCreateDatabase
函数进行数据库操作,并且通过execSQL
进行sql语句执行


将使用提供的数据创建数据库文件并将其存储在文件中。/data/data/<package-name>/databases/privateNotSoSecure
openOrCreateDatabase
的第二个参数决定了sqlite存储的文件是否加密
firebase实时数据库
存储数据并将其与 NoSQL 云托管数据库同步。数据存储为 JSON,并实时同步到每个连接的客户端,即使应用程序脱机,数据也保持可用
可以通过进行以下网络调用来识别配置错误的 Firebase 实例:
https://_firebaseProjectName_.firebaseio.com/.json

或者使用firebase scanner
内部存储
当用户卸载应用时,这些文件也会被删除。并且内部存储由沙箱隔离
以下代码片段会将敏感数据持久存储到内部存储。

openFileOutput
函数会将文件保存到本地,而不是在容器内部,并且第二个参数可以设置文件的权限。同理也包括FileInputStream
openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为: Context.MODE_PRIVATE = 0
Context.MODE_APPEND = 32768
Context.MODE_WORLD_READABLE = 1
Context.MODE_WORLD_WRITEABLE = 2
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
外部存储
存储到外部存储(包括SD)的文件是全局可读的,外部存储主要用于在应用程序之间或与PC共享文件。但是由于内存的不足,往往本应该使用内存的空间却使用了而外部存储
当用户卸载应用程序时,存储在应用程序文件夹 (data/data/) 之外的文件不会被删除
File file = new File (Environment.getExternalFilesDir(), "password.txt");
String password = "SecretPassword";
FileOutputStream fos;
fos = new FileOutputStream(file);
fos.write(password.getBytes());
fos.close();
当一个程序的更新配置文件存放在外部存储时,恶意app可以通过修改外部存储的文件,导致其与原本配置不同而带有“恶意”,那么更新配置文件触发时,就会造成恶意
Man-in-the-Disk: A New Attack Surface for Android Apps - Check Point Software
日志
有两个基本类支持日志记录:log、logger
备份
adb backup
应用开发可以使用两个备份api:key/value backup和auto backup for apps,后者上传到google
测试敏感数据的本地存储(MSTG-STORAGE-1 和 MSTG-STORAGE-2)
静态分析
1. 检查读/写外部存储权限:
androidmanifest.xml uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE”
或者是_EXTERNAL_STORAGE
作为关键词

2.检查用于存储数据的关键字和 API 调用的源代码:
文件权限MODE_WORLD_WRITABLE
会导致其他应用可以读取文件
- 类和函数,例如:
- 类(存储键值对)
SharedPreferences
- 类(使用内部或外部存储)
FileOutPutStream
- 功能(使用外部存储)
getExternal*
- 函数(返回用于写入的 SQLiteDatabase )
getWritableDatabase
- 函数(返回一个SQLite数据库进行读取)
getReadableDatabase
- 和函数(使用缓存文件)
getCacheDirgetExternalCacheDirs
- 类(存储键值对)
注意检查本地敏感信息的加密难度
在res/values/strings.xml中或者local.properties 或 gradle.properties
local.properties文件,该文件一般用来存放该Android工程私有的属性配置,比如Android的sdk路径等等。
动态分析
确定 SQLite 数据库是否包含敏感信息/data/data/<package-name>/databases
,确定 SQLite 数据库是否已加密;
shared_prefs是否存在敏感信息
确定敏感存储的数据是否已通过 IPC 机制公开 (MSTG-STORAGE-6)
作为IPC机制,内容提供商可以允许应用的数据被其他程序所更改
静态分析
确定人AndroidManifest.xml中的provider
标签中的tag android:exported 应该设置为false,以及android:permission的权限

通过工具drozer进行xml的渗透分析
测试敏感数据的备份 (MSTG-STORAGE-8)
文件中是否有以下标志:AndroidManifest.xml
android:allowBackup="true"
可以在代码中搜索是否实现了backupAgent、backupagenthelper
测试敏感数据的内存 (MSTG-STORAGE-10)
静态分析
分析源代码确定应用程序组件,因为直接通过内存转储是很难确定数据泄露的位置的,所以需要提前分析敏感文件的数据位于HTTP?、XML?中
EditText
Editable
Editable.Factory
SpannableStringBuilder
StringBuilder
StringBuffer
这几个类都是可能存在内存中敏感数据的 ,以及一些第三方api是否存在明文的情况
动态分析
可以通过fridump转储后进行分析
也可以在运行时使用r2frida进行运行时检查内存,android studio内置的转储工具会自动生成,.hprof文件,然后通过MAT进行分析就好
SELECT * FROM java.lang.String
SELECT toString(object) FROM java.lang.String object
SELECT password FROM ".*" WHERE (null != password)
Comments | NOTHING