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)
传入就可以弹计算器了