Less 32
JSP
可能是閑著沒事多做了一關(guān),名字就是Fun with JSP,可能確實是用來娛樂的。
單引號小括號字符型,無過濾。
唯一的樂趣是有一個index.jsp1的備份文件,可以看到源碼,這也是 Web 題的一種套路,一般用在 PHP 代碼審計和 SQL 注入的混合關(guān)。

PHP
基于錯誤_GET_單引號_字符型_轉(zhuǎn)義引號反斜杠_寬字節(jié)注入
0x01. 寬字節(jié)注入
在舊版本的 MySQL 安裝時,會有編碼問題導(dǎo)致中文亂碼,需要手動設(shè)置編碼為 UTF-8。而安裝 MySQL 5.7 時并沒有出現(xiàn)這個問題,默認(rèn)編碼已經(jīng)是 UTF-8。
SHOW VARIABLES LIKE 'character%';

PHP 自帶一些轉(zhuǎn)義特殊字符的函數(shù),如addslashes(),mysql_real_escape_string(),mysql_escape_string()等,這些函數(shù)可用來防止 SQL 注入。
如id=1'or'1'='1,單引號本用來閉合語句,這些函數(shù)會自動轉(zhuǎn)義這些閉合的單引號,在這些單引號前面加上轉(zhuǎn)義符\,變?yōu)?code>1\'or\'1\'=\'1,如此在 SQL 查詢中仍然一個普通的字符串,不能進(jìn)行注入。
而網(wǎng)站在過濾'的時候,通常的思路就是將'轉(zhuǎn)換為\',因此我們在此想辦法將'前面添加的\去掉,一般有兩種思路:
%bb連帶\
如果程序的默認(rèn)字符集是GBK等寬字節(jié)字符集,就有可能產(chǎn)生寬字節(jié)注入,繞過上述過濾。
若在 PHP 中使用mysql_query("set names gbk")將默認(rèn)字符集設(shè)為GBK,而使用addslashes()轉(zhuǎn)義用戶輸入,這時如果用戶輸入%bb%27,則addslashes()會在%27前面加上一個%5c字符,即轉(zhuǎn)義字符\。
而 MySQL 在使用GBK編碼時,會認(rèn)為兩個字符為一個漢字,%bb%5c是一個寬字符(前一個 ASCII 碼大于 128 才能到漢字的范圍),也就是籠,也就是說%bb%5c%27=籠',這樣單引號就未被轉(zhuǎn)義能閉合語句,從而產(chǎn)生 SQL 注入。%bb并不是唯一一個可以產(chǎn)生寬字節(jié)注入的字符,理論上%81-%FE均可。過濾
\'中的\
構(gòu)造%bb%5c%5c%27,addslashes()會在兩個%5c和%27前都加上\即%5c,變?yōu)?code>%bb %5c%5c %5c%5c %5c%27,但寬字符集認(rèn)為%bb%5c是一個字符即籠,則變?yōu)?code>%bb%5c %5c%5c %5c%5c %27即籠\\\\',四個\正好轉(zhuǎn)義為兩個\,即'未被轉(zhuǎn)義。這也是 bypass 的一種方法。
0x02. 注入過程
知道這關(guān)是寬字節(jié)注入,先以上帝視角看看源碼:
mysql_query("SET NAMES gbk");
$id = check_addslashes($_GET['id']);
function check_addslashes($string)
{
$string = preg_replace('/'.preg_quote('\\').'/',"\\\\\\",$string); //escape any backslash
$string = preg_replace('/\'/i','\\\'',$string); //escape single quote with a backslash
$string = preg_replace('/\"/',"\\\"",$string); //escape double quote with a backslash
return $string;
}
可以看到這個函數(shù)是個過濾\、'、"的函數(shù),分別在前面加上\。
步驟1:確定寬字節(jié)注入
1、1'、1"都能正?;仫@,可以猜測輸入的引號被過濾,從頁面給的 hint 也證實了這一點。

猜測是引號是被轉(zhuǎn)義而并非被純粹過濾,嘗試寬字節(jié)注入:
http://localhost:8088/sqlilabs/Less-32/?id=1%bb%27

有錯誤回顯,從其中可以看到被單引號閉合。
若無錯誤回顯,可注釋后面的查詢語句:
http://localhost:8088/sqlilabs/Less-32/?id=1%bb%27--+

用上述第二種方法同樣可以做到:
http://localhost:8088/sqlilabs/Less-32/?id=1%bb%5c%5c%27--+

已經(jīng)確定了單引號閉合且寬字節(jié)注入可以繞過,剩下的就是正常的注入,無其他過濾條件。
因未過濾注釋,所以只有開頭的單引號需要寬字節(jié)注入。
0x03. 吐槽
總覺得越到后面越簡單了,可能是沒把過濾條件都結(jié)合起來,后來還得總結(jié)一下過濾條件和注入方式。
Less 33
基于錯誤_GET_單引號_字符型_addslashes()_寬字節(jié)注入
Less 32 是自定義的過濾器,本關(guān)直接使用了 PHP 的addslashes()函數(shù),在 Less 17 中介紹過:
addslashes()與stripslashes()函數(shù)
addslashes(string)函數(shù)返回在預(yù)定義字符之前添加反斜杠\的字符串:
- 單引號
' - 雙引號
" - 反斜杠
\ - 空字符
NULL
該函數(shù)可用于為存儲在數(shù)據(jù)庫中的字符串以及數(shù)據(jù)庫查詢語句準(zhǔn)備字符串。
注意:默認(rèn)地,PHP對所有的GET、POST和COOKIE數(shù)據(jù)自動運行
addslashes()。所以不應(yīng)對已轉(zhuǎn)義過的字符串使用addslashes(),因為這樣會導(dǎo)致雙層轉(zhuǎn)義。遇到這種情況時可以使用函數(shù)get_magic_quotes_gpc()進(jìn)行檢測。
stripslashes(string)函數(shù)刪除由addslashes()函數(shù)添加的反斜杠。
判斷和注入過程同 Less 32 完全相同。