【安全工具】浅谈编写Java代码审计工具

介绍

笔者是大四学生,初涉安全的萌新,如果文章有错误之处还请大佬指出!

最初考虑采用纯正则等方式匹配,但这种方式过于严格,程序员编写的代码有各种可能的组合

于是尝试自行实现Java词法分析和语法分析,稍作尝试后发现这不现实,一方面涉及到编译原理的一些算法,另外相比C语言等,Java语言本身较复杂,不是短时间能搞定的,深入研究编译原理背离了做审计工具的目的

后来找到了几种解决方案:Antlr,JavaCC,JDT,javaparser

经过对比,最终选择javaparser项目,该项目似乎是基于JavaCC,核心开发者是effective java的作者。使用起来比较方便,可以简单地以依赖的方式导入


笔者本想采用Golang编写该工具,查找相关资料后发现,Golang本身提供AST库,可以对Golang本身做语法分析,但找不到实现Java语法分析的库(考虑后续复习下编译原理自己尝试)

实例

javaparser最根本的类是CompilationUnit,如果我们想对代码做分析,首先需要实例化该对象


给出一段最简单的XSS代码


针对于该案例,我们写审计工具的原理

从import来看,比如有request和response,以证明这是HttpServlet

从类来看,必须继承自HttpServlet才能证明这是Servlet

如果req.getParameter得到的值被write了,认为这是XSS

验证导包

关于验证导入包的情况,简单做了一个方法


如果要验证请求和相应包的导入情况



获得类节点

首先拿到Demo这个Class,因为一个java文件中不一定只有一个类


进一步,我们需要判断该类是否继承自HttpServlet


只有得到类节点,才可以继续遍历抽象语法树拿到方法等信息

获得方法

遍历得到方法节点,并且拿到具体的请求和响应参数名称

之所以要拿到方法参数名,是为了做进一步的追踪



确认参数可控

审计漏洞的关键点就在于参数的可控,这也是难点

就本案例而言,如果某个参数是req.getParameter("...")获取的,那么就可以认为是可控

实际上这个req并不一定是req,可能是request,requ等,这也是上一步需要一个map保存的原因

可以加上参数校验


获取所有的赋值表达式,确定是否调用了req.getParameter这样的参数

并且参考上文的方式使用map保存这个参数结果,用于后续校验



确定触发点

触发点在本案例中是resp.getWriter().write()

这是一个方法调用,所以搜索MethodCallerExpr


针对于这个基础案例,可以再加入几个规则,针对于response.getOutputStream方式



测试

尝试让原来的XSS代码复杂一些,看看审计的效果


运行后成功检测到XSS


结尾

这篇文章只针对最基本的Servlet XSS做了审计,实际上无论从广度还是深度,都有巨大的工作量:

广度:SQL注入,XXE,反序列化,文件上传,CSRF等漏洞的审计

深度:如果代码对Servlet做了一定的封装,或者需要跨多个java文件分析

可控参数的追踪:从controller层传入参数到返回,这个参数经历了些什么

代码在github:https://github.com/EmYiQing/XVulnFinder

简单写了个输出html的页面:

最后

【获取网络安全学习资料以及工具】可以关注私我

你可能感兴趣的:(【安全工具】浅谈编写Java代码审计工具)