2 minute read

Hello everyone! In this blog post , I will try to explain my solution steps for BorderDroid challenge from 8kSec Android Labs.

Goal:
Goal is to find a way to bypass BorderDroid's kiosk security mechanisms and deactivate it without usb interaction and hardcoded credentials.

Static Analysis

BorderDroid app is a kiosk app. First, we gave all requested permissions(accesibility etc.), set a pin for it and we can use it as kiosk mode. On kiosk mode,navigation buttons are not working and we can only see a pin enterence screen but when we give a correct pin, app not accepting it and says its wrong. Lets start our analysis with jadx.

Code Analysis

...
...
...
          <activity android:theme="@style/Theme.AppCompat.NoActionBar" android:name="com.eightksec.borderdroid.SplashActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name="com.eightksec.borderdroid.PinEntryActivity" android:exported="false" android:windowSoftInputMode="adjustResize|stateVisible"/>
        <activity android:name="com.eightksec.borderdroid.DashboardActivity" android:exported="false" android:launchMode="singleTop"/>
        <activity android:name="com.eightksec.borderdroid.NothingHereActivity" android:exported="false" android:excludeFromRecents="true" android:launchMode="singleTask"/>
        <activity android:theme="@style/Theme.AppCompat.NoActionBar" android:name="com.eightksec.borderdroid.WipeTimerActivity" android:exported="false" android:excludeFromRecents="true" android:launchMode="singleTask"/>
        <activity android:theme="@style/Theme.AppCompat.Dialog" android:name="com.eightksec.borderdroid.CountdownTimerActivity" android:exported="false"/>
        <activity android:name="com.eightksec.borderdroid.YouAreSecureActivity" android:exported="false" android:launchMode="singleTask" android:lockTaskMode="if_whitelisted"/>
        <service android:label="@string/accessibility_service_label" android:name="com.eightksec.borderdroid.service.KioskAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:exported="false">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService"/>
            </intent-filter>
            <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config"/>
        </service>
        <service android:name="com.eightksec.borderdroid.service.HttpUnlockService" android:exported="false" android:foregroundServiceType=""/>
        <receiver android:name="com.eightksec.borderdroid.receiver.RemoteTriggerReceiver" android:enabled="true" android:exported="true">
            <intent-filter>
                <action android:name="com.eightksec.borderdroid.ACTION_PERFORM_REMOTE_TRIGGER"/>
            </intent-filter>
        </receiver>
...
...
...

App has lots of activities and but they are not exported. Only RemoteTriggerReceiver is exported.

SplashActivity(Main Activity):

On main activity, app check the current status(first launch or re-login) and start PinEntryActivity with mode number.

This activity check current mode and if pin is true, calls goToDashboard method and its send intent for DashboardActivity.

On dashboard screen, when we press the Start Security button, app calls startCountdown method. This method start a 10 sec. countdown screen.

After 10 sec, this methods called:

countdownLauncer onActivityResult ->
 m73lambda$onCreate$0$comeightksecborderdroidDashboardActivity -> 
 handleActionSuccess -> 
 startSecurity

startSecurity method sends intent for YouAreSecureActivity class. At this step, the kiosk is active and ask for a pin for unlock. However, even though we gave the correct pin, it does not accept it.

onNumpadClick method only checks for pin lenght and only shows wrong pin message :/

Kiosk Bypass Methods

1. Volume Keys Combination

YouAreSecureActivity class have implemented onKeyDown callback function. This function called when a button pressed.

This method add 24 or 25 to volumeSequence array for volume up and volume down button presses and calls checkVolumeSequence method.

private final List<Integer> targetSequence = YouAreSecureActivity$$ExternalSyntheticBackport0.m(24, 25, 24, 25);

This method checks if key press sequence is UP DOWN UP DOWN and if the sequence is correct, unlock the kiosk mode.

With this method we can bypass kiosk mode without usb or additional app interaction.

PoC video: Youtube

2. Unlock over HTTP

When app starts kiosk, setKioskState method send intent for HttpUnlockService class. This class start http server on port 8080.

This server checks the requests. If the uri is /unlock, pin send as json data and request method is POST, it calls another method(broadcastVulnerableUnlockIntentWithPın). This method create intent for RemoteTriggerReceiver and send the pin value as extra data.

This class verify the pin and if its correct, http server stopped and kiosk deactivated. This method is a remote attack surface for us. We can bruteforce the pin to this http server and unlock the kiosk mode but this server runs local. We need to port forward for accessing the server.

PoC Video: Youtube

3. Exported “RemoteTriggerReceiver” Component

Http server use RemoteTriggerReceiver to unlock kiosk and also that receiver is exported in AndroidManifest.xml file. We can trigger this receiver with an intent and we can use this for bypassing kiosk.

Here is the adb command:

$ adb shell am broadcast -a "com.eightksec.borderdroid.ACTION_PERFORM_REMOTE_TRIGGER" --es "com.eightksec.borderdroid.EXTRA_TRIGGER_PIN" "123123"

Or you can develop a app that sends that intent :)

PoC Video: Youtube

Final

Thats all, see you!