RBAC管理系统审计记录
环境搭建
环境依赖
- Windows
- idea2022
- jdk 8
- RBAC源码
- phpstudy的mysql 5.6.7
简易搭建流程(Windows下)
- 直接使用idea打开项目,然后选中右上角的项目构建
- 项目中有几处需要修改:
○ 1、 要开启phpstudy的mysql,然后创建rbac数据库,并将源码中的rbac.sql数据导入进数据库
○ 2、在全局中搜索application.yaml文件,修改其中的数据库密码为phpstudy中设置的用户名密码
○ 3、使用admin/123456登录炼石计划后台进入系统
○ 4、使用admin/admin登录sql监控
○ 5、使用idea自动下载系统所需所有依赖包
○ 6、 系统访问url:http://127.0.0.1:8088
系统审计
- java代码审计,一般都是基于maven的web项目,然后使用spring框架,或者是基于tomcat的web项目,使用spring框架
- 审计时,要先关注pom.xml文件,这个文件是Maven进行工作的主要配置文件。在这个文件中我们可以配置Maven项目的groupId、artifactId和version等Maven项目必须的元素;可以配置Maven项目需要使用的远程仓库;可以定义Maven项目打包的形式;可以定义Maven项目的资源依赖关系等等。
漏洞审计
SQL注入
- 从pom.xml文件中可以发现是使用了mybatis进行sql语句的操作
mybatis
- MyBatis支持两种参数符号,一种是#,另一种是$。
- 使用参数符号#的句子:
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT * FROM PERSON WHERE ID = #{id}</select>
- MyBatis会创建一个预编译语句,生成的代码类似于
*// Similar JDBC code, NOT MyBatis…String selectPerson = "SELECT * FROM PERSON WHERE ID=?";PreparedStatement ps = conn.prepareStatement(selectPerson);ps.setInt(1,id);
- 参数会在SQL语句中用占位符”?”来标识,然后使用prepareStatement来预编译这个SQL语句。
- 在默认情况下,MySQL Connector/J只不过是把selectPerson做了一下转义,前后加了双引号,拼接到SQL语句里面,然后再交给MySQL执行。另一种使用参数符号$时,MyBatis直接用字符串拼接把参数和SQL语句拼接在一起,然后执行。这种操作就是十分危险的了,很容易产生sql注入
- 所以对于mybatis进行sql操作的,我们可以直接搜索${来判断
mybatis拼接sql有下面两种方式:
#{} 告诉mybatis创建一个预编译语句(PreparedStatement)参数,在JDBC中,这样的一个参数
在SQL中会由一个"?"来标识,并被传递到一个新的预处理语句中
${} 仅仅是纯粹的string替换,在动态SQL解析阶段将会进行变量替换,类似于直接替换字符串,会
导致SQL注入产生。
一些不能使用#{}的场景:
表名/字段名 如果预编译了,就没法查了
order by/group by
like模糊查询
in
- 直接搜索关键字${
- 所以我们在代码审计阶段进行SQL注入漏洞挖掘时,应关注 xxxMapper.xml 中使用 ${} 凭借SQL的地方。推荐使用搜索关键字符,win快捷键 CTRL+SHIFT+F (PS.设计xml的目的是用作数据交换,当然也可以用作保存数据。xml保存数据具有平台无关,规范化。通过提供方提供的读取程序就可以读取出xml数据。)
- 调出 Find in path ,file mask选择文件夹类型为*.xml,输入关键字符${}(在文件中查找)
- 点击进⼊DictMapper.xml向上找调⽤src/main/resources/mybatis-mappers/DictMapper.xml
- 先双击DictMapper.xml文件定位到关键字,然后跟id=getFuzzyDictByPage到声明处DictDao.java,然后再转到函数引用文件到DictServicelmpl.java,在通过跟踪调用到DictController.java文件
注入点一:/api/dict
http://127.0.0.1:8088/api/dict?page=1&limit=10&dictName=if(1=1,1,exp(710))
dictName参数为注⼊点
注入点二:/api/user
http://127.0.0.1:8088/api/user?
page=1&limit=10&userName=if(2=2,1,exp(710))&nickName=if(1=1,1,exp(710))
userName和nickname处均存在注入
越权漏洞
越权删用户
- 漏洞代码
@Override
public int deleteUser(Integer userId) {
checkUserAllowed(new MyUser(userId));
roleUserDao.deleteRoleUserByUserId(userId);
userJobDao.deleteUserJobByUserId(userId);
return userDao.deleteUserById(userId);
}
- 观察这段代码可以发现会先对输入的可控userid进行check,然后会先删除role再删除用户,其中没有任何的其他鉴权
- 跟一下checkUserAllowed()函数到UserServiceImpl.java文件
public void checkUserAllowed(MyUser user) {
if (!StringUtils.isEmpty(user.getUserId()) && user.isAdmin())
{
throw new MyException(ResultCode.ERROR,"不允许操作超级管理员用户");
}
}
- 这里可以发现只要userid不为空或者不是管理员就可以删除,中间也未做其他鉴权判断,这样就导致会产生越权删除其他用户风险