Skip to content

Latest commit

 

History

History
846 lines (543 loc) · 30.8 KB

File metadata and controls

846 lines (543 loc) · 30.8 KB

五、数据存储及其安全

本章介绍了通常用于评估 Android 应用数据存储安全性的技术。我们将从利用人员在本地存储数据时使用的不同技术以及它们如何影响安全性开始。然后,我们将研究利用人员所做的数据存储选择的安全含义。

以下是我们将在本章中讨论的一些主要主题:

  • 什么是数据存储?
  • 共享首选项
  • SQLite 数据库
  • 内部存储器
  • 外部存储器
  • 用 CouchDB 存储数据
  • 基于备份的技术
  • 检查非根设备上的 Android 应用

什么是数据存储?

Android 使用类 Unix 文件系统在本地存储数据,Android 上使用了十几个文件系统,如 FAT32、EXT 等。

由于 Android 中的一切都是一个文件,我们可以使用以下命令在/proc/filesytems中查看文件系统的详细信息:

C:\> adb shell cat /proc/filesystems

What is data storage?

典型的根文件系统如以下屏幕截图所示:

What is data storage?

Android 存储了大量关于文件系统的详细信息,如本机应用、通过 Play Store 安装的应用等,任何人都可以通过物理访问该设备,轻松收集大量敏感信息,如照片、密码、GPS 位置、浏览器历史记录和/或公司数据。

应用创建者应安全存储数据,否则将对用户、数据产生不利影响,并可能导致严重的攻击。

让我们简要地研究一下文件系统上的重要目录,并了解它们的重要性:

  • /data: Stores app data, /data/data is used to store the app related private data like shared preferences, cache, third-party libraries, and so on. A typical app stores the following information when installed:

    What is data storage?

    注意:只有特定用户,在我们的例子中是u0_a93,才能访问此目录,其他应用无法访问此目录。

  • /proc:存储与流程、文件系统、设备等相关的数据。

  • /sdcard:用于增加存储容量的 SD 卡。在三星设备中,它通常是一个内部设备,ExtSD 卡用于引用外部 SD 卡。它对于大型文件(如视频)非常有用。

安卓本地数据存储技术

Android 为利用者提供了以下不同的应用数据存储方式:

  • 共享首选项
  • SQLite 数据库
  • 内部存储器
  • 外部存储器

除外部存储器外,数据存储在/data/data中的应用目录下,该目录包含缓存、数据库、文件和共享首选项文件夹。每个文件夹存储与应用相关的特定类型的数据:

  • shared_prefs-使用 XML 格式存储应用的首选项
  • lib-保存应用需要/导入的库文件
  • databases-包含 SQLite 数据库文件
  • files-用于存储与应用相关的文件
  • cache-包含缓存文件

共同偏好

共享首选项是用于将应用的非敏感首选项存储为键值对的 XML 文件,通常类型为booleanfloatintlongstring

SQLite 数据库

SQLite 数据库是在移动环境中常用的基于文件的轻量级数据库。SQLite 框架也受到 Android 的支持,因此您经常可以找到使用 SQLite 数据库满足存储需求的应用。由于 Android 实施的安全限制,设备上的其他应用默认无法访问存储在特定应用的 SQLite 数据库中的数据。

内部存储

内部存储器,也称为设备的内部存储器,用于将文件保存到内部存储器中。它提供了一个快速响应内存访问请求,因为它的直接访问和几乎所有的应用相关的数据都在这里使用,逻辑上它是一个手机硬盘。每个应用在安装期间在/data/data/<app package name>/下创建自己的目录,该目录是该应用的专用目录,其他应用无权访问该目录。当用户卸载应用时,此目录将被清除。

外部存储器

外部存储是安卓世界可写可读的存储机制,用于存储文件。任何应用都可以访问此存储来读取和写入文件,由于这些原因,敏感文件不应存储在此处。必须在AndroidManifest.xml中指定适当的权限才能执行操作。

让我们使用以下命令安装演示应用:

adb install <name of the apk>.apk

External storage

安装后,此应用在/data/data/org.owasp.goatdroid.fourgoats下创建以下文件,主屏幕如下图所示。您可以使用joegoat/goatdroid凭据登录此应用:

External storage

如前所述,分析这些目录可以为我们提供一些有趣的信息:

External storage

共同偏好

让我们启动 FourGoals 应用,并使用注册选项注册新用户。创建后,使用凭证登录,我使用用户名testtest作为其密码,如下所示:

Shared preferences

共享首选项是使用SharedPreferences类创建的。下面是一段用于在credentials.xml文件中存储用户名和密码的代码:

public void saveCredentials(String paramString1, String paramString2)
  {
    SharedPreferences.Editor localEditor = getSharedPreferences("credentials", 1).edit();
    localEditor.putString("username", paramString1);
    localEditor.putString("password", paramString2);
    localEditor.putBoolean("remember", true);
    localEditor.commit();
  }

如前所述,应用目录存储共享首选项:

/data/data/<package name>/shared_prefs/<filename.xml>

那么,让我们浏览并检查上面的路径,看看在这个应用中是否创建了任何共享首选项:

Shared preferences

正如我们在前面的屏幕截图中看到的,有一个名为shared_prefs的文件夹,其中包含三个 XML 文件。Credentials.xml似乎是一个有趣的偏好名称。让我们使用“cat credentials.xml命令查看其内容:

Shared preferences

如果您不习惯使用 shell,可以使用以下命令将详细信息拉到系统中,并在您选择的文本编辑器中打开它:

$adb pull /data/data/org.owasp.goatdroid.fourgoats/shared_pres/credentials.xml

真实世界的应用演示

OWASP FourGoals 应用是一个演示应用,读者可能会认为人们不会在共享首选项中存储敏感信息。让我们使用一个名为 WhatsApp lock 的应用来查看此漏洞的真实示例;该应用使用 PIN 锁定 WhatsApp、Viber 和 Facebook 等著名应用。

主屏幕的屏幕截图如下所示:

Real world application demo

让我们使用 GUI 应用Droid Explorer来浏览和查看此应用的/data/data目录。

以下是使用 Droid Explorer 提取共享首选项的步骤:

  1. 将 Android 设备连接到机器。

  2. Launch Droid Explorer and browse to the whatsapplock directory:

    Real world application demo

  3. Select the Copy to Local Computer option which is available just above the Help menu. Once copied, open the XML file in any text editor of your choice:

    Real world application demo

正如您所看到的,密码是明文的,如果您提供机密问题,它会以明文显示密码。

此应用还具有 PIN 恢复功能,可以恢复忘记的 PIN 码。但是,您需要提供这个秘密问题的答案。秘密问题及其答案再次方便地存储在shared_prefsXML 文件中。

Real world application demo

正如您所见,一旦您提供了机密问题的答案,它将显示应用使用的当前 PIN。

SQLite 数据库

SQLite 数据库是基于文件的轻量级数据库。它们通常有扩展名.db.sqlite。Android 提供了对 SQLite 数据库的全面支持。应用中的任何类都可以访问我们在应用中创建的数据库。其他应用无法访问它们。

以下代码片段显示了在 SQLite 数据库user.db中存储用户名和密码的示例应用:

String uName=editTextUName.getText().toString();
String passwd=editTextPasswd.getText().toString();

context=LoginActivity.this;
dbhelper = DBHelper(context, "user.db",null, 1);
dbhelper.insertEntry(uName, password);

在编程方面,我们正在扩展SQLiteOpenHelper类以实现insertread方法。我们正在将来自用户的值插入一个名为USER的表中:

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper
{
  String DATABASE_CREATE = "create table"+" USER "+"(" +"ID "+"integer primary key autoincrement,"+ "uname text,passwd text); ";
  public  SQLiteDatabase db;

  public  SQLiteDatabase getDatabaseInstance(){
    return db;
  }

  public DBHelper(Context context, String name,CursorFactory factory, int version){
    super(context, name, factory, version);
  }

  public void onCreate(SQLiteDatabase db){
    db.execSQL(DATABASE_CREATE);

  }

  public insertEntry(String uName,String Passwd){ 
    ContentValues userValues = new ContentValues();
    userValues.put("uname", uName);
    userValues.put("passwd",passwd);
    db.insert("USER",null,userValues);
  }
}

有了这些信息,让我们继续看看它是如何存储在文件系统中的。Android 应用中存储数据库的位置如下:

/data/data/<package name>/databases/<databasename.db>

因此,让我们浏览并检查应用的上述路径,以查看是否在此应用中创建了任何数据库。程序与SharedPreferences相同,您可以使用adb pull命令拉取文件,也可以使用桌面上的 Droid Explorer。

在我的例子中,我已经导航到/data/data/com.example.sqlitedemo,然后进入databases/,在那里我们有数据库user.db。我们可以将其拉到机器上,如前一屏幕截图所示,然后执行以下步骤:

  1. 使用 Droid Explorer 拉取user.db文件。

  2. 打开 SQLite 浏览器,将user.db文件拖放到浏览器窗口中。

  3. Browse and view the data by double clicking:

    SQLite databases

如您所见,user.db用于存储 android 应用的用户名和密码。

内部存储

内部存储是 Android 应用中存储数据的另一种方式,通常在/data/data/<app name>下的文件目录中。

下面的代码显示了如何使用内部存储器存储应用的私钥,用于存储和发送用户的信用卡和 SSN 号码:

            String publicKeyFilename = "public.key";
            String privateKeyFilename = "private.key";

        try{
            GenerateRSAKeys generateRSAKeys = new GenerateRSAKeys();
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            // Generate public & private keys
 KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");

            //create base64 handler
            BASE64Encoder b64 = new BASE64Encoder();

            //Create random number
            SecureRandom rand = secureRandom();
            generator.initialize(2048, rand);

            //generate key pair
            KeyPair keyPair = generator.generateKeyPair();
            Key publicKey = keyPair.getPublic();
            Key privateKey = keyPair.getPrivate();

            FileOutputStream fos = null;

            try {
                fos = openFileOutput(publicKeyFilename, Context.MODE_PRIVATE);
 fos.write(b64.encode(publicKey.getEncoded()));
                fos.close();

                fos = openFileOutput(privateKeyFilename, Context.MODE_PRIVATE);
 fos.write(b64.encode(privateKey.getEncoded()));
                fos.close();

            } 
            catch (FileNotFoundException e){
                    e.printStackTrace();
            }
            catch (IOException e){
                    e.printStackTrace();
            }    
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

正如我们在前面的屏幕截图中所看到的,私钥被不安全地存储在文件下的private.key文件中。

让我们打开 Droid Explorer(或使用adb pull命令),将私钥从设备复制到机器,并在文本编辑器中打开:

Internal storage

外部存储器

android 中另一个重要的存储机制是 SD 卡或外部存储,应用可以在其中存储数据。一些著名的应用将数据存储在外部存储器中。在 SD 卡上存储数据时应小心,因为 SD 卡是世界上可写和可读的,或者最好只是将 SD 卡从设备上卸下。然后我们可以将其安装到另一个设备上,以便我们访问和读取数据。

让我们使用前面的示例,应用现在将其存储在外部存储器(即 SD 卡)上,而不是存储在内部存储器中:

            String publicKeyFilename = public.key;
            String privateKeyFilename = private.key;

        try{
            GenerateRSAKeys generateRSAKeys = new GenerateRSAKeys();
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            // Generate public & private keys
 KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");

            //create base64 handler
            BASE64Encoder b64 = new BASE64Encoder();

            //Create random number
            SecureRandom rand = secureRandom();
            generator.initialize(2048, rand);

            //generate key pair
            KeyPair keyPair = generator.generateKeyPair();
            Key publicKey = keyPair.getPublic();
            Key privateKey = keyPair.getPrivate();

            FileOutputStream fos = null;

            try {
                //save public key
 file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/vulnApp/",publicKeyFilename);
                fos = new FileOutputStream(file);
                fos.write(b64.encode(publicKey.getEncoded()));
                fos.close();

                //save private key
 file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/vulnApp/",privateKeyFilename);
                fos = new FileOutputStream(file);
                fos.write(b64.encode(privateKey.getEncoded()));
                fos.close();

            } 
            catch (FileNotFoundException e){
                    e.printStackTrace();
            }
            catch (IOException e){
                    e.printStackTrace();
            }    
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

我们可以看到,这个应用使用Environment.getExternalStorageDirectory()将私钥保存在 SD 卡的vulnapp目录中。因此,任何恶意应用都可以读取此密钥并将其发送到 Internet 上的某个远程服务器。

为了让应用能够访问外部存储,前面的代码需要在AndroidManifest.xml文件中有WRITE_EXTERNAL_STORAGE权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

用户字典缓存

用户词典是大多数移动设备中非常方便的功能。这是用来让你的键盘记住经常键入的单词。当我们在键盘上输入一个特定的单词时,它会自动提供一些建议。Android 也有这一功能,它将经常使用的单词存储在一个名为user_dict.db的文件中。因此,利用人员在利用应用时必须谨慎。如果 Android 应用中输入的敏感信息被允许缓存,任何人都可以通过浏览设备上的user_dict.db文件或使用其内容提供商 URI 来访问这些数据。

由于使用用户词典应用的内容提供者的任何应用都可以访问用户词典,因此,阅读用户词典并收集有趣的信息对用户来说是微不足道的。

正如我们对其他.db文件所做的一样,让我们从设备中拉出user_dict.db数据库文件,并用 SQLite 浏览器打开它:

c:>adb pull /data/data/com.android.providers.userdictionary/databases/user_dict.db
477 KB/s (16384 bytes in 0.033s)

前面的命令从设备中提取数据库文件并将其存储在当前目录中:

User dictionary cache

前面的屏幕截图显示了应用在user_dict.db文件中存储的敏感信息。

数据存储不安全–NoSQL 数据库

NoSQL 数据库目前正被广泛使用。企业广泛采用 NoSQL 数据库,如 MongoDB、CouchDB 等。这些数据库也支持移动应用。与任何其他本地存储技术类似,当使用 NoSQL 数据库以不安全的方式存储数据时,可能会被利用。本节将介绍有关不当使用 NoSQL 数据库如何导致不安全数据存储漏洞的概念。

让我们使用一个示例应用来研究这个漏洞。

NoSQL 演示应用功能

了解应用的功能对于了解其风险非常重要,并使我们能够发现应用的风险。

让我们看看一个类似于密码保险库的示例应用。然后,用户提供的数据存储在 NoSQL 数据库的表单文档中。

下面是用于构建演示应用的代码段:

String databaseName = "credentials";

Database db;

Manager manager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS);

try {
  db = manager.getDatabase(databaseName); 

}
catch (CouchbaseLiteException e){
  return;
}

String username=editTextUName.getText().toString();
String password=editTextPasswd.getText().toString();
String serviceName+=editTextService.getText().toString();

Map<String, Object> data = new HashMap<String, Object>();

data.put("username",username);

data.put("password",password);

data.put("service",serviceName);

Document document = db.createDocument();

try {

  document.putProperties(data);

} 

catch (CouchbaseLiteException e) {
  return;
}

上面的代码使用HashMap保存要存储在 NoSQL 数据库中的名称-值对。

让我们使用以下命令在 android 设备上安装此应用:

C:\> adb install nosqldemo.apk

安装后,让我们在其中插入一些用户名和密码数据。让我们打开 adb 外壳并访问data目录,查看凭证存储的位置:

cd data/data/

在我们的例子中,应用的安装目录位于com.example.nosqldemo。让我们cd进入它,分析它的文件系统,寻找一些有趣的文件:

cd com.example.nosqldemo

运行ls命令将提供以下输出:

root@t03g:/data/data/com.example.nosqldemo # ls
cache
files
lib

NoSQL 是一种数据库技术,因此我们希望看到数据库目录,但是,我们只看到files目录。缺少数据库目录的原因是Couchbase使用文件目录存储数据库文件。

因此,让我们导航到文件目录,再次查看其中的文件:

root@t03g:/data/data/com.example.nosqldemo/files # ls
credentials
credentials.cblite
credentials.cblite-journal
root@t03g:/data/data/com.example.nosqldemo/files #

Couchbase 使用.cblite扩展名存储其文件,因此credentials.cblite由我们的应用创建。

就像所有其他示例一样,将credentials.cblite文件拉到您的桌面计算机,以分析其是否存在不安全的数据存储:

root@t03g:/data/data/com.example.nosqldemo/files # pwd
/data/data/com.example.nosqldemo/files
root@t03g:/data/data/com.example.nosqldemo/files #
C:\>adb pull /data/data/com.example.nosqldemo/files/carddetails.cblite
1027 KB/s (114688 bytes in 0.108s)

现在我们有了 Couchbase 文件,因为它是文本格式并使用 JSON 存储数据,我们可以使用 strings 命令查看它。Windows 没有 strings 命令,所以我安装了 Cygwin for Windows,然后打开了 Cygwin 终端。

您可以从下载并安装 Cygwinhttps://cygwin.com/install.html

android@laptop ~
$ strings credentials.cblite | grep 'qwerty'
4-3bb12aee5f548c5bf074e507e8a9ac9f{"username":"alice","password":"qwerty","service":"linkedin"}
android@laptop ~

如您所见,用户名和密码以明文形式存储,任何人都可以访问此信息。

如果您不想忍受安装 Cygwin isstrings.exe的痛苦,可以从 sysintranse 或您选择的任何十六进制编辑器中选择另外两个选项。

备份技术

到目前为止,我们所有的示例和演示都在根设备上。我们的一些读者可能会争辩说,没有多少设备是有根的,我们对无根设备也无能为力

在本节中,我们将了解如何使用备份功能检查非根设备上应用的内部内存。对特定应用或设备进行备份可以让我们检查其安全问题。

我们将使用 WhatsApp 锁作为本演示的目标应用;这与我们在共享首选项部分中使用的应用相同:

C:\ >adb pull /data/data/com.whatsapplock/shared_prefs/ com.whatsapplock_preferences.xml
failed to copy '/data/data/com.whatsapplock/shared_prefs/ com.whatsapplock_preferences.xml' to 'com.whatsapplock_preferences.xml': Permission denied

正如您所看到的,我们得到了权限拒绝错误,因为我们的 adb 不是以 root 身份运行的。

现在,让我们使用 android 的备份技术,通过以下步骤查找安全问题:

  1. 使用adb backup命令备份 app 数据。
  2. 使用 android 备份提取器将.ab格式转换为.tar格式。
  3. 使用 pax 或 star 实用程序提取 TAR 文件。
  4. 分析上一步提取的内容是否存在安全问题。

注意:tar 和 7-Zip 等标准工具不支持对abe.jar生成的文件进行反序列化,因为它们不允许存储没有尾部斜杠的目录。

使用 adb Backup 命令备份 app 数据

Android 允许我们使用内置的adb backup命令备份整个手机数据或特定应用数据。

您可以在下面的屏幕截图中看到adb backup命令提供的选项:

Backup the app data using adb backup command

正如我们所看到的,我们有很多选择来调整我们的备份需求。

我们可以使用以下命令备份整个 android 手机:

adb backup –all –shared –apk 

我们还可以使用以下命令仅存储特定的应用:

adb backup -f <filename> <package name>

在我们的情况下,情况如下:

adb backup –f backup.ab com.whatsapplock

运行该命令将提供以下输出:

C:\> adb backup -f backup.ab com.whatsapplock

现在解锁您的设备并确认备份操作。

如我们所见,上面的命令建议我们解锁屏幕并点击设备上的备份我的数据按钮。它还提供了加密备份的设置,如果您希望使用加密,可以键入密码:

Backup the app data using adb backup command

一旦您点击按钮,它将在我们的工作目录中创建一个名为backup.ab的新文件:

C:\backup>dir
 Volume in drive C is System
 Volume Serial Number is 9E95-4121

 Directory of C:\backup

25-Jan-16  11:59 AM    <DIR>          .
25-Jan-16  11:59 AM    <DIR>          ..
25-Jan-16  11:59 AM             4,447 backup.ab

C:\backup>

使用 Android 备份提取器将.ab 格式转换为 tar 格式

即使我们已经得到了backup.ab文件,我们也无法直接读取该文件的内容。我们需要首先将其转换为我们能够理解的格式。我们将使用我们最喜欢的工具之一,Android 备份提取器,将我们的.ab文件转换为.tar格式。

让我们从以下 URL 下载Android 备份提取器

http://sourceforge.net/projects/adbextractor/

解压缩 ZIP 文件后,我们将看到以下文件和文件夹:

Convert .ab format to tar format using Android backup extractor

虽然这些文件和文件夹都有一定的用途,但我们只对abe.jar感兴趣。将abe.jar文件复制到我们保存backup.ab文件的备份目录中:

C:\backup>dir
 Volume in drive C is System
 Volume Serial Number is 9E95-4121

 Directory of C:\backup

25-Jan-16  12:03 PM    <DIR>          .
25-Jan-16  12:03 PM    <DIR>          ..
03-Nov-15  01:10 AM         6,167,026 abe.jar
25-Jan-16  11:59 AM             4,447 backup.ab
C:\backup>

让我们通过发出以下命令来查看此工具提供的命令标志:

C:\backup>java -jar abe.jar --help
Android backup extractor v20151102
Cipher.getMaxAllowedKeyLength("AES") = 128
Strong AES encryption allowed, MaxKeyLenght is >= 256
Usage:
 info:   abe [-debug] [-useenv=yourenv] info <backup.ab> [password]
 unpack: abe [-debug] [-useenv=yourenv] unpack <backup.ab> <backup.tar> [password]
 pack:   abe [-debug] [-useenv=yourenv] pack <backup.tar> <backup.ab> [password]
 pack 4.4.3+:    abe [-debug] [-useenv=yourenv] pack-kk <backup.tar> <backup.ab> [password]
 If -useenv is used, yourenv is tried when password is not given
 If -debug is used, information and passwords may be shown
 If the filename is '-', then data is read from standard input or written to standard output

如我们所见,我们可以使用abe.jar打包或解包备份文件。因此,让我们使用解包选项来解包备份文件。正如我们在帮助中看到的,我们需要将目标文件指定为.tar

C:\backup>java -jar abe.jar -debug unpack backup.ab backup.tar
Strong AES encryption allowed
Magic: ANDROID BACKUP
Version: 1
Compressed: 1
Algorithm: none
116224 bytes written to backup.tar

如上图所示,备份文件被转换为 TAR 文件,并且应该存在于我们的工作目录中:

android@laptop /cygdrive/c/backup
$ dir
abe.jar  backup.ab  backup.tar

使用 pax 或 star 实用程序提取 TAR 文件

我们现在应该使用 Android backup extractor 软件中的 star 实用程序或 Cygwin 的 pax 实用程序提取内容。

star.exe的语法如下:

C:\backup> star.exe –x backup.tar

让我们使用 Cygwin 的 pax 实用程序来提取backup.tar的内容。

首先,我们需要从其存储库中安装 Cygwin、binutils 和 pax 模块。安装完成后,打开 Cygwin 终端,您将看到以下终端窗口:

android@laptop ~
$ pwd
/home/android

android@laptop ~
$

如我们所见,我们不在c:\backup目录中。要访问c驱动器,您需要进入cygdrive,然后使用以下命令进入C驱动器:

android@laptop ~
$ cd /cygdrive/c/backup
$ ls
abe.jar  backup.ab  backup.tar

最后,使用pax命令提取 TAR 文件:

$ pax -r < backup.tar

前面的命令在当前目录中创建了apps文件夹,您可以使用ls命令查看该文件夹:

android@laptop /cygdrive/c/backup
$ ls
abe.jar  apps  backup.ab  backup.tar

针对安全问题分析提取的内容

让我们回顾一下应用的内容,看看是否可以找到有趣的内容:

android@laptop /cygdrive/c/backup
$ cd apps

android@laptop /cygdrive/c/backup/apps
$ ls
com.whatsapplock

android@laptop /cygdrive/c/backup/apps
$ cd com.whatsapplock/

android@laptop /cygdrive/c/backup/apps/com.whatsapplock
$ ls
_manifest  db  f  r  sp

我们可以看到,有一个名为com.whatsapplock包的文件夹,其中包含以下文件夹:

  • _manifest–应用的AndroidManifest.xml文件
  • db-包含应用使用的.db文件
  • f-用于存储文件的文件夹
  • sp-存储共享首选项 XML 文件
  • r-保存视图、日志等

因为我们已经知道该应用将 PIN 存储在共享首选项文件夹中,所以让我们检查一下它是否不安全shared_preferences

android@laptop /cygdrive/c/backup/apps/com.whatsapplock
$ cd sp/
android@laptop /cygdrive/c/backup/apps/com.whatsapplock/sp
$ dir
com.whatsapplock_preferences.xml  inmobiAppAnalyticsAppId.xml
IMAdTrackerStatusUpload.xml       inmobiAppAnalyticsSession.xml
impref.xml                        WhatsLock.xml

android@laptop /cygdrive/c/backup/apps/com.whatsapplock/sp
$ cat com.whatsapplock_preferences.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
 <string name="entryCode">1234</string>
 <int name="revstatus" value="1" />
</map>

android@laptop /cygdrive/c/backup/apps/com.whatsapplock/sp
$

正如我们在前面的摘录中所看到的,如果我们有一个特定应用的备份,我们可以分析该应用的数据,而无需在设备上进行根访问。当我们必须在没有根设备的情况下展示概念验证时,这非常有用。许多 Android 取证工具也使用这种备份技术从设备中提取数据,而无需 root 访问。

我们还可以对提取的备份文件进行更改。如果您希望更改备份并在设备上恢复备份,则可以按照以下步骤完成:

  1. 备份目标应用:

    adb backup -f backup.ab com.whatsapplock
    
    
  2. 删除标题并使用dd命令保存修改后的文件。保存文件列表以保留其顺序:

    dd if=backup.ab bs=24 skip=1| openssl zlib -d > backup.tar
    tar -tf backup.tar > backup.list
    
    
  3. 提取 tar 文件并对应用的内容进行必要的更改,如更改 PIN、更改首选项等:

    tar -xf backup.tar
    
    
  4. 根据修改后的文件创建.tar文件:

    star -c -v -f newbackup.tar -no-dirslash list=backup.list
    
    
  5. 将原始.ab文件的头追加到新文件中:

    dd if=mybackup.ab bs=24 count=1 of=newbackup.ab
    
    
  6. 将修改后的内容追加到表头:

    openssl zlib -in newbackup.tar >> newbackup.ab
    
    
  7. 使用修改后的内容恢复备份:

    adb restore newbackup.ab
    
    

与数据备份一样,数据还原需要用户确认,请点击还原我的数据按钮完成还原过程:

Analyzing the extracted content for security issues

很明显现在,拥有设备物理访问权限的攻击者可以做任何事情。在接下来的几章中,我们还将看到,锁屏的存在并不会阻碍攻击者实现其目标。

安全

很明显,敏感信息不应以明文形式存储,必须非常小心地安全存储数据。

尽量避免在设备上存储敏感数据,并将其存储在服务器端。如果无法避免,则应考虑使用强加密算法对数据进行加密。在设备上保存数据时,有一些库可用于加密数据。

安全首选项就是这样一个库,可以用来加密共享首选项中的数据。这可以在以下链接中找到 https://github.com/scottyab/secure-preferences

SQLCipher 是加密 SQLite 数据库的选项。SQLCipher 可在以下链接中找到 https://www.zetetic.net/sqlcipher/sqlcipher-for-android/

应该注意的是,在使用 AES 等对称加密算法时,密钥管理是一个问题。在这种情况下,基于密码的加密PBE是另一个选项,其中密钥将根据用户输入的密码导出。

如果考虑使用散列,使用一个强的哈希算法加上一个盐。

总结

在本章中,我们讨论了 Android 框架使用的各种数据存储机制。我们已经了解了如何使用共享首选项、SQLite 数据库以及内部和外部存储来不安全地存储数据。备份技术允许我们只需几个额外步骤就可以在根设备上执行与在根设备上相同的技术,即使在非根设备上也是如此。在下一章中,我们将讨论在移动应用的服务器端查找漏洞的技术。