Skip to content

Latest commit

 

History

History
252 lines (206 loc) · 10.3 KB

insecure_data_storage_android.md

File metadata and controls

252 lines (206 loc) · 10.3 KB

Insecure Data Storage Android

Data storage in mobile applications is often necessary for:

  • Continuous session maintenance: Allowing the creation of persistent sessions for users, avoiding the need for authentication each time the application is opened, providing a more fluid and convenient experience.
  • Storage of media, documents and information: Facilitating access and efficient use of images, files and data that are essential for the operation and interaction of the application, ensuring a rich and interactive experience for the user.

It is crucial to check that this information is being kept securely and that, upon uninstalling the app, all data associated with it is completely removed from the user's device.

Databases

In simple terms, database storage refers to the structured organization of data in a specific system. In mobile applications, this approach is common to store information efficiently, enabling easy access and manipulation of data such as user records, settings and other sets of information. Without adequate security measures, sensitive information may be exposed, compromising user privacy.

SQLite

-> Code example

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "UserData.db";
    private static final int DATABASE_VERSION = 1;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE User (ID INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT)");
        db.execSQL("INSERT INTO User (username, password) VALUES ('usuario', 'senha123')");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS User");
        onCreate(db);
    }
}

-> Identifying on the device

ls -la data/data/<package_name>/databases/ok.db

-> Accessing database with sqlite3

sqlite3 data/data/<package_name>/databases/ok.db

-> See the tables

.tables

-> Include column names as headers in the output, making it easier to identify each column.

.headers on

-> Display query results in an aligned column format, making data easier to read and visualize.

.mode column

-> View table data

select * from <table_name>;

Shared Preferences

Shared Preferences represent a lightweight and straightforward method of storing data. They are used to store small amounts of information, such as user settings, persistently. However, it is crucial to recognize that if not properly protected, these preferences can become vulnerable to unauthorized access.

-> Code example

import android.content.Context;
import android.content.SharedPreferences;

public class InsecureStorage {

    private static final String PREFS_NAME = "InsecurePrefs";
    private static final String KEY_USERNAME = "username";
    private static final String KEY_PASSWORD = "password";

    public static void saveUserData(Context context, String username, String password) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString(KEY_USERNAME, username);
        editor.putString(KEY_PASSWORD, password);
        editor.commit(); // Usando commit de forma síncrona (insegura)
    }

    public static String[] getUserData(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        String username = sharedPreferences.getString(KEY_USERNAME, null);
        String password = sharedPreferences.getString(KEY_PASSWORD, null);
        return new String[]{username, password};
    }
}

-> Identifying on the device

ls -la /data/data/<package_name>/shared_prefs/

The application's SharedPreferences cannot have read permission for all as: -rw-rw-r--. Check the list to see if it contains any files with this permission.

└─$ ls -la /data/data/<package_name>/shared_prefs/
total 56
-rw-rw-r-- 1 u0_a130 u0_a130  4096 Jan  5 20:45 Credentials.xml
-rw-rw-r-- 1 u0_a130 u0_a130  4096 Jan  5 21:23 key.xml

When the application has the "debuggable" flag enabled, it is possible to download files without necessarily being root and we can take advantage of this by using run-as. Example of the flag activated in AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="<package_name>">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:debuggable="true"> <!-- Enables debug mode -->

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

By executing the command, it's possible to download files from an application with debug mode enabled.

adb exec-out run-as <package_name> cat /data/user/0/<package_name>/shared_prefs/key.xml > key.xml

Internal Storage

Internal storage refers to the exclusive space reserved on mobile devices for a specific application. This space is used to store application-specific data files, such as caches, temporary files or sensitive data, and can be accessed by third parties in the absence of security controls applied to it, compromising the confidentiality of the stored information. -> Code example

import android.content.Context;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class InsecureFileStorage {

    private static final String FILENAME = "credit_card.txt";

    public static void saveCreditCardNumber(Context context, String creditCardNumber) {
        try {
            FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
            fos.write(creditCardNumber.getBytes());
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

-> Identifying on the device

/data/data/<package_name>/* or ?

External Storage

External storage makes use of external memory such as SD cards to store application data. While this allows for expansion of storage capacity, it also introduces risks as data can be accessed by other applications or users. Robust security measures are necessary to protect critical information stored externally.

-> Example Code

import android.os.Environment;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class InsecureExternalStorage {

    private static final String FILENAME = "sensitive_data.txt";

    public static void saveData(String data) {
        if (isExternalStorageWritable()) {
            File file = new File(Environment.getExternalStorageDirectory(), FILENAME);

            try {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(data.getBytes());
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }
}

-> Identifying on the device

ls -la /mnt/sdcard/

Backups for Sensitive Data

When reverse engineering an application, be sure to check that the AndroidManifest.xml file contains the value "android:allowBackup="true". This enabled property indicates that the application is configured to save sensitive data (if any) to the file device backup.

Run the backup:

adb backup -apk -f out.ab <package_name>

ADB should respond with the following message: "Now unlock your device and confirm the backup operation", and the Android phone will ask you to enter a password. This step is optional, and you do not need to provide a password.

After the file is downloaded, run Android Backup Extractor (https://github.com/nelenkov/android-backup-extractor):

java -jar abe.jar unpack out.ab out.tar

Then extract the file and check if it contains the sensitive information:

tar xvf out.tar

Dumping Memory for Sensitive Data

In an application, it is possible to identify sensitive data leaks by analyzing process memory. To investigate an application's memory, the first step is to create a memory dump.
Use the "fridump" command for this purpose and then apply filters to identify possible sensitive information that has been exposed, the script will create a /dump folder with the information.
https://github.com/Nightbringer21/fridump

-> Dump memory from an Android device and look for strings associated with the application in all dump files

fridump -U -s <package_name>

Keystore

Keystore provides developers with a secure approach to storing and accessing sensitive cryptographic information, eliminating the need to directly store this data in applications. Using a combination of advanced data protection techniques and security measures, Keystore ensures the integrity and confidentiality of stored information, allowing only authorized applications and authenticated users to access it.

-> Obtain information and extract keys, certificates, and key information from a specific application on a device

frida -U -f <package_name> -l <script>.js

https://github.com/WithSecureLabs/android-keystore-audit/tree/master/frida-scripts

In addition to managing cryptographic keys, Keystore is also capable of storing digital certificates, authentication secrets, and other security-critical data. It offers an intuitive and user-friendly application programming interface (API), allowing developers to easily integrate Keystore into their applications, providing a convenient and secure way to handle sensitive information in an encrypted and protected form.