Android WebView 远程代码执行漏洞
来源:互联网 发布:c语言数据类型怎么用 编辑:程序博客网 时间:2024/06/06 09:02
这个周末我们新开发的app超嘀折交给乌云测试检测,其中WebView 远程代码执行漏洞被反复提出,当时就蒙了,这是个什么东西,在网上查了很多资料,在这里做出记录。
一、 漏洞描述
Android的SDK中提供了的WebView组件,用于在应用中嵌入一个浏览器来进行网页浏览。 WebView组件中的addJavascriptInterface方法可以用于实现本地Java和JavaScript的交互。但是这个方法存在远程代码执行漏洞,远程攻击者利用此漏洞能实现本地java和js的交互,可对Android移动终端进行网页挂马从而控制受影响设备。
简单地说,就是用addJavascriptInterface可能导致不安全,因为JS可能包含恶意代码。当JS包含恶意代码时,它可以干任何事情:访问当前设备的SD卡上面的任何东西,甚至是联系人信息,短信等。
二、 漏洞检测
常用检测漏洞的方法是用webView打开下面的页面,如果当前 app 存在漏洞,将会在页面中输出存在漏洞的接口方便程序员做出修改:
<!DOCTYPE html><html><head> <meta charset="UTF-8" /> <title>WebView 漏洞检测</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"></head><body><p> <b>如果当前 app 存在漏洞,将会在页面中输出存在漏洞的接口方便程序员做出修改:</b></p><script type="text/javascript"> 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){ } } } catch(e) { } } } check();</script></body></html>
check()方法遍历所有window的对象,然后找到包含getClass方法的对象。如果getClass方法能够获取对象,那么就可以利用这个对象的类进行入侵操作。
三、解决方案
1、Android 4.2以上
Android4.2 开始,对于JavaScript代码通过addJavascriptInterface 添加的java 代码的调用做出了限制,只有public并且声明了@JavascriptInterface 的方法才可以被JavaScript代码调用。
@SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"}) public void showSalesActivity(String url) { webView.loadUrl(url); }
2、Android 4.2以下
Android 4.2一下版本就比较不容易解决。主要的思路是动态生成一段声明Javascript方法的JS脚本,通过loadUrl来加载它,从而注册到html页面中,这个js中调用prompt方法,通过prompt把JS中的信息传递给java(这些信息应该是我们组合成的一段有意义的文本,可能包含:特定标识,方法名称,参数等),在onJsPrompt方法中,我们去解析传递过来的文本,得到方法名,参数等,再通过反射机制,调用指定的方法,从而调用到Java对象的方法。
``` pythonpackage com.heshidai.javatojs;import android.annotation.SuppressLint;import android.annotation.TargetApi;import android.graphics.Bitmap;import android.os.Build;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.View;import android.webkit.JsPromptResult;import android.webkit.WebChromeClient;import android.webkit.WebSettings;import android.webkit.WebView;import android.webkit.WebViewClient;import org.json.JSONObject;public class MainActivity extends AppCompatActivity { private WebView webView; private JSCallManager jsCallManager; @TargetApi(Build.VERSION_CODES.HONEYCOMB) @SuppressLint({"JavascriptInterface"}) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); webView = (WebView) findViewById(R.id.webView); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true); webSettings.setAllowFileAccess(true);//允许访问文件 webSettings.setSupportZoom(true);//设置支持缩放 webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);//设置缓存模式(不使用缓存,只从网络获取数据.) webSettings.setBuiltInZoomControls(true);//启动内置缩放 webSettings.setLoadsImagesAutomatically(true);//自动加载图片 webSettings.setDefaultTextEncodingName("UTF-8"); webSettings.setLoadWithOverviewMode(true);//自适应屏幕 webView.setWebViewClient(new MyWebViewClient()); webView.setWebChromeClient(new MyWebChromeClient()); webView.loadUrl("www.baidu.com"); //JSCallManager本地处理js消息的对象 if (Build.VERSION.SDK_INT >= 17) { // 在sdk4.2以上的系统上继续使用addJavascriptInterface webView.addJavascriptInterface(new JSCallManager(this), "Native"); } else { //4.2之前 addJavascriptInterface有安全泄漏风险 //移除js中的searchBoxJavaBridge_对象,在Android 3.0以下,系统自己添加了一个叫 //searchBoxJavaBridge_的Js接口,要解决这个安全问题,我们也需要把这个接口删除 jsCallManager = new JSCallManager(this); webView.removeJavascriptInterface("searchBoxJavaBridge_"); // 在 h5开始加载时动态给js注入Native对象和call方法,模拟addJavascriptInterface //接口给js注入Native对象 //动态注入的好处就是不影响线上的h5数据,不影响ios使用 //在onPageStarted方法中注入是因为在h5的onload方法中有与本地交互的处理 //prompt()方法是js弹出的可输入的提示框 webView.loadUrl("javascript:if(window.Native == undefined){window.Native=\n"+ "{call:function(arg0,arg1){prompt('{\\\"methodName\\\":' + arg0 + ',\\\"jsonValue\\\":' + \n" + "arg1 + '}')}}};\""); } } class MyWebViewClient extends WebViewClient { //WebViewClient的方法 h5开始加载的回调 public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); if (Build.VERSION.SDK_INT < 17) { // 在 h5开始加载时动态给js注入Native对象和call方法,模拟addJavascriptInterface //接口给js注入Native对象 //动态注入的好处就是不影响线上的h5数据,不影响ios使用 //在onPageStarted方法中注入是因为在h5的onload方法中有与本地交互的处理 //prompt()方法是js弹出的可输入的提示框 view.loadUrl("javascript:if(window.Native == undefined){" + "window.Native=\n" + "{" + "onButtonClick:function(arg0,arg1){" + "prompt('{\\\"methodName\\\":' + javaMethod + ',\\\"jsonValue\\\":' + \n" + "jsonValue + '}')" + "}" + "}" + "};"); } } } class MyWebChromeClient extends WebChromeClient { //当js调用prompt方法时会触发onJsPrompt //message就是js传给本地的信息 //result.confirm是回传给js的信息 @Override public boolean onJsPrompt(WebView view, String url, final String message, String defaultValue, JsPromptResult result) { if (Build.VERSION.SDK_INT < 17) { new Thread(new Runnable() { @Override public void run() { try { //message的格式是json //jsCallManager.call方法是原来处理js响应事件的方法,methodName是指要处理的js事件名称,jsonValue是指要处理的js事件的参数 JSONObject jsonObject = new JSONObject(message); String methodName = jsonObject.getString("methodName"); String jsonValue = jsonObject.getString("jsonValue"); jsCallManager.call(methodName, jsonValue); } catch (Exception e) { } } }).start(); } result.confirm("callBackMessage");//返回给js的去处理的数据 return super.onJsPrompt(view, url, message, defaultValue, result); } }}
需要注意的是:
1】刚开始时在当WebView正常加载URL后去加载Js,但发现会存在问题,如果当WebView跳转到下一个页面时,之前加载的Js就可能无效了,所以需要再次加载。这个问题经过尝试,需要在以下几个方法中加载Js,它们是WebChromeClient和WebViewClient的方法:
onLoadResource
doUpdateVisitedHistory
onPageStarted
onPageFinished
onReceivedTitle
onProgressChanged
目前测试了这几个地方,没什么问题,这里我也不能完全确保没有问题。
【2】需要过滤掉Object类的方法。由于通过反射的形式来得到指定对象的方法,他会把基类的方法也会得到,最顶层的基类就是Object,所以我们为了不把getClass方法注入到Js中,所以我们需要把Object的公有方法过滤掉。这里严格说来,应该有一个需要过滤方法的列表。目前我的实现中,需要过滤的方法有:
“getClass”,
“hashCode”,
“notify”,
“notifyAll”,
“equals”,
“toString”,
“wait”,
3、removeJavascriptInterface
当系统辅助功能中的任意一项服务被开启后,所有由系统提供的WebView都会被加入两个JS objects,分别为是”accessibility” 和 “accessibilityTraversal”。如果APP使用了系统的WebView,并且设置了setJavaScriptEnabled(),那么恶意攻击者就可以使用”accessibility” 和 “accessibilityTraversal” 这两个Java Bridge来执行远程攻击代码。
不同的Android 系统版本的可被攻击性也是不一样的。从API Level 17 (含)也就是Android4.2 开始,对于JavaScript代码通过addJavascriptInterface 添加的java 代码的调用做出了限制,只有public并且声明了@JavascriptInterface 的方法才可以被JavaScript代码调用。所以理论上在Android4.1(含)之前的版本上此漏洞会更容易被利用且有更高的危害。但是经过测试发现,有些手机即使系统版本是4.2,仍然可以利用此漏洞,在JavaScript中调用getClass() 方法。
我们需要通过removeJavascriptInterface(该方法在API 11中才有的,需要做判断)显示的删除accessibilityTraversal、accessibility。同时在Android 3.0以下,系统自己添加了一个叫searchBoxJavaBridge_的Js接口,要解决这个安全问题,我们也需要把这个接口删除。
if (Build.VERSION.SDK_INT >= 11) { webView.removeJavascriptInterface("searchBoxJavaBridge_"); webView.removeJavascriptInterface("accessibility"); webView.removeJavascriptInterface("accessibilityTraversal"); }
4、不在js中调用java方法
即不使用addJavascriptInterface 也不使用@SuppressLint({“JavascriptInterface”})。通过url拦截的形式去触发java中的方法
webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) {//此处能拦截超链接的url,即拦截href请求的内容. if (url.contains("first_access_share")) {//如果包含“first_access_share”拦截跳转 firstAccessShare();//调用对应的方法 return true; } view.loadUrl(url); return true; } });
总结
1、WebView 远程代码执行漏洞 在Android4.2之后得到了一定的修复(有的系统中4.2上还是存在),只有public并且声明了@JavascriptInterface 的方法才可以被JavaScript代码调用。
2、Android4.2以下如果需要在JavaScript代码调用,就需要比较复杂的方法。主要的思路是动态生成一段声明Javascript方法的JS脚本,通过loadUrl来加载它,从而注册到html页面中,这个js中调用prompt方法,通过prompt把JS中的信息传递给java(这些信息应该是我们组合成的一段有意义的文本,可能包含:特定标识,方法名称,参数等),在onJsPrompt方法中,我们去解析传递过来的文本,得到方法名,参数等,再通过反射机制,调用指定的方法,从而调用到Java对象的方法。
3、上述两种情况还是有漏洞需要显示的用 webView.removeJavascriptInterface去掉一些方法searchBoxJavaBridge_、accessibility、accessibilityTraversal
4、最后的方法就是不要在JavaScript中调用java方法,使用url拦截的形式去触发(我的项目中使用的这种方法)
本文参考了一下文章
http://blog.csdn.net/leehong2005/article/details/11808557
http://seclab.safe.baidu.com/2014-10/android-webview-cve-2014-7224.html
http://blog.csdn.net/zhouyongyang621/article/details/47000041
- Android WebView 远程代码执行漏洞
- Android WebView远程执行代码漏洞浅析
- Android WebView远程执行代码漏洞浅析
- Android WebView远程执行代码漏洞浅析
- Android WebView 远程执行代码漏洞浅析
- Android安全--webview远程代码执行漏洞
- Android WebView远程代码执行漏洞简析
- android安全之webview远程代码执行漏洞
- WebView 远程代码执行漏洞浅析
- WebView 远程代码执行漏洞浅析
- WebView 远程代码执行漏洞修复方案
- Android静态安全检测 -> WebView组件远程代码执行漏洞检测
- WebView远程代码执行漏洞学习并复现
- JBOSS远程代码执行漏洞
- JBOSS远程代码执行漏洞
- JBOSS远程代码执行漏洞
- Struts2远程代码执行漏洞
- JBOSS远程代码执行漏洞
- android Material主题中的button效果
- VoLTE……由来
- (三)HttpURLConnection
- 浏览器基础
- IIS tomcat共用80端口解决一个IP多个域名:使用Nginx反向代理方式使两者兼容
- Android WebView 远程代码执行漏洞
- VC 用发音函数Beep()播放简谱音乐
- 开源控件ExpandableTextView的使用
- 【LeetCode】13Roman to Integer
- 使用android-async-http下载图片时出现org.apache.http.client.HttpResponseException: Content-Type not allowed的错误
- android 按原始数据读出资源
- iOS CoreImage专题(二) —— 进阶
- 简单的使用GitHub,代码管理
- MIT算法导论-第六讲-顺序统计问题