MASTG-TEST-0078: Determining Whether Native Methods Are Exposed Through WebViews
Deprecated Test
This test is deprecated and should not be used anymore. Reason: New version available in MASTG V2
Please check the following MASTG v2 tests that cover this v1 test:
- References to Native Bridge APIs in WebViews
- References to
evaluateJavaScriptUsed as Bridge Reply inWKScriptMessageHandler - References to Password Fields in WebView-Loaded HTML
- References to
evaluateJavaScriptWithout Content World Isolation - References to
evaluateJavaScriptWriting Sensitive Data into WebView DOM
Overview¶
Static Analysis¶
Testing UIWebView JavaScript to Native Bridges¶
Search for code that maps native objects to the JSContext associated with a WebView and analyze what functionality it exposes, for example no sensitive data should be accessible and exposed to WebViews.
In Objective-C, the JSContext associated with a UIWebView is obtained as follows:
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
Testing WKWebView JavaScript to Native Bridges¶
Verify if a JavaScript to native bridge exists by searching for WKScriptMessageHandler and check all exposed methods. Then verify how the methods are called.
The following example from "Where's My Browser?" demonstrates this.
First we see how the JavaScript bridge is enabled:
func enableJavaScriptBridge(_ enabled: Bool) {
options_dict["javaScriptBridge"]?.value = enabled
let userContentController = wkWebViewConfiguration.userContentController
userContentController.removeScriptMessageHandler(forName: "javaScriptBridge")
if enabled {
let javaScriptBridgeMessageHandler = JavaScriptBridgeMessageHandler()
userContentController.add(javaScriptBridgeMessageHandler, name: "javaScriptBridge")
}
}
Adding a script message handler with name "name" (or "javaScriptBridge" in the example above) causes the JavaScript function window.webkit.messageHandlers.myJavaScriptMessageHandler.postMessage to be defined in all frames in all web views that use the user content controller. It can be then used from the HTML file like this:
function invokeNativeOperation() {
value1 = document.getElementById("value1").value
value2 = document.getElementById("value2").value
window.webkit.messageHandlers.javaScriptBridge.postMessage(["multiplyNumbers", value1, value2]);
}
The called function resides in JavaScriptBridgeMessageHandler.swift:
class JavaScriptBridgeMessageHandler: NSObject, WKScriptMessageHandler {
//...
case "multiplyNumbers":
let arg1 = Double(messageArray[1])!
let arg2 = Double(messageArray[2])!
result = String(arg1 * arg2)
//...
let javaScriptCallBack = "javascriptBridgeCallBack('\(functionFromJS)','\(result)')"
message.webView?.evaluateJavaScript(javaScriptCallBack, completionHandler: nil)
The problem here is that the JavaScriptBridgeMessageHandler not only contains that function, it also exposes a sensitive function:
case "getSecret":
result = "XSRSOGKC342"
Dynamic Analysis¶
At this point you've surely identified all potentially interesting WebViews in the iOS app and got an overview of the potential attack surface (via static analysis, the dynamic analysis techniques that we have seen in previous sections or a combination of them). This would include HTML and JavaScript files, usage of the JSContext / JSExport for UIWebView and WKScriptMessageHandler for WKWebView, as well as which functions are exposed and present in a WebView.
Further dynamic analysis can help you exploit those functions and get sensitive data that they might be exposing. As we have seen in the static analysis, in the previous example it was trivial to get the secret value by performing reverse engineering (the secret value was found in plain text inside the source code) but imagine that the exposed function retrieves the secret from secure storage. In this case, only dynamic analysis and exploitation would help.
The procedure for exploiting the functions starts with producing a JavaScript payload and injecting it into the file that the app is requesting. The injection can be accomplished via various techniques, for example:
- If some of the content is loaded insecurely from the Internet over HTTP (mixed content), you can try to implement a MITM attack.
- You can always perform dynamic instrumentation and inject the JavaScript payload by using frameworks like Frida and the corresponding JavaScript evaluation functions available for the iOS WebViews (
stringByEvaluatingJavaScriptFromString:forUIWebViewandevaluateJavaScript:completionHandler:forWKWebView).
In order to get the secret from the previous example of the "Where's My Browser?" app, you can use one of these techniques to inject the following payload that will reveal the secret by writing it to the "result" field of the WebView:
function javascriptBridgeCallBack(name, value) {
document.getElementById("result").innerHTML=value;
};
window.webkit.messageHandlers.javaScriptBridge.postMessage(["getSecret"]);
Of course, you may also use the Exploitation Helper it provides:

See another example for a vulnerable iOS app and function that is exposed to a WebView in [#thiel2] page 156.