通过审计cms来掌握CodeQL的使用
字数 2174 2025-08-10 12:17:54
通过审计CMS掌握CodeQL的使用 - 华夏ERP代码审计实战指南
一、环境搭建
1.1 目标系统准备
- 目标系统: 华夏ERP v2.3
- 源码地址: https://github.com/jishenghua/jshERP/tree/v2.3
- 数据库准备:
- 创建数据库:
jsh_erp - 导入SQL文件:
docs/jsh_erp.sql
- 创建数据库:
- 运行环境:
- 主启动类:
src\main\java\com\jsh\erp\ErpApplication.java
- 主启动类:
- 默认凭证:
- 用户名:
jsh - 密码:
123456
- 用户名:
1.2 开发环境配置
- 使用IDEA导入项目并自动加载依赖
- 确保Maven依赖正确解析
二、第三方组件扫描
2.1 使用PomEye进行组件扫描
- 工具介绍: PomEye是作者开发的Maven依赖分析工具
- 下载地址: https://github.com/feiweiliang/PomEye
- 关键发现: 存在漏洞版本的fastjson组件
2.2 CodeQL审计目标
- 定位fastjson的
parse或parseObject方法调用点 - 确认参数是否可控
三、系统架构分析
3.1 关键包结构分析
| 包名 | 功能描述 | 重要类/方法 |
|---|---|---|
| config | 系统配置 | Swagger配置、Mapper路径配置、分页拦截器 |
| constants | 常量定义 | SERVICE_SUCCESS_CODE = 200、USER_IS_MANAGER = 0 |
| filter | 过滤器 | 用户登录校验过滤器 |
| controller | 业务控制器 | 多个功能控制器 |
| exception | 自定义异常 | 调试辅助 |
| utils | 工具类 | 各种辅助工具 |
3.2 关键控制器分析
-
AccountController
findBySelect: 查找下拉框中所有账户ID和用户名getAccount: 获取所有账户findAccountInOutList: 查找主表出入库涉及的账户updateAmountIsDefault: 更新默认账户
-
DepotController
- 仓库操作相关功能
-
FunctionController
- 用户功能权限管理
-
InOutItemController
findBySelect: 查找收支项目deleteInOutItem: 删除收支项目
-
UserController
resetPwd: 密码重置deleteUser: 用户删除getUserList: 获取用户列表- 登录/登出功能
-
SystemConfigController
deleteConfig: 删除系统配置
-
SupplierController
updateAdvanceIn: 更新供应商预付款findBySelect: 查找客户/供应商信息- 导入导出功能
四、白盒审计发现
4.1 越权漏洞
4.1.1 任意密码重置
位置: UserController.resetPwd
@PostMapping(value = "/resetPwd")
public String resetPwd(@RequestParam("id") Long id,
HttpServletRequest request) throws Exception {
Map<String, Object> objectMap = new HashMap<String, Object>();
String password = "123456"; // 硬编码密码
String md5Pwd = Tools.md5Encryp(password);
int update = userService.resetPwd(md5Pwd, id);
}
问题:
- 无权限验证
- 密码硬编码为"123456"
- 仅需用户ID即可重置任意用户密码
4.1.2 任意用户删除
位置: UserController.deleteUser
@PostMapping("/deleteUser")
@ResponseBody
public Object deleteUser(@RequestParam("ids") String ids)throws Exception{
JSONObject result = ExceptionConstants.standardSuccess();
userService.batDeleteUser(ids); // 批量删除用户
return result;
}
问题:
- 无权限验证
- 可批量删除任意用户
4.2 信息泄露漏洞
位置: UserController.getUserList
@GetMapping(value = "/getUserList")
public JSONArray getUserList(HttpServletRequest request)throws Exception {
JSONArray dataArray = new JSONArray();
try {
List<User> dataList = userService.getUser();
if (null != dataList) {
for (User user : dataList) {
JSONObject item = new JSONObject();
item.put("id", user.getId());
item.put("userName", user.getUsername());
dataArray.add(item)
}catch(Exception e){
e.printStackTrace();
}
return dataArray;
}
问题:
- 无权限验证
- 泄露所有用户ID和用户名信息
4.3 鉴权绕过漏洞
位置: LogCostFilter.doFilter
String requestUrl = servletRequest.getRequestURI();
if (requestUrl != null &&
(requestUrl.contains("/doc.html") ||
requestUrl.contains("/register.html") ||
requestUrl.contains("/login.html"))) {
chain.doFilter(request, response);
return;
}
绕过方式:
- 路径遍历绕过:
/register.html/../../user/getUserList
- 静态资源后缀绕过:
- 过滤器配置忽略
.css,.js,.jpg,.png等静态资源 - 可尝试添加后缀如
/user/getUserList.css
- 过滤器配置忽略
五、CodeQL审计实践
5.1 创建CodeQL数据库
codeql database create --language=java --source-root=jshERP erp-db
5.2 编写查询规则
5.2.1 查找fastjson调用点
import java
from MethodAccess call, Method method
where
method.getDeclaringType().hasQualifiedName("com.alibaba.fastjson", "JSON") and
(method.getName() = "parse" or method.getName() = "parseObject") and
call.getMethod() = method
select call, "Potential fastjson deserialization vulnerability"
5.2.2 查找无权限检查的控制器方法
import java
from Class c, Method m
where
c.getAnAnnotation().toString() = "@RestController" and
m.getDeclaringType() = c and
not exists(MethodAccess ma |
ma.getMethod().getName() = "checkLogin" and
ma.getEnclosingCallable() = m
)
select m, "Controller method without login check"
5.2.3 查找硬编码密码
import java
from Variable v, StringLiteral s
where
v.getInitializer() = s and
s.toString().matches("%123456%")
select s, "Hardcoded password found"
5.3 分析结果处理
- 验证每个发现的调用点是否确实存在安全问题
- 跟踪数据流确认参数是否可控
- 结合业务逻辑评估实际影响
六、修复建议
6.1 越权漏洞修复
- 添加权限验证注解:
@PreAuthorize("hasRole('ADMIN')")
@PostMapping(value = "/resetPwd")
public String resetPwd(...) { ... }
- 实现权限检查逻辑:
User currentUser = getCurrentUser();
if(!currentUser.isAdmin() && !currentUser.getId().equals(id)) {
throw new AccessDeniedException();
}
6.2 信息泄露修复
- 添加权限控制:
@GetMapping(value = "/getUserList")
@PreAuthorize("isAuthenticated()")
public JSONArray getUserList(...) { ... }
- 实施数据脱敏:
item.put("userName", maskUsername(user.getUsername()));
6.3 鉴权绕过修复
- 改进路径检查逻辑:
String normalizedPath = Paths.get(requestUrl).normalize().toString();
if(normalizedPath.equals("/register.html") || ...) {
...
}
- 严格限制静态资源访问:
@WebFilter(urlPatterns = {"/static/*"})
七、总结
本次审计通过CodeQL结合手动分析,发现了华夏ERP系统中的多个安全问题,包括:
- 多处越权操作(密码重置、用户删除)
- 敏感信息泄露
- 鉴权绕过漏洞
- 第三方组件风险
CodeQL在此次审计中发挥了重要作用,特别是在:
- 快速定位特定API调用点(fastjson)
- 识别缺少安全检查的方法
- 发现硬编码凭证等不良实践
建议开发团队:
- 实施严格的权限验证机制
- 修复已知的fastjson漏洞
- 改进过滤器的路径检查逻辑
- 定期进行代码安全审计