Java-Sec-Code代码审计-RCE篇

前言

​ Java安全开始的第一步了,代码审计在网上找了个综合学习的东西,搭建起来就开始搞吧,最近也是没有时间,只能晚上抽时间搞搞了,话不多说了,开始看吧

分析

RCE

​ 远程命令执行 英文名称:RCE (remote code execution) ,简称RCE漏洞,是指用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令,可能会允许攻击者通过改变 $PATH 或程序执行环境的其他方面来执行一个恶意构造的代码。

​ 环境配置完成后,登录之后直接访问RCE,刚开始我的环境会报错,经过排查后发现是url路径的问题,最后更改为/rce/runtime/exec即可。

Runtime

第一个其实也没有什么好说的,没有任何过滤,不过可以跟进去看下命令执行的具体实现过程。直接通过源码进行分析吧

通过这里区实例化一个Runtime.getRuntime,然后下面去调用exec执行传入的参数。

然后一步步执行即可得到我们命令执行的结果,总结

1
2
3
getRuntime():该方法用于返回当前应用程序的运行环境对象。

exec(String command):该方法用于在单独的进程中执行指定的字符串命令

该修复方法和建议,通过使用java的正则表达式来防护

具体可参考正则表达式使用

吃饭吃饭。。。。。。。

ProcessBuilder

接着看吧,里面的另外一处rce点 ProcessBuilder 也是没有任何过滤,就简单的分析一下吧

StringBuilder 是一个可变的字符序列。它继承于AbstractStringBuilder,实现了CharSequence接口。在代码中首先会通过StringBuilder实例化一个sb对象,紧接着声明一个列表

可以看到在这个列表为

1
{"/bin/sh", "-c", "ls"}

会将ls这个字符作为命令来执行,然后作为ProcessBuilder的command参数,不理解的可以参考这篇文章 https://www.jianshu.com/p/10f4771909f9

通过ProcessBuilder.start()执行命令后通过下面的代码块对存在的文件进行便利输出,得到的文件名存放在tmpStr之中。

最后得到输出

漏洞修复建议对用户输入进行严格过滤,参考上一例即可。

Jscmd

这个模块的代码我贴出来吧

1
2
3
4
5
6
7
8
@GetMapping("/jscmd")
public void jsEngine(String jsurl) throws Exception{
// js nashorn javascript ecmascript
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
String cmd = String.format("load(\"%s\")", jsurl);
engine.eval(cmd, bindings);
}

这个模块的RCE代码利用点就是在script包,最主要的几个类和接口为:ScriptEngineManager,ScriptEngine,CompiledScript和Bindings。

  • ScriptEngineManager:是一个工厂的集合,可以通过name或者tag的方式获取某一个脚本的工厂,并且生成一个脚本的ScriptEngine.
  • ScriptEngine:是一个脚本引擎,包含一些操作方法,eval,createBindings,setBindings
  • option 可以是一段js代码,函数,函数传参需要调用 engine.createBindings获得bindings,bindings.put(key,value)来传入参数
  • CompliedScript: engine 实现该接口,可以将ScriptEngine解析一段脚本的结果存起来,方便多次调用,需要将engine向上转换
  • Bindings:用来存放数据的容器,它有3个层级,为Global级、Engine级和Local级,前2者通过ScriptEngine.getBindings()获得,是唯一的对象,而Local Binding由ScriptEngine.createBindings()获得,很好理解,每次都产生一个新的。Global对应到工厂,Engine对应到ScriptEngine,向这2者里面加入任何数据或者编译后的脚本执行对象,在每一份新生成的Local Binding里面都会存在。

了解完这些之后紧接着看代码

1
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");

通过ScriptEngine脚本引擎获取通过jsurl传入的文件扩展名为js的脚本,js脚本文件

1
2
3
4
var a = mainly0n();
function mainly0n(){
var x=java.lang.Runtime.getRuntime().exec("open -a Calculator");
}

最后调试完的结果如图所示,这里简单说一下,首先就是通过ScriptEngine获取jsurl传入的js脚本文件,然后通过engine.getBindings获取js脚本文件中的方法和属性,加载js之后将其赋值给cmd,然后再通过engine.eval执行。