由于前段时间工作原因,Java代码审计的知识交流暂时搁置了,从这段时间开始我将继续开始分享我在学习代码审计时的遇到的问题以及我个人在学习时的感悟。在这里和大家共同讨论,一起进步。 本篇继上次搭建好的环境进行危险函数的学习,同时进行我们首次Java代码审计(大家还记得在学习PHP代码审计的时候,第一套自己审计的系统是什么吗),由简到难,在思想不断碰撞感觉很痛苦的时候,正是我们成长的时候,我觉得学习不就如此,也因如此。
首先我们启动之前的项目,先对项目进行黑盒测试,发现可能存在的问题以及漏洞点,在白盒审计时我们结合发现的漏洞点进行白盒审计分析。
在Java渗透测试中也会使用到很多中间件以及依赖,例如Druid、SpringBoot、Swagger、Mybatis、Tomcat等,他们自身可能也会存在一些漏洞,所以在Java渗透测试时也需要了解这些中间件以及依赖的历史漏洞,这不仅在渗透测试方面对我们有帮助,同样在代码审计中使用不同依赖的项目,在审计方法上可能也会有一定的变化。
目录扫描
目录扫描一般使用dirsearch,通过扫描可以发现一些后台接口,以及某些依赖的未授权的接口。
https://github.com/maurosoria/dirsearch
扫描结果如下:
通过dirsearch可以发现该项目存在swagger()未授权访问,里面记录了大量后端API接口信息。
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。 总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。
简单来说就是API接口管理与应用框架。
异常报错信息以及敏感信息泄露
通过dirsearch可扫描出大量4XX、5XX响应码的文件,有的时候Java异常处理没有做好的话就会在前端通过报错泄露一些敏感路径以及源码信息、版本信息等。
通过上篇环境搭建我们知道该项目存在Druid数据管理工具,该工具应配置错误会造成未授权访问,通过访问。
/druid/index.html
Druid如果存在未授权访问或登陆可暴力破解,进入监控页面的话,可以查看很多敏感信息,比如session信息,SQL执行情况等等。
由于Druid没有验证码校验,我们可以尝试通过Burp Intruder爆破出管理员账号密码。
登录页面抓包后,重放包发现并未提示验证码错误,而是账号密码错误,初步断定验证码可复用。通过burp Intruder进行暴力破解,成功跑出密码。
这里因为是测试环境就没有修改默认账号密码:admin/123456
通过上述弱口令登录后台,发现后台多处存储型XSS
系统管理=》用户管理=》新增用户处
系统管理=》岗位管理=》新增岗位处
系统监控=》操作日志
操作日志会记录你操作的IP以及操作了哪些模块,浏览器版本,详细信息会在前端显示你操作的数据,而且未做过滤。
既然没做过滤大家可以想想哪些点可以由我们人为控制呢?如果操作日志会记录前台的登录记录是不是在前台也可以打到管理员的Cookie呢?
登录admin
账号,访问系统管理 -> 用户管理
,点击新增
,添加越权测试使用的账号,如下图所示:
确定我们要越权删除的test账号的userId值,Burp抓包通过抓包确定我们要越权删除的userId值为15。
登录ceshiyuequan账号。使用该账号创建一个可以抓包的用户,方便后续测试越权。
删除Burp用户,并抓包修改userid值为我们要越权删除的账户id值
登录admin账户查看test账户是否被越权删除
开始此项目代码审计之前,首先要了解MVC以及项目目录结构,因MVC模式在上篇已经介绍过了,这里就不在赘述。 下面主要介绍一下代码审计前了解目录结构的重要性,就像PHP在代码审计之前需要了解该项目使用什么框架,每个目录分别是做什么用;Java也是一样的,了解这了些在审计时就会提高我们的审计效率。
在src/main下有两个子目录Java和resource
Java目录主要存放后端java代码。
resource目录主要存在前端js、html、css以及某些依赖文件。
在Java目录下还有一些常见的子目录:
annotation
:放置项目自定义注解controller/
: 存放控制器,接收从前端传来的参数,对访问控制进行转发、各类基本参数校验或者不复用的业务简单处理等。dao/
: 数据访问层,与数据库进行交互,负责数据库操作,在Mybaits框架中存放自定义的Mapper接口entity/
: 存放实体类interceptor/
: 拦截器service/
: 存放服务类,负责业务模块逻辑处理。Service
层中有两种类,一是Service
,用来声明接口;二是ServiceImpl
,作为实现类实现接口中的方法。utils/
: 存放工具类dto/
: 存放数据传输对象(Data Transfer Object),如请求参数和返回结果vo/
: 视图对象(View Object)用于封装客户端请求的数据,防止部分数据泄漏,保证数据安全constant/
: 存放常量filter/
: 存放过滤器而resource目录下
mapper/
: 存放Mybaits的mapper.xml文件static/
: 静态资源文件目录(Javascript、CSS、图片等),在这个目录中的所有文件可以被直接访问templates/
: 存放模版文件application.properties
或application.yml
: Spring Boot默认配置文件本项目大致请求流程:
Filter(过滤器)
和Interceptor(拦截器)
,然后根据请求的URL映射到绑定的Controller
,之后调用Service
接口类,然后再调用serviceImpl
接口实现类,最后调用DAO
。controller
:负责简单的逻辑处理和参数校验功能,之后调用Service。service
:接口类,主要负责业务模块逻辑处理。serviceImpl
:接口实现类,实现类实现service接口中的方法。DAO
:如果service涉及数据库操作就会调用dao。DAO主要处理数据库操作。DAO只做中间传递角色,涉及的SQL语句都写在了配置文件Mapper.xml中。位于src/main/resources/mapper
中。pom.xml文件
基本所有项目都会有该文件,该文件存放本项目用到的所有依赖以及依赖的版本号,类似于PHP中的phpinfo()。我们就可以通过查看该文件找到一些存在漏洞的第三方依赖,确认该依赖是否调用了存在漏洞的函数。
这里有一个IDEA的插件推荐给大家,他可以自动扫描pom.xml中存在漏洞的组件,对于刚刚接触Java代码审计的小伙伴感觉还是挺有帮助的。
IDEA=》setting=》插件中搜索=》MurphySec Code Scan
安装完成后在IDEA最下方会有该插件的图标,点击图标进行快速认证,在网页中注册账号完成认证即可开始扫描。
扫描结果如下图:
配置文件查看
配置文件都在src/main/resources
下面,名字通常为application.yml
或者application.properties
。配置文件存在数据库或其他组件的连接信息。可通过上述文件修改组件配置。
在黑盒测试中我们测试出该项目登录入口存在验证码复用,接下来我们通过代码审计分析该漏洞的形成原因。
首先登录框找到"name"属性,定位代码位置
在IDEA中全局搜索captcha关键字
在java/filter/verifyCodeFilter.java中发现VerifyCodeFilter类,该类中存在doFilterInternal()方法,该方法用来判断验证码是否正确。
doFilterInternal()方法中接收三个参数,HttpServletRequest类用来接收所有请求的信息,包括请求方法、请求大小、请求IP地址等。HttpServletResponse类用来接收返回信息,包括响应行、响应头以及响应体。
FilterChain(过滤器链)类 在一个 Web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以针对某一个 URL 进行拦截。如果多个 Filter 程序都对同一个 URL 进行拦截,那么这些 Filter 就会组成一个Filter 链(也称过滤器链)。 Filter 链用 FilterChain 对象表示,FilterChain 对象中有一个 doFilter() 方法,该方法的作用是让 Filter 链上的当前过滤器放行,使请求进入下一个 Filter。
首先if判断该请求方法是否为POST并且请求路径是否为/lgoin,如果都满足的话进入到if体中。
if体中首先使用HttpServletRequest类中getSession()获取用户session,然后使用getParameter()获取body中captcha值也就是获取用户输入的验证码,在session中getAttribute()获取服务端存存储的session中captcha参数值。
第一个if中判断输入的验证码是否为空值,如果不为空则不进入第一个if体,而第二个if判断了session中存放的验证码值是否为空,不为空则不进入if体,最后一个if判断输入的验证码值是否与服务器端中session中保存的验证码相同,如果不通则进入最后一个if抛出验证码错误提示。表面上看逻辑似乎没有问题,但是代码中没有每次请求都删除缓存里session中的验证码值,导致我们只要使用Burp将包拦截后就会造成爆破时session中验证码不会进行更新,导致验证码重用。
通过查看前端html文件发现该项目使用了layui框架,全局搜索layui发现使用版本为v2.5.6,在github中layui项目issue中发现该版本存在xss漏洞。
这里说明table模块存在xss漏洞
Layui.table有三种渲染方式,本项目中使用了方法渲染
,使用了table.render
。
在代码审计中,我觉得XSS其实不用看源码,遵循见框就插的原则就好了,通过查看源码发现其中是否存在编码或过滤,如果有的话在考虑如何绕过就好。
越权在渗透测试中也是比较常见也是开发人员在开发中容易忽略的一点,有时候可能由于权限逻辑较为复杂而导致代码逻辑出现问题,从而会导致横向越权,甚至纵向越权的风险。
通过上述黑盒测试路由api/user
中发现src/main/java/com/codermy/myspringsecurity/plus/admin/controller/
usercontroller.java中存在deleteUser()方法
deleteUser()方法通过userid删除用户,跟踪userService类下的deleteUser()方法查看具体的删除流程。
首先checkUserAllowed()判断删除的用户是否是admin用户,如果是admin用户则不允许删除。deleteRoleUserByUserId()、deleteUserJobByUserId()删除对应的角色和岗位关联信息。最后通过deleteUserById()删除用户。
在整个删除逻辑中,删除时只对admin账户进行判断,而删除时并未对其他任何用户进行权限的判断,所以除了admin账户不能删除之外,在数据包中通过userid可以删除任意用户,从而造成越权。
我感觉在Java代码审计初期可以结合Fortify扫描工具进行审计,因为在初期审计的过程中,我们在审计思路或者Java中危险函数的认识还不是特别熟悉,需要扫描工具进行辅助审计,就像我当时学习Java代码审计一样,初期使用seay来辅助自己进行审计。日积月累自己就会慢慢掌握代码审计的一种节奏以及思路。
Fotify使用教程如下:
https://blog.csdn.net/Michael_lcf/article/details/107521006
本篇是作者第一次审计JavaWeb项目,过程很坎坷,感觉Java依赖以及框架种类繁杂,而且框架依赖也会存在不同程度的安全问题,不同的框架有它自己的特性。虽然对比来说Java难度会比PHP稍大,但毕竟也还是有一点PHP审计基础,在Java审计的道路上应该不会遇到太大的问题。大家如果遇到了什么关于Java审计方面的问题也可以在下方留言一起交流,下篇会以一个开源OA系统进行Java审计的学习,可能会遇到一些困难,但是只要勇敢的迈出去,我相信没有什么解决不了的问题。小伙伴们下期再见!