All skills
hardw00t avatar

/android-pentest

@f9bb3b2

Comprehensive Android mobile application penetration testing with rooted-device ADB and Frida-based MCP tooling. Covers OWASP MASTG full methodology: recon, static + dynamic analysis, SSL/root bypass, IPC fuzzing, data exfiltration, crypto audit, and reporting. Triggers on requests to pentest Android apps, analyze APKs, bypass mobile security controls, or run MASVS/MASTG assessments.

Use this Skill: https://skilld.dev/gh/hardw00t/ai-security-arsenal/android-pentest

This session only. Nothing lands on disk.

methodologydata_storage.md

≈2.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Data Storage Security Testing Methodology

Data storage testing focuses on identifying sensitive data stored insecurely on the device, including databases, preferences, files, and cache.


Storage Locations

Internal Storage

  • /data/data/<package>/ - App's private directory
  • /data/data/<package>/shared_prefs/ - SharedPreferences XML files
  • /data/data/<package>/databases/ - SQLite databases
  • /data/data/<package>/files/ - Application files
  • /data/data/<package>/cache/ - Cache directory

External Storage

  • /sdcard/Android/data/<package>/ - App-specific external storage
  • /sdcard/ - General external storage (world-readable)

SharedPreferences Testing

Extraction

# Using MCP tool
prefs = dump_shared_prefs("com.target.app")

Manual Analysis

# List preference files
adb shell "su -c 'ls -la /data/data/com.target.app/shared_prefs/'"

# Read preference files
adb shell "su -c 'cat /data/data/com.target.app/shared_prefs/*.xml'"

# Search for sensitive data
adb shell "su -c 'grep -riE \"password|token|key|secret|session\" /data/data/com.target.app/shared_prefs/'"

What to Look For

Data Type Risk Level MASTG Reference
Passwords in plaintext Critical MASTG-TEST-0001
Authentication tokens High MASTG-TEST-0001
Session IDs High MASTG-TEST-0001
API keys High MASTG-TEST-0001
Encryption keys Critical MASTG-TEST-0001
PII (email, phone, SSN) Medium MASTG-TEST-0002
Financial data High MASTG-TEST-0002
PIN codes/hashes High MASTG-TEST-0001

Runtime Monitoring

frida_run_script(pid, """
Java.perform(function() {
    var SharedPrefsEditor = Java.use('android.app.SharedPreferencesImpl$EditorImpl');

    SharedPrefsEditor.putString.implementation = function(key, value) {
        console.log('[PREFS] putString: ' + key + ' = ' + value);
        return this.putString(key, value);
    };

    SharedPrefsEditor.commit.implementation = function() {
        console.log('[PREFS] commit() called');
        return this.commit();
    };

    SharedPrefsEditor.apply.implementation = function() {
        console.log('[PREFS] apply() called');
        return this.apply();
    };
});
""")

SQLite Database Testing

Extraction

# Using MCP tool
databases = dump_databases("com.target.app")

Manual Analysis

# List databases
adb shell "su -c 'ls -la /data/data/com.target.app/databases/'"

# Pull database
adb shell "su -c 'cp /data/data/com.target.app/databases/*.db /sdcard/'"
adb pull /sdcard/*.db ./databases/

# Analyze with sqlite3
sqlite3 database.db ".tables"
sqlite3 database.db ".schema"
sqlite3 database.db "SELECT * FROM users;"
sqlite3 database.db "SELECT * FROM credentials;"

Encrypted Database Detection

# Check file signature
file database.db

# SQLite header: "SQLite format 3"
# SQLCipher: encrypted, no readable header

# If encrypted, hook to capture password

Decrypting SQLCipher

frida_run_script(pid, """
Java.perform(function() {
    // Hook SQLCipher
    var SQLiteDatabase = Java.use('net.sqlcipher.database.SQLiteDatabase');

    SQLiteDatabase.openOrCreateDatabase.overload('java.lang.String', 'java.lang.String', 'net.sqlcipher.database.SQLiteDatabase$CursorFactory').implementation = function(path, password, factory) {
        console.log('[DB] SQLCipher database opened');
        console.log('  Path: ' + path);
        console.log('  Password: ' + password);
        return this.openOrCreateDatabase(path, password, factory);
    };

    SQLiteDatabase.openDatabase.overload('java.lang.String', 'java.lang.String', 'net.sqlcipher.database.SQLiteDatabase$CursorFactory', 'int').implementation = function(path, password, factory, flags) {
        console.log('[DB] SQLCipher database opened');
        console.log('  Path: ' + path);
        console.log('  Password: ' + password);
        return this.openDatabase(path, password, factory, flags);
    };
});
""")

SQL Injection in Database Queries

frida_run_script(pid, """
Java.perform(function() {
    var SQLiteDatabase = Java.use('android.database.sqlite.SQLiteDatabase');

    // Hook rawQuery - vulnerable to injection
    SQLiteDatabase.rawQuery.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(sql, selectionArgs) {
        console.log('[SQL] rawQuery: ' + sql);
        if (selectionArgs) {
            console.log('  Args: ' + JSON.stringify(selectionArgs));
        }
        return this.rawQuery(sql, selectionArgs);
    };

    // Hook execSQL - direct SQL execution
    SQLiteDatabase.execSQL.overload('java.lang.String').implementation = function(sql) {
        console.log('[SQL] execSQL: ' + sql);
        return this.execSQL(sql);
    };
});
""")

File Storage Testing

Internal Files

# Using MCP tool
files = dump_internal_storage("com.target.app")

External Files

# Using MCP tool
external = dump_external_storage("com.target.app")

Manual Analysis

# List all files in app directory
adb shell "su -c 'ls -laR /data/data/com.target.app/'"

# Find sensitive files
adb shell "su -c 'find /data/data/com.target.app/ -name \"*.json\" -o -name \"*.xml\" -o -name \"*.pem\" -o -name \"*.key\" -o -name \"*.p12\"'"

# Check external storage
adb shell "su -c 'ls -laR /sdcard/Android/data/com.target.app/'"

# World-readable files
adb shell "su -c 'find /sdcard/ -name \"*com.target.app*\"'"

File Permission Checks

# Check permissions
adb shell "su -c 'ls -la /data/data/com.target.app/files/'"

# Vulnerable: MODE_WORLD_READABLE (deprecated but still used)
# rw-rw-rw- indicates world-readable

Runtime File Monitoring

frida_run_script(pid, """
Java.perform(function() {
    var FileOutputStream = Java.use('java.io.FileOutputStream');

    FileOutputStream.$init.overload('java.io.File').implementation = function(file) {
        console.log('[FILE] Write: ' + file.getAbsolutePath());
        return this.$init(file);
    };

    FileOutputStream.$init.overload('java.lang.String').implementation = function(path) {
        console.log('[FILE] Write: ' + path);
        return this.$init(path);
    };

    var FileInputStream = Java.use('java.io.FileInputStream');

    FileInputStream.$init.overload('java.io.File').implementation = function(file) {
        console.log('[FILE] Read: ' + file.getAbsolutePath());
        return this.$init(file);
    };
});
""")

Android Keystore Testing

Keystore Usage Detection

# Search for Keystore usage in code
grep -rniE "(KeyStore|KeyGenerator|KeyPairGenerator)" jadx_output/ --include="*.java"

Keystore Monitoring

frida_run_script(pid, """
Java.perform(function() {
    var KeyStore = Java.use('java.security.KeyStore');

    KeyStore.getInstance.overload('java.lang.String').implementation = function(type) {
        console.log('[KEYSTORE] getInstance: ' + type);
        return this.getInstance(type);
    };

    KeyStore.getKey.implementation = function(alias, password) {
        console.log('[KEYSTORE] getKey: ' + alias);
        var key = this.getKey(alias, password);
        if (key) {
            console.log('  Algorithm: ' + key.getAlgorithm());
        }
        return key;
    };

    KeyStore.setKeyEntry.overload('java.lang.String', 'java.security.Key', '[C', '[Ljava.security.cert.Certificate;').implementation = function(alias, key, password, chain) {
        console.log('[KEYSTORE] setKeyEntry: ' + alias);
        console.log('  Algorithm: ' + key.getAlgorithm());
        return this.setKeyEntry(alias, key, password, chain);
    };

    // KeyGenParameterSpec for hardware-backed keys
    var KeyGenParameterSpec = Java.use('android.security.keystore.KeyGenParameterSpec$Builder');
    KeyGenParameterSpec.$init.overload('java.lang.String', 'int').implementation = function(keystoreAlias, purposes) {
        console.log('[KEYSTORE] KeyGenParameterSpec: ' + keystoreAlias);
        console.log('  Purposes: ' + purposes);
        return this.$init(keystoreAlias, purposes);
    };
});
""")

Keystore Security Issues

Issue Description Impact
No user authentication Key usable without device unlock High
No biometric binding Key not protected by biometrics Medium
Weak key properties Short validity, weak algorithm Medium
Key exportable Key can be extracted High

Backup Testing

Check Backup Flag

# In AndroidManifest.xml
grep "allowBackup" AndroidManifest.xml

Extract via Backup

# Create backup (if allowBackup=true)
adb backup -f backup.ab com.target.app

# Convert to tar
java -jar abe.jar unpack backup.ab backup.tar

# Extract
tar -xvf backup.tar

# Analyze extracted data
ls -laR apps/com.target.app/

Logcat Analysis

Extract Logs

# Using MCP tool
logs = get_logcat("com.target.app")

Search for Sensitive Data

# Real-time log monitoring
adb logcat | grep -i "com.target.app"

# Search for sensitive data
adb logcat -d | grep -iE "password|token|key|secret|session|bearer"

# Application-specific logs
adb logcat -d --pid=$(adb shell pidof com.target.app)

Disable Logging in Production

Search for logging calls that should be removed:

grep -rniE "Log\.(d|v|i|w|e)\(" jadx_output/ --include="*.java"

Data Storage Checklist

SharedPreferences

  • No sensitive data in plaintext
  • No authentication tokens stored
  • No encryption keys stored
  • MODE_PRIVATE used (not MODE_WORLD_READABLE)

Databases

  • Sensitive data encrypted
  • No plaintext credentials
  • Proper parameterized queries
  • Database encryption (SQLCipher) if sensitive

Files

  • No sensitive data in plaintext files
  • Internal storage used for sensitive data
  • External storage not used for secrets
  • Proper file permissions

Keystore

  • Hardware-backed key storage used
  • User authentication required for keys
  • Keys not exportable
  • Proper key validity periods

Logging

  • No sensitive data logged
  • Debug logging disabled in production
  • No PII in logs

Backup

  • allowBackup="false" or proper rules
  • Sensitive data excluded from backup

Common Findings

Finding Severity MASTG Reference
Credentials in SharedPreferences Critical MASTG-TEST-0001
Unencrypted database High MASTG-TEST-0001
Tokens in plaintext files High MASTG-TEST-0001
Sensitive data on external storage High MASTG-TEST-0003
Debug logging with secrets Medium MASTG-TEST-0004
Backup enabled with sensitive data High MASTG-TEST-0005
World-readable files High MASTG-TEST-0002
No Keystore for secrets Medium MASTG-TEST-0006

Source: SKILL.md on GitHub

1 warning16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides a comprehensive environment and automated workflows for Android mobile application penetration testing. It interfaces with standard industry tools like ADB and Frida to perform security audits aligned with the OWASP MASTG methodology. While it performs sensitive operations like command execution and remote tool downloads, these are transparently implemented for its stated purpose using trusted sources.

  • Socket16d

    21 alerts: gptSecurity, gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    2 findings · Score: 80/100

Signed by skilld at f9bb3b2. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 6 months ago

README badge

README badge for hardw00t/ai-security-arsenal/android-pentest