When Equal is Not, Another WebView Takeover Story
Don’t put your blame on me
You might wonder that, since this issue is so common, haven’t the developer community heard about it ?… After all it can’t be that difficult to sanitise the user input.
Well, let me put it this way… think of multiple layers of java inheritance, where some superclass is loading “any” given url from an un-sanitised parameter. When you are writing code on the child of a child of a child … of a naughty parent, these issues are not as obvious as you might think.
When Equal is Not
During my assessments I encountered cases where the mistake is pretty much obvious and this is what this post is all about. I won’t be using real application names for obvious reasons, so I wrote a simple Android app to prove my concept. Let’s start with a deeplink declaration in my AndroidManifest file:
And here is the application’s code:
TL;DR Our application registers the deeplink
example://webview which means that the
MainActivity will be triggered through the intent filter for intents with action set to
android.intent.action.VIEW and data
example://webview . The
onNewIntent callback inspects the data string and if this is not empty it calls the
handleDeeplink to handle the intent. Finally the handleDeeplink will call the
isAuthorisedURL function in order to check the validity of the incoming URL. If the return value is set to true, the WebView loads the URL. In the code snippet above, the isAuthorisedURL returns always true so any given URL will be loaded.
Equal is ! (Starts || Ends || Contains)
There are cases where the applications need to load various URLs in their WebViews including subdomains which are not always given during the application development. These subdomains are get added or removed from time to time to facilitate or discard various features and services.
To handle this problem, the developers come up with various solutions which sometimes are not the best from a security aspect. The startsWith and endsWith or even the contains functions of the java.lang.String class are used to filter out invalid domains, in the most unsafe way. Let’s see a real example which I encountered in a 100,000,000+ downloads application.
isAuthorisedURL function looked like bellow:
The objective was probably to include the foo subdomains of the foobar domain, but the implementation is obviously wrong since all the
foo.foobar* URLs will be considered as valid and will be loaded to the WebView. Believe it or not, a similar issue with an endsWith function was found in a 10,000,000+ application. This time the request to the loaded URL was authenticated while the isAuthorisedURL looked like below:
One more time all the
*foobar.com domains will pass the
if condition thus they will be loaded to the WebView.
The host is dead, long live the host
Sometimes the development team during the staging phase uses hostnames which are valid inside a company’s local network but not in the world wide web … but they can be valid in the world wide web…. Here is an example:
In this case, the developers wanted to include the
test.com but during the staging phase they also added the
staging.site to test out this feature. While this is OK during the tests, when they publish the app they forgot to remove the extra URL. As you understand, assuming that the
staging.site is available an attacker can register the domain and takeover the WebView. The same condition of course stands for expired domains.
This post just scratches the tip of the iceberg when it comes to WebView security vulnerabilities. The intention though was to pinpoint some cases where small mistakes (even in very popular applications) can literally have very serious impact.
See you on the next post !