JeecgBoot SQL Injection in Dictionary Table Query (CWE-89)
概述
JeecgBoot (jeecg-boot) is vulnerable to SQL Injection (CWE-89) in its dictionary table query mechanism. The SysDictServiceImpl.getFilterSql method concatenates an attacker-controlled condition/filterSql value into a WHERE clause, and SysDictMapper.xml interpolates it using MyBatis ${filterSql} raw string substitution. A remote, effectively unauthenticated attacker can supply a boolean or comparison expression (for example 1=1, 1=0, or id='<uuid>') that is evaluated as SQL, allowing arbitrary row and column reads from database tables such as sys_user.
版本号:
<= v3.9.2
Vulnerable Components
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xmlSysDictServiceImpl.getFilterSql
similar endpoints include /sys/api/getDictItems, /sys/api/queryFilterTableDictInfo, /sys/dict/loadDictOrderByValue/{dictCode}, /sys/api/queryTableDictByKeys, /sys/api/queryTableDictItemsByCode, and /sys/api/translateDictFromTableByKeys.
问题描述:
User-controlled filterSql/condition strings are spliced directly into the SQL text through MyBatis ${} raw string interpolation, which performs no escaping or parameterization.
SysDictMapper.xml interpolates the attacker-controlled fragment verbatim:
<!-- SysDictMapper.xml (line 187) -->
where ${filterSql}
<!-- SysDictMapper.xml (line 208) -->
and ${filterSql}
SysDictServiceImpl.getFilterSql builds that fragment by concatenating the attacker-controlled condition (the 4th comma-separated element of dictCode) into a WHERE clause with no escaping:
// SysDictServiceImpl.getFilterSql (line 541)
filterSql = " where " + condition;
SysDictServiceImpl.queryTableDictItemsByCodeAndFilter passes the raw filterSql request parameter straight into queryTableDictWithFilter(...), reaching the ${filterSql} sink.
The guard is a keyword blacklist, SqlInjectionUtil.specialFilterContentForDictSql. It throws when the input contains select, insert, update, delete, union (via "select "), sleep(, benchmark(, database(), version(), substring, information_schema, ;, +, --, and similar tokens. It does not block 1=1, 1=0, =, and, or, or id='...'.
PoC:
# Returns ALL rows (WHERE always true)
curl -s -G "http://127.0.0.1:8082/jeecg-boot/sys/api/getDictItems" \
--data-urlencode "dictCode=sys_user,realname,id,1=1" \
-H "X-Access-Token: $TOKEN"
Confirmed harm
- Bulk disclosure of PII and business data.
dictCode=sys_user,phone,email,1=1returned every user's phone number and email. An attacker can dump any non-blacklisted table and column using1=1or a targeted condition. - Arbitrary non-sensitive tables readable.
dictCode=sys_dict_item,item_text,item_value,1=1returned dictionary rows;dictCode=sys_user,realname,id,1=1returned all 4 users (测试用户, 张三, jeecg, 管理员).
Source: jeecgboot/JeecgBoot