windows下sqli-labs的搭建及學習(GET篇)


環境搭建:

源碼下載地址:https://github.com/Audi-1/sqli-labs

需要搭建以下環境:

  1. apache+mysql+php
  2. Tomcat+mysql+java(部分關卡需要)

        apache的環境在windows下可以直接安裝wamp、phpstudy、apmserv等,我安裝的是wamp,安裝過程中可能會遇到一些問題:像是之前安裝過mysql,防火牆,端口被占用了之類的,導致啟用不了或者logo出現紅色和橙色,可能需要改一些配置文件,這個百度一下很容易解決

      tomcat的環境比較容易搭建,百度照着做不會出錯

安裝sql-libs:

     將之前下載的源碼解壓到web目錄下,windows下的wamp解壓在www目錄下。

     打開sql-connections/db-creds.inc文件

     將數據庫的username和password修改為你自己的mysql賬號和密碼

     然后再訪問127.0.0.1的頁面,點擊鏈接Setup/reset Database for labs創建數據庫

 

     然后就可以開始玩游戲了~


實驗測試:

Less-1:基於錯誤的_get_單引號_字符型注入


     輸一個id值,返回了name和password,接着測試是否能注入,url后加上?id=',發現報錯了,直接報的數據庫的錯,對web瀏覽器用戶透明,那么可以從報錯中得到很多信息,比如這是個MySQL的數據庫,還可以猜想到后台的sql語句,應該是“SELECT * FROM table_name WHERE id='$_get['id']' LIMIT 0,1”這種,說明他沒有過濾單引號,並且id是char型的輸入,之所以報錯是因為用了單引號,導致后面的部分“'LIMT 0,1;”多余出來了


     於是構造sql語句-1‘OR’1'='1'--+屏蔽掉后面的,也可以用#屏蔽,但這里#沒有被url編碼,故需自己將他轉成url編碼%23


      注入成功~接着來猜字段,有3個字段存在,再試試4個

     沒有第4個字段了,即沒有第4列

     接着用union 語句爆字段,但始終只顯示一條記錄,看了下源碼,發現他並沒有將結果循環輸出,而是只返回符合查詢結果的第一條記錄


     於是利用聯合查詢的特點,使原查詢左邊為空,那么我們定義的查詢結果便可以返回出來

     於是我們可以通過這里使用數據庫的函數來爆出數據庫的信息,構造如下語句

     這里用到的數據庫函數有cancat_ws(),char(),user(),database(),cancat_ws()是連接函數,第一個參數是分隔符,同樣作用的函數還有cancat(),不同的是cancat()沒有連接符,char()函數是將十進制參數轉換成對應的acsii碼,user()和database()都是內置的函數,分別返回用戶名和數據庫名,類似的函數還有version(),返回數據庫的版本信息,但是沒有直接返回表名的函數,所以需要通過其他方式獲取表名

     這里有一個很經典的方法,我們可以通過系統數據庫information_schema來獲取表名,information_schema數據庫中含有很重要的三張表:SCHEMATA,TABLES和COLUMNS

     SCHEMATA表中存儲了MySQL中所有數據庫的信息,包括數據庫名,編碼類型路徑等,show databases的結果取之此表

     TABLES表中存儲了MySQL中所有數據庫的表的信息(當然,索引是根據數據庫名的),包括這個表是基本表還是系統表,數據庫的引擎是什么,表有多少行,創建時間,最后更新時間等,show tables from schemaname的結果取之此表

     COLUMNS表中存儲了MySQL中所有表的字段信息,show columns from schemaname.tablename的結果取之此表

     於是,我們可以構造?id=-1' union select 1,2,table_name from information_schema where table_schema='security'#

     這樣就爆出了第一張表名,但要獲取所有表名還需要用到'limit',limit是用來指定范圍,他有兩個參數(limit a,b)a是從第幾行開始取,b是取多少行,但需要注意的是實際取出來的開始行下標比a大1,即limit 5,10是表示取6到15行數據,接下來我們就可以用它取指定范圍的表了


     這里取的是第4張表,如果超出能取的范圍,他會報錯

     於是通過修改limit的范圍我們獲取到了所有的表名,且與數據庫中的表名一致,其中users表用來存儲用戶信息的可能性最大,於是,我們可以用同樣的方法爆他的字段名

     獲取到的字段名有三個id,username,password,於是我們就可以構造語句了


     同樣的,改變limit的范圍以獲取所有用戶信息

     還有一種方法是通過group分組代替limit將所有信息列出來,查找表名可以構造如下payload:

     查找字段也是同樣的

     最后的payload可以合並不同的列,上下對應輸出



Less-2:基於錯誤的_get_整型注入

     嘗試單引號:


     這里的報錯與less-1不同了,從報錯可以看出,此處的id是當做數值來處理的,因為sql語句對於數字型的數據可以不加單引號,而less-1是作為字符串來處理的,猜想后台sql語句應該是select * from table_name where id = $_get['id'] limit 0,1於是構造-1 or 1=1


     可以注入,接着用和之前相同的方法先報數據庫名,然后是表名,接着是字段,最后的payload如下



Less-3:基於報錯的_get_單引號_變形_字符型注入


     看報錯,所謂變形就是用)代替了空格,猜想后台sql是select * from table_name where id =('$_get['id']')limit 0,1於是構造-1')or'1'='1'--+


     最后的payload:



Less-4:基於錯誤的_get_雙引號_字符型注入


     嘗試單引號正常無報錯信息,因為在php中雙引號可以包含單引號,輸入單引號后台就變成了id=("$_GET['id']'")


     於是嘗試雙引號,查看報錯信息,猜想后台sql語句為select * from table_name where id =("$_get['id']")limit 0,1;構造如下sql注入:


     payload:



less-5:雙注入_get_單引號_字符型注入

     這個題很有意思,一開始我還是放原來的payload,已經准備好爆表名了,結果他給我的反應是這個


     什么都沒有,然后注意到提示是“雙注入”,於是百度了一下,總結如下:

     雙查詢注入顧名思義形式上是兩個嵌套的查詢,即select ...(select ...),里面的那個select被稱為子查詢,他的執行順序也是先執行子查詢,然后再執行外面的select,雙注入主要涉及到了幾個sql函數:

     rand()隨機函數,返回0~1之間的某個值

     floor(a)取整函數,返回小於等於a,且值最接近a的一個整數

     count()聚合函數也稱作計數函數,返回查詢對象的總數

     group by cluase分組語句,按照cluase對查詢結果分組

     雙注入的原理總的來說就是,當一個聚合函數后面出現group分組語句時,會將查詢的一部分結果以報錯的形式返回,他有一個固定的公式,於是payload構造如下:


     獲取到數據庫名后再用同樣的方法獲取表名


     然后是用戶信息,這里只能查詢一行,所以不能用group_concat,可以修改limit的范圍來遍歷用戶信息



Less-6:雙注入_get_雙引號_字符型注入

     換湯不換葯,按照Less-5的方法,只是把單引號改成了雙引號,直接上payload:



Less-7:導出文件_get_字符型注入


     嘗試之前的方法行不通了,他把報錯做了處理統一返回“You have an error in your SQL syntax”,明顯的,他也給出了提示use outfile,outfile的固定結構是:select A into outfile B,這里的B通常是一個文件路徑,A可以是文本內容(小馬),也可以是數據庫信息,於是這里就有兩種思路:

     第一種,構造select * from users into outfile "數據庫導入導出數據的目錄"


     這真是一件很悲傷的事情...我的語句構造沒問題,但是F盤下就是沒有test.txt文檔出現,於是查了一波資料,有一種說法是權限問題,需要root權限才能進行數據庫的讀寫操作,可以用這個語句來判斷: and (select count(*) from mysql.user)>0 ,如果回顯正常,就是表示最高權限


     我是最高權限呀,難道是路徑轉義的問題,又試一下


     還是沒有...好吧,放Mysql里面白盒測一下


     報了一個錯,查了下資料,報錯原因是:Mysql數據庫需要在指定的目錄下進行數據的導出,secure_file_priv這個參數用來限制數據導入和導出操作的效果,例如執行LOAD DATA、SELECT ... INTO OUTFILE語句和LOAD_FILE()函數。這些操作需要用戶具有FILE權限。
     如果這個參數為空,這個變量沒有效果;
     如果這個參數設為一個目錄名,MySQL服務只允許在這個目錄中執行文件的導入和導出操作。這個目錄必須存在,MySQL服務不會創建它;
     如果這個參數為NULL,MySQL服務會禁止導入和導出操作。這個參數在MySQL 5.7.6版本引入。

     於是查看了下secure_file_priv,然后換成他指定的目錄,還是有問題...然后想到路徑的轉義,OK,成功了,路徑下面也出現了1.txt


     但是,我們這個是通過白盒測試拿到的數據,在正常情況下,我們是不知道數據庫名和表名的,不過,原理也類似,可以結合前面用到的經典方法


     然后是表名


     字段


     注意,這里我為方便重復使用的2.txt,但每次都要刪除后才可以生成新的

     最后的payload:


     這里除了用以前的order by判斷字段數,還有一個方法,像下面這樣直接試就好了,只有字段數剛好正確才會生成2.txt,多了少了都不行


     第二種,將一句話木馬寫入到文件,用菜刀拿下網站


     這里文件后綴要改成.php(我懶得換圖了),然后用菜刀連接,由於我這台機沒裝菜刀,所以就不截圖了,大致意思就是這樣,下面來擴展一下導入導出數據還會涉及到哪些函數:

     @@datadir:數據庫存儲路徑

    @@basedir:MySQL安裝路徑

     dumpfile:導出文件,類似outfile,不同的是,dumpfile一次導出一行,會和limit結合使用

     load_file():將文件導入mysql,用法 select load_file("文件路徑");


Less-8:bool型_單引號_盲注

     首先嘗試less-7的方法,沒問題


     接着探索新姿勢,正常輸入返回“You are in......”,嘗試單引號卻什么都沒返回,看了下源碼就是這樣處理的,點題盲注

     盲注主要分為bool型和時間性,通常涉及到這幾個函數:

     length(str):返回字符串str的長度

     substr(str,pos,len):將str從pos位置開始截取len長度的字符返回,需要注意的是這里pos的是從1開始的

     mid(str,pos,len):和substr()類似

     ascii(str):返回字符串str最左邊的acsii碼(即首字母的acsii碼)

     ord():同上,返回acsii碼

     left(str,len):對字符串str左截取len長度

     right(str,len):對字符串str右截取len長度

     if(a,b,c):條件判斷,如果a為true,返回b,否則返回c

     盲注有個固定式:and ascii(substr(A,1,1))>B,或者and if(ascii(substr(A,1,1))>B,1,0),這里的A通常是一個select語句,B則是字符或數字的ascii碼,他們的中心思想都是通過substr等截取函數以二分法的形式查詢逐個匹配想要的信息,這個過程通常都很耗時,所以建議直接寫個盲注腳本來跑

     下面是盲注匹配的一個例子,我們來匹配數據庫名,在之前的實驗中已知數據庫名是security,下面的sql語句是用來匹配數據庫名的第一個字母


     字母s的ascii碼是115,所以他大於114,結果為true,頁面顯示正常


     這里大於了115,結果為false,頁面顯示異常,好,接下來直接寫個盲注腳本,跑出來結果如下:



Less-9:時間型_單引號_盲注

     時間型盲注和bool型盲注應用場景不同之處在報錯的返回上,從less-8我們知道,輸入合法時他會返回正常頁面“You are in......”,而非法輸入時他沒有返回任何東西,於是,我們可以根據這個特點跑盲注,通過他不同的返回頁面來判斷我們匹配的字符是否正確,而在less-9中合法輸入他返回如下


     非法輸入也是返回該頁面


     這樣,我們就不能根據他頁面的返回內容來判斷匹配結果了,因此我們需要用延時函數sleep()對兩種輸入進行區分,可以構造如下語句:

     ?id=1' and if(ascii(substr(database(),1,1))>115, 0, sleep(5))%23

     這里的意思是,如果數據庫名首字母的ascii碼大於115,那么執行sleep(5),延時5秒,此時標簽欄會變成緩沖,於是,我們就可以判斷匹配的結果了,盲注腳本與less-8類似,只需要加入sleep函數即可


Less-10:時間型_雙引號_盲注

     把上面payload中的單引號改成雙引號就可以了,如:

     ?id=1" and if(ascii(substr(database(),1,1))>115, 0, sleep(5))%23


參考文獻:

http://www.freebuf.com/articles/web/34619.html

http://blog.csdn.net/u012763794/article/details/51207833

http://blog.itpub.net/26506993/viewspace-2121850/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM