Java安全之命令执行(一)
前言
java安全里最关键的可以说就是命令执行了,无论是反序列化还是什么RCE漏洞,要说最终最能体现漏洞价值的话,那就是非命令执行莫属了。这次打算花点时间好好总结整理下java命令执行的几种方式,并做些浅面的分析。最近刚好看到了360BugCloud公众号的一篇java命令执行的调试分析文章,我也跟着调试了一遍,期间学到了不少,链接会在文末贴出来。
首先总的的来说,java命令执行可以分为4种方法,分别是 java.lang.Runtime#exec()、java.lang.ProcessBuilder#start()、java.lang.ProcessImpl#start()以及通过JNI的方式调用动态链接库,最后一种方式这篇文章暂不做分析,先看完前面比较常用的三种方法。
Runtime命令执行
在java反序列化中用到最多的就是Runtime类的exec方法来命令执行了,用法:
Runtime.getRuntime().exec("whoami")
实际上Runtime类的exec的重载方法有6个,如下:
例如本地运行命令ipconfig查看网络配置并返回信息:
InputStream ins = Runtime.getRuntime().exec("ipconfig").getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int size;
while(
(size = ins.read(bytes)) > 0)bos.write(bytes,0,size);
System.out.println(bos.toString()
);
但是这里有个问题,在渗透的过程中如果要遇到要写入文件的话,这里使用"echo xxx>test.txt"等类似的命令就会爆出如下的错误:
跟入代码调试查看下具体原因
首先是跳到另外一个exec的重载方法,envp参数为null,file类型的dir参数也为null
接着将我们传入的command字符串带入到StringTokenizer类进行处理,跟入查看下
初始化参数后又调用了setMaxDelimCodePoint方法
跟入到setMaxDelimCodePoint方法后,查看代码
来看最后的处理结果
最后再重新调用了对应的exec重载方法
跟入到java.lang.ProcessBuilder#start,首先会先取出cmdarray[0]赋值给prog,这里值为“echo”
接着,后面又调用了ProcessImpl.start
继续跟入查看ProcessImpl#start
接着,后面调用了ProcessImpl的构造方法,再跟入构造方法查看下
跟进ProcessImpl的构建方法后,首先是对系统的配置及环境变量进行检查,比如检测是否允许调用本地进程等配置,接着以cmd[0]为参数创建了一个File对象,然后调用其getPath方法得到路径并赋值给executablePath变量
往下,接着调用needsEscaping()方法对executablePath进行判断,如果其中包含空格,则调用quoteString()方法进行处理;然后调用createCommandLine()把字符串数组拼成字符串,最终的cmdstr为“echo xxx>test.txt”
最后,再调用了create()方法创建进程,整个过程调试到这里好像也没发现问题所在,原因是最后关键的问题还在create方法创建进程中。
查看该create()方法的代码可看到,这是个native方法,后续是通过调用ProcessImpl_md.c的创建进程的方法来调用调用window系统的API接口,从而完成命令执行等操作。
那么我们的问题该怎么解决呢?还是得回到ProcessImpl_md.c的创建进程的方法中,这方法会对最后的我们传入的cmdstr进行以空格分割,也就是"echo xxx>test.txt",会被分割会"echo"和"xxx>test.txt",然后第一部分的"echo"会被当成启动的执行模块,然而在window的系统环境变量中是找不到这个启动模块的(可以在cmd中输入命令“where echo”进行测试),所以运行后才会抛出文章一开始的“系统找不到指定文件”错误。
知道了问题所在,解决办法的思路就比较清晰了,可以把cmd做为启动的指定模块,然后以运行批处理的方式来达到命令执行,要以这样的方式的话就必须启动命令解释器,就是在批处理的语句前面加上"/c",最终的命令应该为“cmd /c echo xxx>test.txt”。
我们通过IDEA的调试器来测试一遍:
OK,这回没有抛出其他错误了,在本地的项目位置在找到了新创建的test.txt文件