Skip to content

Latest commit

 

History

History
662 lines (586 loc) · 28.6 KB

File metadata and controls

662 lines (586 loc) · 28.6 KB

📵 Android Penetration Testing 🇳🇵

Contents

1. Setup and Decompile
2. Verify Signing
3. Check for Hardcoded and URL endpoints
4. Digging into AndroidManifest.xml File
5. Network
6. Storage
7. Analyze the source code thoroughly specially on
8. Reverse Engineering
9. Cryptography
10. Exploiting backup
11. Exploiting Android Debuggable
12. Exploiting Exported Components with drozer
13. Exported Components with APKAnalyzer
14. DeepLink URIs
15. Intercepting HTTPS request on Java Based Application
16. Intercepting HTTPS request on Flutter Based Application
17. Intercepting HTTPS request on Webview Based Application
18. SSL Pinning Bypass as a whole
19. MobSF and Drozer on Docker
20. Testing APIs
21. References
22. More Resources
23. Static Analysis Toolkit
24. Dynamic Analysis Toolkit
25. Decompiling Xamarin Based Applications
26. Bypassing SSL Pinning on Xamarin Based Applications

Setup and Decompile

  • Install the application on emulator or physical device
  • View the package name of application with ADB
    • adb shell pm list packages | grep "app-name"
  • View the path of the application.
    • adb shell pm path "package-name"
  • Decompile the application with APKTOOL
    • apktool d app.apk
  • Decompile the application with JADX
    • jadx /path/to/apk -d /path/to/output

Verify Signing

  • Check if the application has been properly signed.
   apksigner verify --verbose app.apk
   jarsigner -verify -verbose -certs app.apk

Check for Hardcoded and URL endpoints

  • Hardcoded Emails
    • grep -HnroE '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b' | awk -F: '{print $3}'
  • Hardcoded AWS Keys
    • gf aws-keys
  • Hardcoded IPs
    • gf ip
  • Hardcoded Base64 data
    • gf base64
  • Hardcoded usernames and passwords on the source code
  • Hardcoded data on strings.xml ➡️ /res/values/strings.xml
  • Hardcode encryption keys and secrets
  • Hardcoded data on raw.xml ➡️ /res/values/raw.xml
  • Hardcoded URL endpoints
    • gf urls

Digging into AndroidManifest File

  • Check if backup is enabled ➡️ android:allowBackup="true"
  • Check if debug mode is enabled ➡️ android:debuggable="true"
  • DeepLink ➡️ Check for deeplink schemas
  • Permission ➡️ Check if application is asking unnecessary permission.
  • Permission ➡️ Check if application is having permission like External Storage, SMS
  • Check the exported activites, services, providers and receivers
  • Intent Filter also makes components exported by default
  • Task Hijacking ➡️ Check if launchMode=singleTaskdefined and launchMode=singleTop
  • Task Hijacking ➡️ Check if taskAffinity is present
  • Check the Implicit and Explicit Intents
  • Note down the interesting activites on the manifest file
  • Check if HTTP is enabled ➡️ cleartextTrafficPermitted="true"
  • Checked for exported components apkanalyzer manifest print appname.apk

Network

  • Check the Network Security config file ➡️ /res/xml/network_security_config.xml
  • URL with HTTP protocol on the source code
    • Find the URLs with gf url and list the HTTP only
    • Or, with GREP ➡️ grep -iRn "http://"
  • Check if SSL pinning is enabled on the application or not

Storage

  • Shared Preferences

    • Check if the shared preferences contains sensitive data unecrypted ➡️ /data/data/package-name/sharedprefs
    • World Writable - Check if the shared preferences is world writable
    • World Readable ➡️ Check if the shared preferences is world readable
    • MODE_WORLD_READABLE allows all applications to access and read the content of the file
      SharedPreferences sharedPref = getSharedPreferences("key", MODE_WORLD_READABLE);
  • SQLite Database

    • Check if database contains sensitive information unencrypted ➡️ /data/data/package-name/files/
  • Firebase

    • Check for firebase URL endpoint with gf url or on /res/values/strings.xml
    • Add /.json on the end of the URL curl -X GET https://subdomain.firebaseio.com/.json
      • The endpoint will be vulnerable if it does not replies with "error" : "Permission denied"
  • Internal Storage

    • World Writable - Check if the internal storage is world writable
    • World Readable - Check if the external storage is world readable
    fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
    • Analyse the data in internal storage
      • Pull the internal storage without using (just after installation) adb pull /data/data/package-name
      • Pull the internal storage after using (full feature usage) adb pull /data/data/package-name
      • Analyze the difference
  • External Storage

    • Application can store data externally on SD card or on internal (non-removal).
    • Pull the external storage of the application and look for any sensitive information.
    # locate the external storage of the app
    adb shell ls /sdcard/Android/data
    
    # Pull the external directory of the app
    adb pull /sdcard/Android/data/"package-name"
    • File saved to external storage is World Readable which can be accessed by other apps.
    File file = new File (Environment.getExternalFilesDir(), "password.txt");
    • Search for Classes and Functions such as
      • MODE_WORLD_READABLE or MODE_WORLD_WRITABLE
      • the SharedPreferences class (stores key-valu pairs)
      • the FileOutPutStream class (uses internal or external storage)
      • the getExternal* functions(use external storage)
      • the getWritableDatabase function (returns a SQLiteDatabase for writing)
      • the getReadableDatabase function (returns a SQLiteDataabase for reading)
      • the getCacheDir and getExtrernalCacheDirs function (use cached files)
    • Check for HTTP caching (sensitive information) which is stored in Cache.db in internal storage
    • Keyboard Cache
      • Determine Whether the Keyboard Cache is Disabled for Sensitive Input.
      • The keyboard cache file is located in: /var/mobile/Library/Keyboard
      <EditText
          android:id="@+id/KeyBoardCache"
          android:inputType="textNoSuggestions" />

Analyze the source code thoroughly specially on

  • Login and Registration
  • Password Forgot and Reset
  • Activity which has implemented the intent defined on AndroidManifest.xml
  • Encryption and Decryption
  • Web API Intregation
  • Transactions Related
  • OTP Related
  • Activity which has implemented webviews
  • Database, Shared Preferences, Internal and External Directory Integration
  • Build Configs

Reverse Engineering

  • Decompile

    • Basic Decompilation
      • apktool d base.apk
    • Decompile only resource
      • apktool d -s base.apk
    • Decompile only source
      • apktool d -r base.apk
    • If above give errors
      • apktool --use-aapt2 d base.apk
  • Recompile

    • apktool b --use-aapt2 -o out.apk base
  • Generate a key

    • keytool -genkey -v -keystore keys/test.keystore -alias Test -keyalg RSA -keysize 1024 -sigalg SHA1withRSA -validity 10000
  • Sign the application

    • jarsigner -keystore keys/test.keystore dist/test.apk -sigalg SHA1withRSA -digestalg SHA1 Test
  • Zipalign the application

    • zipalign -v 4 <YOUR_APP_NAME> app-release-final.apk
  • Automate the signing and zipalign with uber-apk-signer

    • java -jar uber-apk-signer-1.2.1.jar -a out.apk
  • If you faced adb: failed to install out-aligned-debugSigned.apk: Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2] during the installation. Remove the below code snippet from the AndroidManifest.xml file and try again.

    android:extractNativeLibs="false"
  • Or, you might need to perform zipalign as per below commands.

    zipalign -p -f -v 4 out.apk out-aligned.apk
  • Note:

    • Run zipalign before signing the apk file if you are using apksigner
    • Run zipalign after signing the apk file if you are using jarsigner.
  • If you got AAB file from the client: BundleTools

    # Generate the certificate
    keytool -genkey -v -keystore keys/test.keystore -alias Test -keyalg RSA -keysize 1024 -sigalg SHA1withRSA -validity 10000
    
    # Convert AAB into the different APKs compatible for different architecture.
    java -jar bundletool-all-1.15.6.jar build-apks --bundle=app.aab --output=app.apks --ks=keys/test.keystore --ks-key-alias=Test --ks-pass=pass:<password-used-for-above-command>
    
    # Install the compatible APK automatically
    java -jar bundletool-all-1.15.6.jar install-apks --apks=app.apks

Cryptography

  • Check if application is communicating with server encrypted or unencrypted
  • Check if the private key secrets are being stored hardcode on the source code
  • Check if the application is using Base64 for encrypting data for transmitting or storing ➡️ gf base64
  • Check for depreciated algorithms like RC1, MD4, MD5 and SHA1 which causes collision issues
  • Analyze the source code and workflow of the encryption technique
    • Sometimes there might not be issues on hardcoding secrets, depreciated algorithm, but the implementation of the techniques might be done insecurely
  • Check if the application has implemented their own custom cryptographic algorithm and try to reverse it.

Exploiting backup

  • Check if application has backup enabled. If enabled, use following commands to extract internal storage even if the device is non-rooted.
   # Look for backup on Manifest file
   android:allowBackup="true"
   
   # List the package name
   adb shell pm list packages | grep "app name"
   
   # Backup the data contained in the package.
   adb backup "package-name"
   
   # The file name will be backup.ab
   # Convert .ab extension with android backup extractor.
   Download link: https://sourceforge.net/projects/adbextractor/
   
   # Convert .ab into tar
   java -jar abe.jar unpack backup.ab backup.tar
   
   # Extract the tar file
   tar -xvf backup.tar
   
   # Analyze the files in the extracted folder and look for directory like databases, shared preferences, files

Exploiting Android Debuggable

  • Check if application has debuggable mode enabled. If enabled, use following commands to access the android shell as the vulnerable application even if the device is not rooted.
   # Look for debuggable mdoe on Manifest file
   android:debuggable="true"
   
   # Before app start run,
   adb jdwp
   # It will list all the process ID of the running applications.
   
   # After app start run,
   adb jdwp
   # The currently started application process ID can be identified.
   
   adb shell ps | grep "ID-number"
   # It will give the package name of the ID.
   
   adb shell
   run-as package-name
   
   # Or,
   adb shell pm list packages | grep "app-name"
   adb shell
   run-as package-name
  • For further exploitation, follow Link1 and Link2.

Exploiting Exported Components with drozer

Setup

  • Download drozer app for android and PC from here.
  • Install the applications on android and PC.
  • Forward the port from PC
   adb forward tcp:31415 tcp:31415
  • Open the drozer application on android device and click on ON button
  • Launch the application
   drozer console connect

Retrieving Package information

  • View the package name of the application
   run app.package.list -f "app-name"
  • View the basic information of the package
   run app.package.info -a "package-name"
  • View the Manifest information of the package
   run app.package.manifest "package-name"
  • Identify the attack surface
   run app.package.attacksurface "package-name"
   # It will list all the exported activities, services, providers, broadcasts.

Exported Activities

  • Verify if unnecessary activities are exported and exploit it
   run app.activity.info -a "package-name"
   # It will list the exported activities
   
   run app.activity.info -a "package-name" -u
   # It will list all the activities
   
   # Start the exported activity from drozer and see the result on android device
   run app.activity.start --component "package-name" "component-name"

Exported Content Providers

  • Verify if any content providers are exported and exploit it
   run app.provider.info -a "package-name"
   # It will list the exported providers
   
   run scanner.provider.finduris -a "package-name"
   # It will list the URIs of the exported providers
   
   run app.provider.query "uri"
   # List the query on exported URIs
   
   run app.provider.update "uri" --selection <conditions> <selection arg> <column> <dataa>
   # Update the database using exported URIs
  • SQLi on Content providers
   run scanner.provider.sqltables -a "package-name"
   # List the tables
   
   run scanner.provider.injection -a "package-name"
   # Performs some basic SQLi
  • Path traversal on Content providers
   run scaner.provider.traversal -a "package-name"

Exported Broadcast Receivers

  • Verify any exported broadcast receivers and exploit it
  run app.broadcast.info -a "package-name"
  # List the exported broadcast receivers
  
  run app.broadcast.send --component "package-name" "component-name" --extra <type> <key> <value>
  # Send data through exported broadcast receivers
  
  run app.broadcast.sniff --action <action>
  # Sniff the data through exported broadcast receivers

Exported Services

  • Verify any exported services and exploit it
  run app.service.info -a "package-name"
  # List the exported services
  
  run app.service.start --action <action> --component <package-name> <component-name>
  # Start the exported services
  
  run app.service.send <package-name> <component-name> -msg <what> <arg1> <arg2> --extra <type> <key> <value> --bundle-as-obj
  # Send data through services

Exported Components with APKAnalyzer

  • Drozer might not work on every device, we can use apkanalyzer for exported components in such case.
  • Exported Activities apkanalyzer manifest print app-name.apk | grep -i activity
    • Start an activity adb shell am start -n com.example.demo/com.example.test.MainActivity
  • Exported Services apkanalyzer manifest print app-name.apk | grep -i service
    • Start the services adb shell am startservice com.some.package.name/.YourServiceSubClassName
  • Exported Content Providers apkanalyzer manifest print app-name.apk | grep -i provider
    • Query the content providers adb shell content query --uri content://com.myapp.authority/path --where column=x --arg 1 --sort column_name DESC
    • More on Stack Overflow
  • Exported Broadcast Receivers apkanalyzer manifest print app-name.apk | grep -i broadcast
    • Start broadcastadb shell am broadcast -a <Action-Name> -n <package-nname/.BroadcastReceiver> --es <parameter> <value>

DeepLink URIs

  • Download the below script.
  • Decompile the application.
  • Execute below commands
    git clone https://github.com/teknogeek/get_schemas 
    pip3 install -r requirements.txt
    python3 get_schemas.py -m ./com.twitter.android/AndroidManifest.xml -s ./com.twitter.android/res/values/strings.xml
  • Execute the deeplink adb shell am start -W -a android.intent.action.VIEW -d "example://gizmos" com.example.android
  • For manual enumeration and exploitation, check out another notes of mine here.

Intercepting HTTPS request on Java Based Application

With Frida

  • Download and install frida
pip3 install frida-tools
  • Download frida servers according to your android architecture from here and rename it to frida-server
   # View CPU architecture of the android device
   adb shell getprop ro.product.cpu.abi
  • Download the certificate from burp and copy as cert-der.crt
  • Push the server and certificate file to android
   adb root # might be required
   adb push frida-server /data/local/tmp/
   adb push cert-der.crt /data/local/tmp/
   adb shell "chmod 755 /data/local/tmp/frida-server"
   adb shell "/data/local/tmp/frida-server &"
  • Download the SSL Pinning bypass script from here and save it as sslPinningBypass.js
  • Change proxy on android device
    • Long press on wifi
    • Click on Advance option
    • Change proxy to manual
    • Enter your PC ip address
    • Enter a random port (like 5567)
    • Save
  • Open the burp and Change the proxy option from 127.0.0.1:8080 to PC-IP:5567 (port number must be same)
  • Grab the package name with adb shell pm list packages | grep "app-name"
  • Run the script
   frida -U -l sslPinningBypass.js -f "package-name" --no-pause
  • The application will open automatically and now the requests will be captured on burp

With Objection (works also on non-rooted device)

  • Install Objection
   pip3 install objection
  • Patch the apk with Objection
   objection patchapk -s base.apk
  • If the above patch failed, follow here for manual patch of application using objection
  • Installed the patched apk
   adb install patched.pak
  • Proxy the android route into PC as described on frida section
  • Setup burp as described on frida section
  • Run the Application
  • Run Objection explore
   objection explore
  • Disable SSL Pinning
   android sslpinning disable
  • Burp will start intercepting the packets

  • If you are testing the application on latest Android versions like 11, you will get error while running SSL pinning bypass script with frida.

  • There are two solutions for this.

  • One is to downgrade the frida version to pip3 install frida==16.1.8.

  • And then disable the USAP.

adb shell
su
mount -o remount,rw '/'
chmod 777 /
setenforce 0
setprop persist.device_config.runtime_native.usap_pool_enabled false
settings put system screen_off_timeout 100000000
exit
exit

Intercepting HTTPS request on Flutter Based Application

The use of Frida on bypassing SSL Pinning may not work on flutter. I also performed some exploitatio in libflutter.so file for injecting the memory address of the certificate checker. However it did not work as intended. Here is the reference for bypassing SSL Pinning on flutter application through the exploitation of libflutter.so file.

This is an alternative method for bypassing SSL Pinning in Flutter application.
Note: I have tested this method on few aplications with success but this might not work as well.

  • Requirements

    • Genymotion: Android Emulator
    • ProxyDroid: Since flutter appication ignores manual proxy configuration through wifi
    • Burp Suite
  • Setup and Configurations

    • Install ARM Translation tool on the device since flutter application and proxydroid may not work in genymotion since it is of x86 architecture.
    • Click on the File Upload widget and INSTALL OPEN GAPPS
    • Click INSTALL
    • Wait for the package to be installed
    • When done, you will be prompted to reboot the virtual device.
    • (Optional) Open the Play Store and configure you account.
    • Verify ARM Translation tools installtion
       adb shell getprop ro.product.cpu.abilist
       # This command should return "x86,armeabi-v7a,armeabi" as the output.
  • Download the Burp Certificate

  • Convert Burp Certificate into PEM format

    • Android only accepts certificate of PEM format if needs to be installed as system certificate.
    • We can convert the burp certificate into PEM format using openssl. More
       openssl x509 -inform DER -in cacert.der -out cacert.pem
       openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1
    
       # Rename the PEM file with the output given by the second command
       mv cacert.pem <RandomAlphaNumeric>.0
    
       # Example: mv cacert.pem 4a787b67.0
  • Push the certificate file into android application

    • We need to push the certificate into /system/etc/security/cacerts directory inorder to install it as system certificate. But although having root access on the device, permission to write on system directory is denied. For this we need to remount the device.
       adb root
       adb remount
    
       # Push the file
       adb push 4a787b67.0 /system/etc/security/cacerts/
    
       # If the above command still throws error. Consider pushing it into the sdcard at first.
       adb push 4a787b67.0 /sdcard/Download/
       adb shell
       mv /sdcard/Download/4a787b67.0 /system/etc/security/cacerts/
    
       # Change the permission of the file (inside adb shell)
       chmod 644 /system/etc/security/cacerts/4a787b67.0
    
       # Reboot the device (inside adb shell)
       reboot
    • Sometime above method also doesnot works and there will be error saying skipped unmounted partition . In that case we need to mount with read/write permission.
       adb shell
       
       # Enter root
       su 
       
       # Mount with read write permission 
       mount -o rw,remount -t rootfs/
       
       # exit the root
       exit 
       
       # Rebbot the device (inside adb shell)
       reboot
       
       # Push the file 
       mv /sdcard/Download/4a787b67.0 /system/etc/security/cacerts/
    • Verify the certicate installation by navigating to installed certificates on android device through settings. Should list Portswigger CA.
  • Install and Configure the ProxyDroid aplication on the device

  • Since the flutter application ignores the proxy configured through wifi options, proxydroid must be installed.

  • Download Link is here

  • Open the application

    • Enter the IP address of your computer (which intercepts the traffic) on the host parameter and a random port number and enable the proxy.
    • Remove the custom proxy from the Wifi advance option if you have configured previously.
  • Burp's Things

    • Open the Burp
    • Go To: Proxy ➡️ Options ➡️ Add ➡️ Request handling
    • Enter the previously entered host and port from proxy droid
    • Click on Support invisible proxying.
  • Save the configuration, and you will be able to intercept the traffic of the flutter application

Intercepting HTTPS request on Webview Based Application

  • Grab the package name. frida-ps -Uai | grep -ia 'app-name'
  • Save the below JS code. fridawebview.js
       Java.perform(function() {
         var array_list = Java.use("java.util.ArrayList");
         var ApiClient = Java.use('com.android.org.conscrypt.TrustManagerImpl');
         // Cert pin bypass by https://techblog.mediaservice.net/2018/11/universal-android-ssl-pinning-bypass-2/
         ApiClient.checkTrustedRecursive.implementation = function(a1,a2,a3,a4,a5,a6) {
           console.log('Bypassing SSL Pinning');
           var k = array_list.$new(); 
           return k;
         }
    
         var WebView = Java.use('android.webkit.WebView');
         WebView.loadUrl.overload("java.lang.String").implementation = function (s) {
           console.log('Enable webview debug for URL: '+s.toString());
           this.setWebContentsDebuggingEnabled(true);
           this.loadUrl.overload("java.lang.String").call(this, s);
         };
       },0);
  • Proxy the request from Android device to your PC.
  • Run the command frida -U -l fridawebview.js -f com.packagename

SSL Pinning Bypass as a whole

frida -U --codeshare akabe1/frida-multiple-unpinning -f package-name

MobSF and Drozer on Docker

MobSF

  • Download: docker pull opensecurity/mobile-security-framework-mobsf:latest
  • Run: docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
  • Stop: docker ps and then docker stop container-id

Drozer

  • Download: docker pull withsecurelabs/drozer
  • Connect to the phone via USB
  • Open the apk file
  • Port Forward: adb forward tcp:31415 tcp:31415
  • Execute drozer
docker run --add-host host.docker.internal:host-gateway -it withsecurelabs/drozer console connect --server host.docker.internal
  • If a system shell is required
adb forward tcp:31415 tcp:31415
docker run --add-host host.docker.internal:host-gateway -it --entrypoint sh withsecurelabs/drozer
drozer console connect --server host.docker.internal

Testing APIs

  • Please follow this for API Pentesting Checklist

References

More Resources

Static Analysis Toolkit

Dynamic Analysis Toolkit

Decompiling Xamarin Based Applications

  • Download pyxamstore from https://github.com/jakev/pyxamstore
    • git clone https://github.com/jakev/pyxamstore.git
  • Install
    • python3 setup.py install
    • pip3 install xxhash
  • Decompile the apk with apktoool.
    • apktool d yourapp.apk
  • Unpack the assemblies
    • pyxamstore unpack -d yourapp/unknown/assemblies/
  • There will be a directory called out.

Bypassing SSL Pinning on Xamarin Based Applications

  • As Xamarin seems to be moving away from the .NET HTTP Client in favor of the native client on each platform, universal pinning bypasses designed for the Java HttpClient may now be effective on newer Mono-based apps.

  • The main exception is AOT (Ahead-of-Time compiled) apps, which still rely on the .NET HTTP Client. In these cases, it's necessary to identify the relevant native method via reverse engineering and use a custom Frida script to patch it.

  • We can find the relevant script for the bypass on GoSecure repository.

    #clone the repo
    https://github.com/GoSecure/frida-xamarin-unpin
    
    cd frida-xamarin-unpin
    
    # Load the application using frida
    frida -U -f <package-name>
    %load dist/xamarin-unpin.js
    
    # Note that proxy to be configured already