教你怎么开发一个基于java的语义waf
今天在看腾讯介绍自己jdk的文章,其中提到了腾讯的waf是java写的,所以到github上搜索了一下,发现了一个java开发的语义waf
https://github.com/Kanatoko/libinjection-Java
这个项目的作者实在是太强了,使用的是libinjection的开发思路,所以我拿来研究了一下,产生了本文。
首先我写了一个有sql注入的接口如下,代码逻辑是name是sql拼接点,如果sql被库识别为sql注入,那么就直接拦截掉。
其中的我们要注意,因为本次是研究性质的,所以我会用sqlmap直接跑这个接口,对未发现的payload直接在 Dirty SQLi found 中打印出来。
@RequestMapping("list2")
public User getList2(String name) {
//sql语句是 "select * from user where name='${name}'"
if (name == null) {
name = "dato";
}
boolean isSQLi = com.client9.libinjection.SQLParse.isSQLi(name);
if (isSQLi) {
return userMapper.getUserByName3("dato");
}
// 如果没有发现sql注入,则打印sql语句
System.out.println("Dirty SQLi found : " + name);
return userMapper.getUserByName3(name);
}
好,我们开始跑sqlmap了
./sqlmap.py -u "http://localhost:8082/list2?name=dato" --dbs -v 3 --level=5 --risk=3 -p name --dbms mysql
很遗憾已经出现了可以注入的payload
其中最终导致注入的 payload 是
[PAYLOAD] dato' AND GTID_SUBSET(CONCAT(0x71716a7171,(SELECT MID((IFNULL(CAST(schema_name AS NCHAR),0x20)),1,190) FROM INFORMATION
因为百度上分析libinjection的原理文章实在是太多了,我就不在这里反复写了
依照网上文章的解析可以发现,默认规则里少了一个GTID_SUBSET函数,所以我们需要在 SQLParse.java 增加这个函数的策略
加完这一行以后我们再试试,yeah!没办法注入了!
那么我们继续分析一下日志,上文我提到,我会把sqlmap投入的payload中没有拦截的打印在 Dirty SQLi found 中
所以我们可以看到很多类似于下图中的打印内容(数量太多,我只能讲一部分了)
很明显,一些探测是否是sql注入的payload还是很容易被放过去
所以我认为语义waf的趋势:
1)语义waf可以与rasp进行一次嵌入。因为rasp可以获取的输入数据都是层层转码后的数据,可以有效的避免各种sql绕过的手法。而且转码后再使用语义进行分析可以大大增加防护作用并减少整个系统的算力支出,所以将语义策略嵌入rasp是未来很好的降本增效的设计。
2)openrasp本身就存在常见的sql注入屏蔽策略,与我分析的sqlmap注入日志中部分payload是重合的,尤其是openrasp可以屏蔽sql报错,这本身就能防护住较多的sql注入场景。尤其是sql注入前期探测阶段时如果rasp屏蔽了sql报错,可以大大增加攻击者进行sql注入的难度。
没有kpi吗?本文又给了你们思路了哦。
禁止转载




