某RBAC管理系统

源码

  已经下载至本地:

C:\Users\chenyuanhang\Documents\WorkSpace\security\RefiningStone-RBAC(最终版)

A、所需环境

  本项目安装基于windows 10操作系统搭建而成。

1、Java环境部署

  Java版本为8就行了

  ‍

  JDK下载链接:

https://www.oracle.com/java/technologies/downloads/#java8-windows

  安装步骤操作简单,只需下一步即可,不过多赘述。

  ‍

2、Maven环境部署

3、Mysql环境部署

  个人偏好于使用phpstudy,它集成了很多常用组件,如apache,mysql等。作为练习,方便至极,一键启动即可使用。

  启动cmd命令行,进入mysql数据库,命令:mysql -u root -p​,然后键入你的密码。

  使用命令创建数据库:create database rbac;

  导入rbac.sql​文件,该文件位于RefiningStone-RBAC​ 项目文件夹内。可以使用mysql工具导入

B、环境搭建

  安装整体过程首先将数据导入mysql数据库中,然后将项目导入IDEA中,修改配置文件中数据库信息,点击启动即完成环境搭建。

  使用idea打开项目

  进入src - main - resources - application.yml​,对配置文件进行相关修改,主要修改Mysql数据库连接账号密码,具体可以去phpstudy下数据库处查看。

  ​image

  打开浏览器,键入http://127.0.0.1:8088/login.html​,访问项目。

  ‍

  ​image

  ‍

渗透测试

目录爆破

  使用dirsearch进行目录爆破

  ​image

  ​image

未授权访问

  根据上面的结果可以看到有一些目录,首先先去看/actuator/env​ ,因为通过他可以看到 SpringBoot 载入了哪些 properties,以及 properties 的值(这个里面会自动用*替换 key、password、secret 等关键字的 properties 的值进行脱敏)

  ​image

  ‍

  其他的一些常见的:

路径 描述
/autoconfig 提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没通过
/beans 描述应用程序上下文里全部的Bean,以及它们的关系
/env 获取全部环境属性
/configprops 描述配置属性(包含默认值)如何注入Bean
/dump 获取线程活动的快照
/health 报告应用程序的健康指标,这些值由HealthIndicator的实现类提供
/info 获取应用程序的定制信息,这些信息由info打头的属性提供
/mappings 描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系
/metrics 报告各种应用程序度量信息,比如内存用量和HTTP请求计数
/shutdown 关闭应用程序,要求endpoints.shutdown.enabled设置为true
/trace 提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

登录爆破

  之前看配置文件发现了1个账户:

  ​image

  本人以为就是登录密码,直接登录爆出用户名密码错误!因此以为代码出现bug,又查询数据库发现账号是admin​密码是加密的,因此本人被误导了,并一直追踪调试,最终还是没有解决,最终发现这个配置文件中账户并非登录账户!浪费了许久时间!

  使用bp抓登录包:

  ​image

  响应包中文乱码,解决方案:改成UTF-8,以及font改成黑体

  ​image

  ​image

  回归正题,尝试登录看看:

  ​image

  乱填验证码试试:

  ​image

  验证码格式不对?抓包发送试试:

  ​image

  居然没有爆出验证码格式不对,那说明这个验证码的格式校验在前端,究竟有没有校验这个验证码呢?

  不管怎么输入,响应包只会返回“用户名或密码错误”,可能在校验密码错误的时候就返回了,还没到验证码校验这部分。

  不管验证码了,直接尝试爆破:

  设置payload,密码尽量设置哪种常见的dict,bp自带的不太行,少了很多东西。。。

  ​image

  ​image

  爆破成功了,账号:admin​,密码:123456

  果然验证码根本就没有校验,如果要检验的话,爆破起来就比较麻烦了。。。因为还要去找一些可靠的在线校验工具。。。

  ‍

  ‍

Druid登录爆破

  之前目录探针时发现了druid登录的链接,访问看看:

  ​image

  ​image

  试试用bp爆破:

  ​image

  获取到账号密码都为:admin

  ‍

  ‍

XSS测试

  ‍

  看见有输入框,就可以尝试xss,在角色管理​->新增​模块处存在xss,在菜单管理​->新增​那也存在xss注入,其他的模块就不一一测试了

  ​image

  提交后刷新页面就会弹窗。

  ​image

  ‍

  ‍

  在用户管理这里的查询也是,当插入payload时会引发全局异常​,此时会被记录得到异常操作日志​中。

  ​image

  这个项目还存在异常日志模块,并且触发了xss,

  在系统管理->异常日志中加载错误记录时就会触发。

  ​image

  -

  同样的,这样的xss有很多很多,因为很多地方都直接将错误记录了,对一些输入框的校验过滤可以说根本没有。

  只要能触发全局异常,在加载异常日志的时候都会引发xss弹窗。

  ‍

SQL注入

  用bp插件SQLIPy sqlmap来扫描可能存在的sql注入,这个插件可以在bp自带的插件商店上下载,但是需要安装Jython​环境,安装之后打开bp设置,把安装之后的jython路径​填写上:
image

  右键打开这个插件,调一下设置:

  ​image

  启动这个插件,把ip和端口号设置好,按照图上设置就行了,只要端口不冲突就行了,

  ​image

  打开sqlmap scanner,自己勾选一些设置,

  ​image

  划到最后面,开始扫描

  ​image

  你点击扫描之后可能没有反应,它这个插件响应很慢,开始之后挂在后台等一段时间再看

  ‍

  打开site map,可以查看到已经扫描到一些sql注入,是用户查询​部分存在SQL注入image

  ​字典查询​那块也存在sql注入

  ​image

  ‍

  根据payload可以实现sql注入。

  使用SQLmap​来扫描一下:

python sqlmap.py -r C:\Users\chenyuanhang\Documents\sqli.txt --dbs --batch

  ​sqli.txt​文件如下:

GET /api/dict?page=1&limit=10&dictName=adf HTTP/1.1
Host: 127.0.0.1:8088
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Connection: close
Referer: http://127.0.0.1:8088/api/dict/index
Cookie: JSESSIONID=340D9A618B59A2E8B0A5EAA3DEC72448; remember-me=YWRtaW46MTcxMDMwMjI4ODcyNTowYjdiNjAxNzZhMzg3NGFiOTgxNWYwODY1M2YzYjNjYg
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

  成功扫描出来一些数据库,执行如下:image

  来扫描出数据表来:

python sqlmap.py -r C:\Users\chenyuanhang\Documents\sqli.txt -D rbac --tables --batch

  ​image

  ‍

越权漏洞

  创建一个用户agnoy​,弹框提示密码默认为:123456

  ​image

  使用agony​账户登录,发现仅仅只能操作test6​这个账号

  ​image

  先抓一下删除包,仔细一看,删除操作需要参数userId​,以及Cookie

  ​image

  注意:Cookie​值必须正确,不然将无法删除

  ​userId​的值对应着数据库的表中user_id​的值

  ​​image​​

  尝试一下能不能直接删除test1​用户,返回成功,乱码不重要,居然成功了。

  ​image

  登录admin​,查看test1​已经删除了

  ​image

  数据库也同步删除了,实现了越权删除。。。

  ​image

  ‍

  ‍

  ‍

代码审计

信息收集

  • pom.xml漏洞挖掘

    通过分析pom文件,发现引入了swagger2,可能存在swagger接口文档泄露

    image

  发现fastjson版本<1.2.80,存在Fastjson漏洞。

  使用Fastjson 1.2.56​版本,该版本存在漏洞,如下图所示:

  ‍

  ​image

  在发现了第三依赖库存在漏洞版本时,可以进一步利用。

  但有时,尽管使用了带有漏洞版本的组件,但并没有使用存在漏洞的相关函数。

  比如Fastjson​反序列化漏洞,该项目实际并没有使用到parseObject​。

  注意:

  ​通过组件及版本寻找漏洞,最起码需要知道什么组件时干什么的,然后对于常见的组件看多了,也就知道什么版本有什么漏洞了,熟能生巧。

  • 查看配置文件

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

  数据库连接信息账号密码:

  ​image

  还有一个不知道是什么账户密码,如下图所示:

  ​image

  ‍

未授权访问

  查看到SpringSecurityConfig​这个配置文件下,

  ​image

  它放行了静态资源,包括一系列swagger-ui.html,和druid,actuator目录下的文件​,所以导致被目录爆破出来,从来达到未授权访问

  ​image

越权漏洞

  通过之前的渗透存在越权删除的情况下,直接逆向找到删除模块

  先进入controller层找到对应的控制器

  ​image

  最终定位到函数,

  ​image

  进入checkUserAllowed​,发现仅仅做了校验是否为空,以及不能操作超级管理员,并未对其他权限的用户进行校验。。

  ​image

  跟着删除用户整体流程逻辑走下来,发现userId是从用户侧获取的,也没有将userId与所删除的数据做关联,而且userId也不是从session中获取的,从而导致任意用户都可以调用该接口进行删除。

  并且用户ID值极易进行遍历,从而进行批量任意用户删除。

  它直接接受用户输入的userID​值,但是并未做很深究的校验,从而导致这个userId​可控,从而导致随便一个普通用户就可以操作其他同等权限的用户。

验证码校验

  定位到:com/codermy/myspringsecurityplus/security/filter/VerifyCodeFilter.java​这个文件,可以看到仅仅做了验证码不能为空的校验(下面并不是我注释的!)看到他只有在验证码为空时才会置空销毁掉缓存中存储的验证码,这也就是说不为空的时候就算使用了错误的验证码也可以通过校验,这就是验证码可以重用的原因。

  ​image

  这就导致你可以随意输入验证码。当然前端可能有些简单的校验,比如长度之类的。。。这都不是问题,

SQL注入漏洞挖掘

  本项目基于Mybatis操作数据库,我们了解到Mybatis错误的配置会导致SQL注入漏洞的存在,这是我们挖掘SQL注入漏洞的入口点。

  我们先来回顾下:

  Mybatis拼接sql有下面两种方式:

  ​#{}​告诉 MyBatis 创建一个预编译语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中,

  ​${}​ 仅仅是纯粹的 string 替换,在动态 SQL 解析阶段将会进行变量替换,直接替换字符串,会导致SQL注入产生。

  一些不能使用#{}​的场景:

表名/字段名
order by/group by
like模糊查询
in

  因此,我们在代码审计阶段进行SQL注入漏洞挖掘,应关注xxxxMapper.xml​中使用${}​拼接SQL的地方,全局搜索关键字符。Windows快捷键CTRL+SHIFT+F​(如果快捷键冲突,需自己更改)。

  调出Find in path​,File mask选择文件类型为*.xml​,键入关键字符${​,如下图所示:

  这是UserMapper.xml​文件,存在使用${}

  ​image

  通过上述搜索,发现了SQL语句使用了like​语句并使用$​进行拼接参数,这种情况下无疑是存在SQL注入的。

  这和我们渗透测试时发现的用户查询​功能存在SQL是对应的。。

  我们逆向追踪所拼接的参数,看看是从前端哪个地方输入进来的。

  ①、通过搜索还发现src/main/resources/mybatis-mappers/DictMapper.xml​文件,第17行,存在使用like​语句以及$​拼接SQL。

  ​image

  ‍

  安装了Free Mybatis Plugin​插件后,左侧会有绿色箭头,点击即可跳转到mapper接口处,也就是DAO层文件,如下图所示:

  ​image

  ②、我们继续向前找到谁调用了DictDao.java​中的getFuzzyDictByPage​,Windows系统按住ctrl​键,鼠标左击getFuzzyDictByPage​进入该方法,或者说查看谁用了这个方法。如下图所示:

  ‍

  ③、点击进入DICTServiceImpl.java​文件,发现getDictPage​函数中使用了getFuzzyDictByPage​,如下图所示:

  ​image

  ‍

  ④、继续按住ctrl​键,鼠标左击getDictPage​方法,点击后,直接进入到了DictController​文件中第43行,如下图所示:

  ​image

  找到Controller层后,发现并没有dictname​参数,因为Controller中以实体类接收表单数据。进入MyDict​​发现该类为实体类,其中定义多个参数,如下图所示:

  ​image

  ⑥、经过上述参数逆向追踪,确定了dictName为字典名称​位于查询字典功能​处,不出所料,在渗透测试中也发现字典查询​功能存在sql注入。

  漏洞成因分析完了可能会有疑问使用拼接容易产生SQL注入,哪为什么不全部使用预编译?使用${}拼接是有一些有优点的,他可以实现一些动态的功能,比如指定表名,列名,排序字段等等。而在某一些场景下还真不能使用#{}去进行预编译。举个栗子:

  1. 模糊查询 like

  就是上面发现的地方,拿另外一个sql语句来看:

select * from users where name like '%#{name}%' 

  这时候使用#号会直接报错,而经验不足的新手程序员就直接改成$号,这样如果没有对用户输入再有额外的过滤转义那势必产生SQL注入,而正确写法应该是这样的:

select * from users where name like contact('%', #{name}, '%')

而这个项目中存在注入的代码说这样写的:
di.dict_name like CONCAT('%', ${dictName}, '%')

  1. in之后有多个参数

  in之后多个id查询时使用# 同样会报错,就比如:

select * from users where id in (#{ids})

  正确用法应该是使用foreach标签,如下:

select * from users where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
  #{id}
</foreach>

  1. order by

  使用#{}来动态拼接order by的字段或方向,可能会导致SQL注入,比如:

@Select("select * from user order by #{column} #{direction}")
List<User> selectUsers(@Param("column") String column, @Param("direction") String direction);

  修改方案:使用${}。

@Select("select * from user order by ${column} ${direction}")
List<User> selectUsers(@Param("column") String column, @Param("direction") String direction);

  或者也可以使用orderby方法来构建动态排序。

SelectStatementProvider selectStatement = select(user.allColumns())
    .from(user)
    .orderBy(sortColumn(sortSpecification(column, direction)))
    .build()
    .render(RenderingStrategies.MYBATIS3);

Swagger接口文档泄露

  通过分析pom文件,发现引入了swagger2

  ​image

  尝试使用swagger2默认访问地址:Swagger UI

  成功登录:

  ​image

  如果要进行操作的话,需要token!

  ‍

XSS

  在开发一个网站项目时,开发人员不可能将所有的参数分别做过滤或转义。最好的办法是统一写个过滤/转义XSS的Filter。

  在本项目中全局搜索,没发现XSS相关过滤器(Filter)或拦截器(Interceptor)。初步判断存在XSS漏洞。

  对后端简单分析后,初步判断存在XSS漏洞,然后我们对前端进行分析,是否有转义机制。

  在了解了整个项目之后,发现前端使用了Thymeleaf模板引擎​和Layui框架​。

  Thymeleaf中th:text​标签进行渲染的时候,默认对特殊字符进行了转义,th:utext​不会将字符转义。也就是说使用了th:utext​标签会出现XSS漏洞。经过全局搜索,发现只有两处使用了th:text​标签。没有地方使用th:utext​标签。

  其经过分析src/resouces/templates/​下的html文件。发现本项目前端还使用了Layui框架​。

  全局搜索Layui​关键字,得到layui使用版本为2.5.6

  通过翻阅Layui的github中ISSUES发现该版本存在XSS漏洞。链接https://github.com/sentsin/layui/issues/711

  ‍

  在渗透测试阶段挖掘到了XSS漏洞。经过从代码层分析,该漏洞的出现主要分为两点:

  • 一是:后端没有对用户输入的字符进行转义或过滤。
  • 二是:使用的前端框架存在XSS漏洞版本,也没有对返回到前端的参数进行过滤或转义。

  ‍

  ​imageimage

  ​​image​​

  但是还有一个属性——th:value​,来到resources/templates/system/role/role-edit.html​这里使用了th:value​属性来设置输入框的值,而th:value​属性不会对HTML标签进行转义,恶意输入也会被浏览器执行,导致产生XSS。

  ​image

  ​image

  ‍

  ‍

  知识补充:

  Java中可用的10种方法,用于有效预防跨站脚本攻击(XSS)

  1. 输入验证和过滤

    • 在后端接口中,对用户提交的数据进行严格的验证和过滤。确保输入不包含恶意脚本。
    • 使用白名单过滤,只允许特定的HTML标签和属性。
  2. 转义输出

    • 在将数据插入到页面中时,使用适当的转义函数,例如htmlspecialchars​,以防止恶意脚本被执行。
    • 对于前端模板引擎,确保插入的数据都经过了转义处理。
  3. Cookie 安全

    • 设置HttpOnly​标志,以防止JavaScript访问敏感的Cookie信息。
    • 使用Secure​标志,仅在HTTPS连接中传输Cookie。
  4. CSP(内容安全策略)

    • 配置CSP以限制页面中可以执行的脚本来源。
    • 禁止内联脚本,只允许从受信任的域加载脚本。
  5. 会话管理

    • 避免在URL中传递敏感信息,例如会话ID。
    • 使用随机生成的会话ID,并定期更换。
  6. HTTP响应头

    • 设置适当的X-Content-Type-Options​和X-XSS-Protection​响应头。
    • 启用浏览器的内置XSS过滤器。
  7. 使用安全的框架和库

    • 使用安全性良好的框架和库,例如Spring Security。
    • 避免自己手动处理输入和输出,而是使用已有的安全解决方案。

  ‍

  ‍

Fortify扫描

  待完成

posted @ 2024-02-29 19:13  itchen-2002  阅读(64)  评论(0编辑  收藏  举报