# JeecgBoot Remote Code Execution Vulnerability Summary ## Vulnerability Overview JeecgBoot has a **second-order remote code execution (RCE)** vulnerability. The vulnerability stems from an insecure reflection mechanism in the `FillRuleUtil` component. The `/sys/fillRule/edit` endpoint lacks role-based authorization and input validation, allowing attackers to modify the `ruleClass` parameter (e.g., injecting `org.apache.commons.collections3.functors.InvokerTransformer`) and store malicious class names in the database. When an administrator or user later creates a department via `/sys/sysDepart/add`, the application reads this malicious rule from the database and instantiates the malicious class using `Class.forName().newInstance()`, leading to arbitrary code execution. ## Impact Scope * **Affected Versions**: <= v3.9.1 * **Affected Components**: * `SysFillRuleController.java` (L96-100) * `SysDepartController.java` (L213-230) * `SysDepartServiceImpl.java` (L187-227) * `FillRuleUtil.java` (L30-84) * **Entry Points**: * Injection Point: `POST /sys/fillRule/edit` * Trigger Point: `POST /sys/sysDepart/add` ## Remediation Measures * **Authorization Fix**: Exploiting the vulnerability requires standard authentication but completely lacks proper role-based authorization. Implement strict RBAC (Role-Based Access Control) to prevent regular users from overwriting rules. * **Input Validation**: Perform strict whitelist validation on parameters such as `ruleClass`, prohibiting reflection loading of unintended classes. * **Dependency Management**: Ensure no vulnerable gadget chains (e.g., Apache Commons Collections) exist on the classpath. ## POC / Exploit Code ### Malicious Payload (Phase 1) ```json { "id": "existing_fill_rule_id", "ruleCode": "org_num_role", "ruleClass": "org.apache.commons.collections3.functors.InvokerTransformer", "ruleParams": "{\"methodName\": \"exec\", \"arg0\": [\"calc.exe\"]}" } ``` ### Trigger Point Code (Phase 3: Detonation) ```java // Line 36-38: Query sys_fill_rule table QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("rule_code", ruleCode); // "org_num_role" JSONObject entity = JSON.parseObject(JSON.toJSONString(sql.getOne(queryWrapper))); // Line 44: Extract ruleClass from database (now attacker-controlled) String ruleClass = entity.getString("ruleClass"); // // Line 77 - UNSAFE REFLECTION - HERE !!! IFillRuleHandler ruleHandler = (IFillRuleHandler) Class.forName(ruleClass).newInstance(); return ruleHandler.execute(params, formData); ```