打開主頁進(jìn)入第一關(guān) :

提示傳入id這個(gè)參數(shù)

發(fā)現(xiàn)這個(gè)頁面會(huì)根據(jù)傳入的ID查詢到對(duì)應(yīng)的用戶
這里我們可以通過查看數(shù)據(jù)庫進(jìn)行驗(yàn)證 :

這樣就可以推斷出PHP執(zhí)行的SQL語句的功能就是從數(shù)據(jù)庫中查詢出id為我們傳入的id的那個(gè)用戶 , 并且把得到的數(shù)據(jù)中的用戶名和密碼顯示出來
我們猜測SQL語句可能是這樣 :
SELECT username,password FROM `users` WHERE id = $_GET['id'];
但是我們猜測的這個(gè)SQL語句并不一定正確
因?yàn)镾QL語句在執(zhí)行的時(shí)候 , 對(duì)語法有一定的要求 , 但是并不是特別嚴(yán)格 , 例如 :
SELECT username,password FROM `users` WHERE id = '$_GET['id']';
SELECT username,password FROM `users` WHERE id = "$_GET['id']";
這兩種都是可以查詢到數(shù)據(jù)的
因此我們?nèi)绻暨@個(gè)網(wǎng)站的話 , 就要想辦法猜測出這個(gè)頁面的SQL語句是怎么寫的
要猜測屬于上面的哪一種情況 , 這樣我們才可以將我們自己精心構(gòu)造的SQL語句注入到正常的參數(shù)里面
讓我們的SQL語句的到執(zhí)行 , 達(dá)到我們的目的(讀出本來我們不能讀取的內(nèi)容 , 或者對(duì)數(shù)據(jù)庫進(jìn)行增/刪/改/查的操作 , 或者利用數(shù)據(jù)庫軟件讀取或者寫入服務(wù)器上的文件 ... )
我們可以先在本地的MySQL中對(duì)SQL語句進(jìn)行測試 :
SELECT username,password FROM `users` WHERE id = 1;



那么如果當(dāng)我們輸入的參數(shù)id并不是按照程序員想的是一個(gè)整數(shù)呢 ?
如果我們輸入一個(gè)字母/一個(gè)符號(hào)會(huì)怎么樣 ?


這個(gè)時(shí)候 , 當(dāng)我們輸入的參數(shù)是 1'
發(fā)現(xiàn)這個(gè)頁面報(bào)錯(cuò)了 , 報(bào)錯(cuò)的內(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ù)這個(gè)報(bào)錯(cuò) , 我們可以看到它顯示出來了一部分SQL語句 :
'1'' LIMIT 0,1
而這其中的1’
就是我們剛才輸入的參數(shù)
那么我們就可以繼續(xù)對(duì)剛才的猜測進(jìn)行完善
可以看到我們輸入的參數(shù)1'是被兩個(gè)單引號(hào)包裹起來的
而且在后面還對(duì)查詢的結(jié)果集進(jìn)行了切片 , 這樣查詢的結(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)當(dāng)我們輸入的單引號(hào)不匹配的時(shí)候 , MySQL的客戶端會(huì)一直等待用戶閉合這個(gè)單引號(hào)
但是當(dāng)使用PHP去操作MySQL的時(shí)候 , 因?yàn)橛脩羰峭ㄟ^PHP對(duì)數(shù)據(jù)庫進(jìn)行操作 , 所以不可能像我們剛才那樣存在一個(gè)交互的界面 , 因此就這個(gè)單引號(hào)就不可能被閉合 , 因此這個(gè)時(shí)候就會(huì)報(bào)錯(cuò) , 也就是剛才我們得到的這個(gè)錯(cuò)誤
這個(gè)時(shí)候 , 如果我們繼續(xù)修改一下查詢的id這個(gè)參數(shù)
這里可以嘗試使用MySQL定義的注釋關(guān)鍵字
--
/**/
需要說明一下 , 第一個(gè)是兩個(gè)-連接符后面緊跟著一個(gè)空格
前兩個(gè)注釋符是單行注釋 , 第三個(gè)是多行注釋
如果我們在id這個(gè)參數(shù)后面添加了注釋的時(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)被我們注釋掉了
這樣的話 , 如果我們剛才猜測的后臺(tái)的SQL語句是正確的
如果我們傳遞參數(shù)為 :
http://127.0.0.1/Less-1/?id=1%27--+
http://127.0.0.1/Less-1/?id=1%27%23
注意這里我們沒有使用到原本的字符'和#
而是將它們URL編碼以后再進(jìn)行參數(shù)的傳遞 , 這里是因?yàn)榉?wù)器再接收到參數(shù)以后會(huì)對(duì)參數(shù)進(jìn)行一次URL解碼
這樣的話解碼之后剛好就可以拼湊成正常的SQL語句
還有一個(gè)需要注意的地方就是 :
- 為什么是
--+而不是--
這里字符
-和字符+在URL中都是有固定的含義的 , 比如說+就在URL編碼中就代表空格 , 而URL編碼中-不用編碼
- 為什么
--+沒有被URL編碼
由于這里我們是用
+代替了, 因此不需要進(jìn)行編碼 , 我們也可以不用+而使用空格的URL編碼 , 那么編碼得到的URL就應(yīng)該是 :
http://127.0.0.1/Less-1/?id=1%27--%20
-
#又為什么必須得編碼 , 不編碼可以嗎 ?
不可以 , 因?yàn)?code># 在URL中是有固定的含義的 , 表示頁面中的錨點(diǎn) , 如果不進(jìn)行編碼瀏覽器就會(huì)將其當(dāng)成頁面的錨點(diǎn) , 而這里我們是需要將其作為數(shù)據(jù)傳輸給服務(wù)器的 , 因此需要進(jìn)行URL編碼
- 為什么不用多行注釋來注釋后面的SQL語句
因?yàn)槎嘈凶⑨尩母袷绞?:
/*注釋內(nèi)容*/
在注釋內(nèi)容的前后都需要有標(biāo)記
而這里我們只能控制SQL語句的一個(gè)位置 , 也就是輸入id的地方
所以這樣我們并不能構(gòu)成一個(gè)正確的多行注釋 , 因此不可以 , 大家也可以自己嘗試一下 , 會(huì)直接報(bào)錯(cuò)(語法錯(cuò)誤)
好了 , 現(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ù)(因?yàn)樽⑨尩袅?code>LIMIT 0,1)
到這里 , 我們就可以肯定這個(gè)網(wǎng)站的這個(gè)PHP文件的id這個(gè)參數(shù) , 是存在注入點(diǎn)的
接下來 , 我們就要利用這個(gè)注入點(diǎn)將其數(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--+