freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Java代码审计一危险函数分析与利用(二)
2022-04-26 21:13:05
所属地 海外

0x01 前言

由于前段时间工作原因,Java代码审计的知识交流暂时搁置了,从这段时间开始我将继续开始分享我在学习代码审计时的遇到的问题以及我个人在学习时的感悟。在这里和大家共同讨论,一起进步。 本篇继上次搭建好的环境进行危险函数的学习,同时进行我们首次Java代码审计(大家还记得在学习PHP代码审计的时候,第一套自己审计的系统是什么吗),由简到难,在思想不断碰撞感觉很痛苦的时候,正是我们成长的时候,我觉得学习不就如此,也因如此。

1650504972_6260b50cc62d356f856b8.jpg!small

0x02 黑盒测试

首先我们启动之前的项目,先对项目进行黑盒测试,发现可能存在的问题以及漏洞点,在白盒审计时我们结合发现的漏洞点进行白盒审计分析。
在Java渗透测试中也会使用到很多中间件以及依赖,例如Druid、SpringBoot、Swagger、Mybatis、Tomcat等,他们自身可能也会存在一些漏洞,所以在Java渗透测试时也需要了解这些中间件以及依赖的历史漏洞,这不仅在渗透测试方面对我们有帮助,同样在代码审计中使用不同依赖的项目,在审计方法上可能也会有一定的变化。

1.信息收集

目录扫描

目录扫描一般使用dirsearch,通过扫描可以发现一些后台接口,以及某些依赖的未授权的接口。

https://github.com/maurosoria/dirsearch

扫描结果如下:

1650520582_6260f20626288d5c799a1.png!small

通过dirsearch可以发现该项目存在swagger()未授权访问,里面记录了大量后端API接口信息。

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。 总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。
简单来说就是API接口管理与应用框架。

1650520860_6260f31c6cb6229f2ad37.png!small

异常报错信息以及敏感信息泄露

通过dirsearch可扫描出大量4XX、5XX响应码的文件,有的时候Java异常处理没有做好的话就会在前端通过报错泄露一些敏感路径以及源码信息、版本信息等。

1650521493_6260f595b7b7dc5ed7227.png!small?1650521494165

2.暴力破解

通过上篇环境搭建我们知道该项目存在Druid数据管理工具,该工具应配置错误会造成未授权访问,通过访问。

/druid/index.html

1650522138_6260f81a9b7249879bed2.png!small?1650522138886

Druid如果存在未授权访问或登陆可暴力破解,进入监控页面的话,可以查看很多敏感信息,比如session信息,SQL执行情况等等。

由于Druid没有验证码校验,我们可以尝试通过Burp Intruder爆破出管理员账号密码。

3.验证码复用

登录页面抓包后,重放包发现并未提示验证码错误,而是账号密码错误,初步断定验证码可复用。通过burp Intruder进行暴力破解,成功跑出密码。

这里因为是测试环境就没有修改默认账号密码:admin/123456

1650763104_6264a5601278251c0615f.png!small

4.XSS

通过上述弱口令登录后台,发现后台多处存储型XSS

系统管理=》用户管理=》新增用户处

1650525616_626105b06d5d28360f2fb.png!small?16505256167591650525718_626106161d30b7f9174f1.png!small?1650525718387

系统管理=》岗位管理=》新增岗位处
1650525853_6261069dc4be7ea2ceef4.png!small?16505258541741650525902_626106ceda26f79d25a2f.png!small?1650525903211
系统监控=》操作日志

操作日志会记录你操作的IP以及操作了哪些模块,浏览器版本,详细信息会在前端显示你操作的数据,而且未做过滤。

既然没做过滤大家可以想想哪些点可以由我们人为控制呢?如果操作日志会记录前台的登录记录是不是在前台也可以打到管理员的Cookie呢?1650526317_6261086db3fd796c5d787.png!small?1650526318213

1650527040_62610b4083fddaf499a75.png!small?1650527040829

5.越权

登录admin账号,访问系统管理 -> 用户管理,点击新增,添加越权测试使用的账号,如下图所示:

1650534156_6261270cd0d87a4a9ade7.png!small?1650534157323

确定我们要越权删除的test账号的userId值,Burp抓包1650588630_6261fbd672fe0721f48df.png!small通过抓包确定我们要越权删除的userId值为15。1650588663_6261fbf77b3601163d32c.png!small

登录ceshiyuequan账号。1650589049_6261fd79555c071cc0bd0.png!small使用该账号创建一个可以抓包的用户,方便后续测试越权。

删除Burp用户,并抓包修改userid值为我们要越权删除的账户id值1650589229_6261fe2dbe973c26fc39e.png!small1650589232_6261fe303304fdc490eee.png!small

登录admin账户查看test账户是否被越权删除1650589320_6261fe88ebe836cd282ef.png!small

0x03 项目结构

开始此项目代码审计之前,首先要了解MVC以及项目目录结构,因MVC模式在上篇已经介绍过了,这里就不在赘述。 下面主要介绍一下代码审计前了解目录结构的重要性,就像PHP在代码审计之前需要了解该项目使用什么框架,每个目录分别是做什么用;Java也是一样的,了解这了些在审计时就会提高我们的审计效率。

在src/main下有两个子目录Java和resource

Java目录主要存放后端java代码。

resource目录主要存在前端js、html、css以及某些依赖文件。

1650590262_626202361ca7b278cbb82.png!small

在Java目录下还有一些常见的子目录:

  • annotation:放置项目自定义注解
  • controller/: 存放控制器,接收从前端传来的参数,对访问控制进行转发、各类基本参数校验或者不复用的业务简单处理等。
  • dao/: 数据访问层,与数据库进行交互,负责数据库操作,在Mybaits框架中存放自定义的Mapper接口
  • entity/: 存放实体类
  • interceptor/: 拦截器
  • service/: 存放服务类,负责业务模块逻辑处理。Service层中有两种类,一是Service,用来声明接口;二是ServiceImpl,作为实现类实现接口中的方法。
  • utils/: 存放工具类
  • dto/: 存放数据传输对象(Data Transfer Object),如请求参数和返回结果
  • vo/: 视图对象(View Object)用于封装客户端请求的数据,防止部分数据泄漏,保证数据安全
  • constant/: 存放常量
  • filter/: 存放过滤器
  • config/:某些依赖或框架的配置文件

而resource目录下

  • mapper/: 存放Mybaits的mapper.xml文件
  • static/: 静态资源文件目录(Javascript、CSS、图片等),在这个目录中的所有文件可以被直接访问
  • templates/: 存放模版文件
  • application.propertiesapplication.yml: Spring Boot默认配置文件

本项目大致请求流程:

  1. 用户请求URL发送到服务器,服务器解析请求后发送到后端代码处理请求。
  2. 在后端代码处,首先经过Filter(过滤器)Interceptor(拦截器),然后根据请求的URL映射到绑定的Controller,之后调用Service接口类,然后再调用serviceImpl接口实现类,最后调用DAO
  3. controller:负责简单的逻辑处理和参数校验功能,之后调用Service。service:接口类,主要负责业务模块逻辑处理。serviceImpl:接口实现类,实现类实现service接口中的方法。DAO:如果service涉及数据库操作就会调用dao。DAO主要处理数据库操作。DAO只做中间传递角色,涉及的SQL语句都写在了配置文件Mapper.xml中。位于src/main/resources/mapper中。

0x04 代码审计

1.信息收集

pom.xml文件

基本所有项目都会有该文件,该文件存放本项目用到的所有依赖以及依赖的版本号,类似于PHP中的phpinfo()。我们就可以通过查看该文件找到一些存在漏洞的第三方依赖,确认该依赖是否调用了存在漏洞的函数。

1650592209_626209d16ca069732d00a.png!small

这里有一个IDEA的插件推荐给大家,他可以自动扫描pom.xml中存在漏洞的组件,对于刚刚接触Java代码审计的小伙伴感觉还是挺有帮助的。

IDEA=》setting=》插件中搜索=》MurphySec Code Scan

1650592433_62620ab104dc29d1dd258.png!small

安装完成后在IDEA最下方会有该插件的图标,点击图标进行快速认证,在网页中注册账号完成认证即可开始扫描。

1650592527_62620b0fae7bd5b5aa8ab.png!small

扫描结果如下图:

1650592726_62620bd6cde239eae02a5.png!small?1650592727073

配置文件查看

配置文件都在src/main/resources下面,名字通常为application.yml或者application.properties。配置文件存在数据库或其他组件的连接信息。可通过上述文件修改组件配置。

1650594019_626210e35687fffbb9cb1.png!small?1650594019490

2.验证码复用

在黑盒测试中我们测试出该项目登录入口存在验证码复用,接下来我们通过代码审计分析该漏洞的形成原因。

首先登录框找到"name"属性,定位代码位置

1650594780_626213dc97687fc74baeb.png!small

在IDEA中全局搜索captcha关键字

1650605494_62623db67c77d03a4b3c9.png!small

在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。

1650608213_626248556e3e8a8216efd.png!small

首先if判断该请求方法是否为POST并且请求路径是否为/lgoin,如果都满足的话进入到if体中。

1650609035_62624b8bd5c9bc46719b5.png!small?1650609036315

if体中首先使用HttpServletRequest类中getSession()获取用户session,然后使用getParameter()获取body中captcha值也就是获取用户输入的验证码,在session中getAttribute()获取服务端存存储的session中captcha参数值。

1650762025_6264a1292be202137ae00.png!small

第一个if中判断输入的验证码是否为空值,如果不为空则不进入第一个if体,而第二个if判断了session中存放的验证码值是否为空,不为空则不进入if体,最后一个if判断输入的验证码值是否与服务器端中session中保存的验证码相同,如果不通则进入最后一个if抛出验证码错误提示。表面上看逻辑似乎没有问题,但是代码中没有每次请求都删除缓存里session中的验证码值,导致我们只要使用Burp将包拦截后就会造成爆破时session中验证码不会进行更新,导致验证码重用。

1650762493_6264a2fd47600b83d9cea.png!small

3.XSS

通过查看前端html文件发现该项目使用了layui框架,全局搜索layui发现使用版本为v2.5.6,在github中layui项目issue中发现该版本存在xss漏洞。

1650765591_6264af17ed8c8af4023ac.png!small

这里说明table模块存在xss漏洞

https://github.com/layui/layui/issues/711

1650765970_6264b092af65ace53bda6.png!small

Layui.table:

https://www.layuion.com/doc/modules/table.html#use

Layui.table有三种渲染方式,本项目中使用了方法渲染,使用了table.render

1650766221_6264b18da4e84dc803a48.png!small

在代码审计中,我觉得XSS其实不用看源码,遵循见框就插的原则就好了,通过查看源码发现其中是否存在编码或过滤,如果有的话在考虑如何绕过就好。

4.越权

越权在渗透测试中也是比较常见也是开发人员在开发中容易忽略的一点,有时候可能由于权限逻辑较为复杂而导致代码逻辑出现问题,从而会导致横向越权,甚至纵向越权的风险。

通过上述黑盒测试路由api/user中发现src/main/java/com/codermy/myspringsecurity/plus/admin/controller/usercontroller.java中存在deleteUser()方法

1650767341_6264b5edc57ce7da91d2e.png!smalldeleteUser()方法通过userid删除用户,跟踪userService类下的deleteUser()方法查看具体的删除流程。

首先checkUserAllowed()判断删除的用户是否是admin用户,如果是admin用户则不允许删除。deleteRoleUserByUserId()、deleteUserJobByUserId()删除对应的角色和岗位关联信息。最后通过deleteUserById()删除用户。

1650768134_6264b9062aa0dabaaf80d.png!small

1650772700_6264cadc5e616c840a52c.png!small?1650772700627

在整个删除逻辑中,删除时只对admin账户进行判断,而删除时并未对其他任何用户进行权限的判断,所以除了admin账户不能删除之外,在数据包中通过userid可以删除任意用户,从而造成越权。

5.Fortify扫描器

我感觉在Java代码审计初期可以结合Fortify扫描工具进行审计,因为在初期审计的过程中,我们在审计思路或者Java中危险函数的认识还不是特别熟悉,需要扫描工具进行辅助审计,就像我当时学习Java代码审计一样,初期使用seay来辅助自己进行审计。日积月累自己就会慢慢掌握代码审计的一种节奏以及思路。

Fotify使用教程如下:

https://blog.csdn.net/Michael_lcf/article/details/107521006

1650778828_6264e2ccb34e713f4cb12.png!small?1650778829133

0x05 下期内容预告:Java代码审计一开源办公系统 OASYS(三)

本篇是作者第一次审计JavaWeb项目,过程很坎坷,感觉Java依赖以及框架种类繁杂,而且框架依赖也会存在不同程度的安全问题,不同的框架有它自己的特性。虽然对比来说Java难度会比PHP稍大,但毕竟也还是有一点PHP审计基础,在Java审计的道路上应该不会遇到太大的问题。大家如果遇到了什么关于Java审计方面的问题也可以在下方留言一起交流,下篇会以一个开源OA系统进行Java审计的学习,可能会遇到一些困难,但是只要勇敢的迈出去,我相信没有什么解决不了的问题。小伙伴们下期再见!

# java # Java代码审计 # 小白学Java审计
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录