xxl-job子任务越权漏洞代码分析及修复代码分析(CVE-2024-42681)
字数 972 2025-08-30 06:50:35
XXL-JOB子任务越权漏洞分析及修复指南(CVE-2024-42681)
漏洞概述
XXL-JOB是一个分布式任务调度平台,在2.4.1版本中存在子任务越权漏洞。该漏洞允许普通用户通过在执行程序A上创建任务并使用子任务ID,从而执行管理员权限才能执行的执行程序B上的子任务。
漏洞原理分析
权限控制机制
XXL-JOB的权限控制主要通过两个关键方法实现:
- filterJobGroupByRole方法 - 用于过滤用户可查看的执行器组
public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all) {
List<XxlJobGroup> jobGroupList = new ArrayList<>();
if (jobGroupList_all != null && jobGroupList_all.size() > 0) {
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (loginUser.getRole() == 1) { // 管理员
jobGroupList = jobGroupList_all;
} else {
List<String> groupIdStrs = new ArrayList<>();
if (loginUser.getPermission() != null && loginUser.getPermission().trim().length() > 0) {
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
}
for (XxlJobGroup groupItem : jobGroupList_all) {
if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
jobGroupList.add(groupItem);
}
}
}
}
return jobGroupList;
}
- validPermission方法 - 用于验证用户对特定执行器组的操作权限
public static void validPermission(HttpServletRequest request, int jobGroup) {
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
if (!loginUser.validPermission(jobGroup)) {
throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username=" + loginUser.getUsername() + "]");
}
}
漏洞核心问题
漏洞存在于子任务处理逻辑中,具体在com.xxl.job.admin.service.impl.XxlJobServiceImpl类的子任务ID处理代码段:
if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
String[] childJobIds = jobInfo.getChildJobId().split(",");
for (String childJobIdItem: childJobIds) {
if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
if (childJobInfo==null) {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
}
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE,
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
}
}
}
关键问题点:
- 在添加/更新任务时,对子任务ID仅进行了存在性验证,未检查用户对子任务的权限
- 在执行任务时(
trigger方法),仅验证了用户对主任务的权限,未验证对子任务的权限
public ReturnT<String> trigger(XxlJobUser loginUser, int jobId, String executorParam, String addressList) {
if (loginUser == null) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("system_permission_limit"));
}
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(jobId);
if (xxlJobInfo == null) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
}
if (!hasPermission(loginUser, xxlJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("system_permission_limit"));
}
JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
return ReturnT.SUCCESS;
}
漏洞利用场景
假设:
- 普通用户A只有对执行器组1的权限
- 执行器组2中存在子任务ID为2的任务
利用步骤:
- 用户A在组1中创建任务
- 在子任务ID字段中填写"2"
- 系统仅验证子任务ID=2是否存在,未验证用户权限
- 执行任务时,系统仅验证用户对组1的权限
- 最终同时执行了组1的任务和组2的子任务2,实现越权
修复方案
官方修复方案主要做了以下改进:
- 在
add和update接口中添加LoginUser参数,用于获取当前用户信息 - 在子任务验证过程中添加权限检查:
// 伪代码示例
if (!hasPermission(loginUser, childJobInfo.getJobGroup())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "No permission for child job");
}
修复验证
验证修复是否有效的方法:
- 普通用户尝试添加不属于其权限范围内的子任务ID
- 系统应返回权限不足的错误提示
- 确保执行任务时也会验证用户对子任务的权限
安全建议
- 及时升级到修复漏洞的XXL-JOB版本
- 对于无法立即升级的系统,可考虑以下临时措施:
- 自定义拦截器检查子任务权限
- 限制普通用户创建包含子任务的任务
- 定期审计系统中的权限控制逻辑
- 实施最小权限原则,严格控制用户权限范围
总结
该漏洞暴露了XXL-JOB在子任务权限控制方面的不足,提醒开发者在设计类似功能时:
- 必须对所有涉及资源访问的操作进行权限验证
- 特别注意级联操作(如子任务)的权限控制
- 实施完整的权限验证链条,不遗漏任何环节