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 column asc/desc.

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

如果这个?位置参数本身是字符串但是又不需要引号,那么就不能预编译。

还有 group by column,如果这个column是可控的。

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

 

ORDER BY 关键字用于对结果集按照一个列或者多个列进行排序。

可以看到想要实现对于这个cloumn字段的排序必须不加引号

 

 

 

GROUP BY 语句用于结合聚合函数,根据一个或多个列对结果集进行分组。

 

上面这种使用感觉这两个关键字有点类似,其实还是不一样,看看这个:

 

 

order by 是按表中某字段排列表中数据。

group by 是按某些字段分类。

 这个count(id),就看出来了order by 是用于排序执行结果后的也就是count(id)完再进行order by 只有一row

而group by 却有13row,说明group by是先分类了,再count(id)的。

如果要同时使用这两个关键字,order by会滞后。

这就是group by 分组完,又被order by给重新排序了

 

 

是不是又多了一种猜测字段数的关键字呢?

 

 

遇到这种情况使用预编译+白名单过滤能有效防止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模板引擎漏洞可参考

posted @ 2022-02-10 17:02  Erichas  阅读(815)  评论(0编辑  收藏  举报