CVSS: 7.8
Target Service
JeecgBoot
- Java-based low-code/enterprise development framework
- Provides integrated back-office functions such as code generator, permission management, dictionary, and online development.
- It is based on Spring Boot, MyBatis-Plus, and Vue and is used to build a quick work system at home and abroad.
- Internally, it contains SQL filtering logic of the WAF nature and performs defense against some dynamic query inputs.
Affected Versions
- Affected Versions: JeecgBoot 3.9.0, 3.9.1
Vulnerability Overview
Vulnerability Types
- SQL Injection
- SQL injection after authentication
- Bypass WAF
- JeecgBoot can bypass the built-in WAF’s regular expression and blacklist validation logic.
- Dynamic SQL injection
- External input is interpreted as filterSql and combined directly after the SQL where clause.
- Blind SQL Injection
- Table names, column presence, and data values can be extracted based on response differences.
Root Cause
- There was a design flaw in the dictionary lookup function.
- The dictCode value passed through the GET /sys/dict/getDictItems/{dictCode} or related API path is directly passed to the service layer, and for input of a specific format, the fourth segment is interpreted as a filter condition.
- In SysDictServiceImpl.java, dictCode in four-column format is processed as queryTableDictItemsByCodeAndFilter(params[0], params[1], params[2], params[3]) path, where the fourth value is passed to ${filterSql}.
- Afterwards, dynamic SQL string combining is performed in SysDictMapper.xml in the form of where ${filterSql}, and the external input is directly reflected as part of the SQL syntax.
- Originally, there was a filtering logic to prevent SQL injection, but instead of a general inspection logic, it used a dictionary-specific inspection logic called specialFilterContentForDictSql.
- This dictionary-only blacklist excludes and and or, which are included in the general blacklist, so logical conditions can be expanded.
- In addition, since the regular expression-based detection logic relies on a specific combination of spaces, non-space strings, and special characters rather than the inclusion of simple keywords, it can be bypassed by simply changing the syntax placement.
- In other words, SQL injection occurs due to the combination of the structure that directly accepts external input as a SQL piece and the incomplete WAF logic.
Exploitation Mechanism
Attack Flow
- Attacker → send request to vulnerable dictionary lookup endpoint
- Configure dictCode in 4-column format
- Insert conditional expression SQL in the fourth item
- Server-side processing
- The controller passes the dictCode as is to the service layer.
- The service layer decomposes this and interprets the fourth value as a filter condition.
- Perform check WAF
- Dictionary-specific inspection logic is applied, not the default SQL injection inspection logic.
- Filter bypass possible due to missing and, or and regex flaws
- SQL Assembly
- Perform dynamic SQL combination in Mapper in the form of where ${filterSql}
- Perform blind SQL injection
- Database information can be extracted based on true/false response differences
At the point when an attacker can access the dictionary lookup API even if he or she only has authenticated normal user privileges, the SQL filter statement can be inserted by manipulating the dictCode. This value is internally interpreted as filterSql and directly combined with the SQL sentence, making conditional clause expansion possible.
Afterwards, the WAF must block this, but the dictionary-only check is weaker than the general blacklist, and regular expression matching also does not reliably detect the entire actual SQL grammar. For example, keywords such as select and from can pass the filter if placed in a specific form.
As a result, the attacker can perform a blind SQL injection to observe the true/false response by inserting a conditional expression in the form of 1=1 and (…). Through this, the number of tables in the current database, table name, column presence, and the length and content of a specific field can be sequentially extracted.
Additionally, even if some system tables are blocked, you can still enumerate the table structures of the current database by using alternative metadata paths such as mysql.innodb_index_stats.
Patch Details
Recommended Remediation
The 4-column format of dictCode should be prohibited and filterSql should not be passed directly from the outside.
- Remove structure that interprets the fourth segment of dictCode as a filter condition
- Restrict tableFilterSql from including where clauses or conditional expressions
- Remove dynamic SQL join in where ${filterSql} method within SysDictMapper.xml
- Change to structured inquiry method
- Field names are restricted to a whitelist.
- Values are only processed through parameter binding
- Modified to assemble only safe conditional expressions on the server side
Blacklists can be used as an auxiliary defense measure, but preventing SQL injection through string filtering alone cannot be a fundamental solution. Ultimately, this vulnerability is a problem in the design itself, which directly accepts external input as SQL syntax, so it must be fundamentally modified to eliminate dynamic SQL string combinations.