Java-sec-code sql注入&Velocity RCE


先来看看这个靶场sql注入的位置

简单的一个闭合单引号就能探测出了注入

 

那么来看看源码

可以看到jdbc_sqli_vul函数直接传入的username就拼接到了sql中,然后取执行返回信息,没有做任何防护。

jdbc_sqli_sec 再来看看安全的查询函数  

这里用到了PreparedStatement,是java.sql包中的接口,继承了Statement,包含已编译的 SQL 语句。

PreparedStatement st = con.prepareStatement(sql);是把该sql语句进行预编译,

这里的 st.setString(1, username); 就是把username添加引号传入sql语句(仅仅作为字符串),不会改变sql的语法结构了。

改成这个方法访问就不能注入了

当然预编译不是绝对安全的,因为有些地方不能使用预编译。

比如:order by 后面的表名、列名或者字段名,因为预编译只有setString()方法来加引号,

如果这个?位置参数本身是字符串但是又不需要引号,那么就不能预编译。还有order by asc/desc.

也就是说sql关键字、库名、表名、字段名、函数名等都不能预编译。

遇到这种情况使用预编译+白名单过滤能有效防止sql注入。

这篇讲的很好

MyBatis

MyBatis是一个基于Java的持久层框架,支持自定义SQL,存储过程和高级映射。MyBatis可以使用简单的XML或注释进行配置。

 几个可注入的的mybatisVuln函数

这里的mybatisSec01方法也存在sql注入

再来看一下02的

这里使用的是${}也就是直接拼接字符串,也和01类似

再看看03的使用的是order by asc,以升序排列

同样的没有做防护,可以被延时

 几个安全的mybatisSec函数

然后看看安全的01,跟进过来参数化了username #{}

02这里过来是int类型的id 只能输入int,不能构造sql语句去拼接了

03的化是没有可控参数的地方,直接写了order by id ,

还是来看看04 ,跟进这个sqlFilter方法

再用 FILTER_PATTERN来进行正则匹配

限制了输入字符只能是0-9 大小写字母和几个符号 _-.  这样做的防护

Velocity RCE

网上找的解释

Velocity是一个基于java的模板引擎(template engine),
它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。
它作为一款成熟的基于java的模板引擎,能够帮我们实现页面静态化,
同时它将Java代码与网页分开,使网站在其生命周期内更加可维护,并为Java Server Pages(JSP)或PHP提供了可行的替代方案。

模仿这里的SSTI写一个demo

这里我们给template赋值

大概的原理是这里定义一个$e变量,这个变量是继承所有类的基类Obejct的,可以调用父类Object的方法

通过反射获取到类getClass ,然后获取对象java.lang.Runtime,再反射获取getRuntime方法,然后再invoke调用exec方法去弹计算器。

这个没什么好调试的

这样再看看靶场中SSTI的代码

只需要这个template参数是可控的就能被反射获取

在这里可以直接输入

那么简单构造一下

#set($e=666);$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc")

url编码后:
%23set(%24e%3D666)%3B%24e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22%2Cnull).invoke(null%2Cnull).exec(%22calc%22)

传入就可以弹计算器了

Velocity模板引擎漏洞可参考

相关