XSS & Command Injection in Android — MobileHackingLab ‘Post Board’ Write-up
A lab that covers XSS in a WebView within Android which could be exploited by other apps in the device, combined with a Command Injection leading to RCE.
This post contains the solution to the lab challenge. If you’d like to try the lab first, try it over here : https://www.mobilehackinglab.com/course/lab-postboard
Objective
The challenge objective clearly says the following :
‘Exploit an XSS vulnerability in a WebView component to achieve RCE in an Android application.’
Got to look into the app for further analysis.
Discovering the bug
I tried running the app :
The app accepts ‘markdown’ input.
How does it behave with HTML input then ?
Black box payloads can be tried first always. Trying hello<img src=x onerror=alert(1)>
.
This looks like the mentioned XSS vulnerability. Now there has to be a vector for another hypothetically ‘malicious’ app to reach this bug, otherwise it’s only as good as self-xss. Into the decompiled APK.
In AndroidManifest.xml , The ‘MainActivity’ of app is attached to an intent with ‘host’ postmessage
and 'scheme' postboard
. This must be it. So the app might be accepting VIEW
intent calls with attached data in the URI format postboard://postmessage/?a=b
. But what is the vulnerable parameter? Over to the decompiled MainActivity.java
.
handleIntent()
got the logic we're looking for. It's checking for host and scheme, but the payload need no parameter, its taken from the path (after doing base64 decoding). There are some interesting invocations using javascript:
scheme. Got to dig in to these further. These might be the vectors for RCE probably - Android WebView can have custom JavaScript functions that is bridge to the Native Java code. For now, I can verify if the URL scheme is working.
This worked very well.
While inspecting the html
file loaded in WebView, we can see native functions being invoked.
Found new function in WebAppInterface.java
that is not used from the html
.
To validate I tried the following payload :
hello again<img src=x onerror=window.WebAppInterface.postCowsayMessage('hi')>
We have a cow ascii art being printed with the message from it — hi
. Got to inspect this function further. postCowsayMessage()
function executes a function runCowsay()
- which contains the following code.
There’s a shell command being executed here, while message
we passed to postCowsayMessage()
being appended in the shell command. We can try command injection payloads here. hello1<img src=x onerror=window.WebAppInterface.postCowsayMessage('abc;id')>
Exploitation
As the final exploit, I will create a shell command to launch the intent of Postboard — which is equivalent of what a malicious app would do.
~ echo "hi<img src=x onerror=window.WebAppInterface.postCowsayMessage('msg;id;')>" | base64 -w 0 aGk8aW1nIHNyYz14IG9uZXJyb3I9d2luZG93LldlYkFwcEludGVyZmFjZS5wb3N0Q293c2F5TWVzc2FnZSgnbXNnO2lkOycpPgo=
Using the base64 message, the following would be the final command for launching exploit :
adb shell am start -a android.intent.action.VIEW -d "postboard://postmessage/aGk8aW1nIHNyYz14IG9uZXJyb3I9d2luZG93LldlYkFwcEludGVyZmFjZS5wb3N0Q293c2F5TWVzc2FnZSgnbXNnO2lkOycpPgo="