By HelloWeb 2017-3-7
MySQL寬字節注入漏洞是SQL注入漏洞攻防技術相互促進的一個典型例子。
1 經典SQL注入漏洞
例子1是沒有任何SQL注入防護措施的php程序,它存在SQL注入漏洞。
<?php $name=$_GET['name']; $conn=mysql_connect('localhost','root','root'); if($conn==null){exit("connect error !<br>");} mysql_select_db("aaa",$conn); $sql="select * from a1 where name='".$name."'"; $result=mysql_query($sql,$conn); while($val=mysql_fetch_row($result)){ PRint_r($val); print("<br>"); }?>例子1:無SQL注入防護的PHP程序
對該PHP程序的SQL注入POC包括:
(1) http://127.0.0.1/test/t1.php?name=a'or 'a'='a
(2) http://127.0.0.1/test/t1.php?name=a'or 1=1 -- %20
(3) http://127.0.0.1/test/t1.php?name=a'or 1=1 -- %23
其中,%20對應空格,%23對應#的URL編碼,該POC在PHP5.4.45+Apache測試成功。
2 安全過濾
如果對例子1中的PHP程序中的$name變量進行安全過濾,如使用轉義函數addslashes,mysql_real_escape_string,mysql_escape_string,則對應的POC全部失效了。
轉義函數影響的字符包括:
(1) ASCII(NULL)字符/x00,
(2) 換行字符/n,addslashes不轉義
(3) 回車字符/r,addslashes不轉義
(4) 反斜杠字符/,
(5) 單引號字符‘,
(6) 雙引號字符“,
(7) /x1a,addslashes不轉義
對于例子1進行安全增強后,得到例子2,如下所示。
注意:三個轉義函數的功能稍有區別,同時,轉義只對字符型SQL注入防范有效,對于數值型SQL注入無效。
<?php$name=$_GET['name'];//$name=addslashes($name);//$name=mysql_escape_string($name);$conn=mysql_connect('localhost','root','root');$name=mysql_real_escape_string($name);if($conn==null){exit("connect error !<br>");}mysql_select_db("aaa",$conn);$sql="select * from a1 where name='".$name."'";$result=mysql_query($sql,$conn);while($val=mysql_fetch_row($result)){ print_r($val); print("<br>");}?>例子2:轉義增強后的PHP程序
3 寬字節注入漏洞原理
寬字符是指兩個字節寬度的編碼技術,如UNICODE、GBK、BIG5等。當MYSQL數據庫數據在處理和存儲過程中,涉及到的字符集相關信息包括:
(1) character_set_client:客戶端發送過來的SQL語句編碼,也就是PHP發送的SQL查詢語句編碼字符集。
(2) character_set_connection:MySQL服務器接收客戶端SQL查詢語句后,在實施真正查詢之前SQL查詢語句編碼字符集。
(3) character_set_database:數據庫缺省編碼字符集。
(4) character_set_filesystem:文件系統編碼字符集。
(5) character_set_results:SQL語句執行結果編碼字符集。
(6) character_set_server:服務器缺省編碼字符集。
(7) character_set_system:系統缺省編碼字符集。
(8) character_sets_dir:字符集存放目錄,一般不要修改。
寬字節對轉義字符的影響發生在character_set_client=gbk的情況,也就是說,如果客戶端發送的數據字符集是gbk,則可能會吃掉轉義字符/,從而導致轉義消毒失敗。
例子3就是一個存在寬字符注入漏洞的PHP程序。
<?php$name=$_GET['name'];$name=addslashes($name);$conn=mysql_connect('localhost','root','root');if($conn==null){exit("connect error !<br>");}mysql_query("SET NAMES 'gbk'",$conn);mysql_select_db("aaa",$conn);$sql="select * from a1 where name='".$name."'";$result=mysql_query($sql,$conn);while($val=mysql_fetch_row($result)){ print_r($val); print("<br>");}?>這個PHP程序的SQL注入POC為:
http://127.0.0.1/test/t3.php?name=a%df' or 1=1; %20%23
其原理是mysql_query("SETNAMES 'gbk'",$conn)語句將編碼字符集修改為gbk,此時,%df/'對應的編碼就是%df%5c’,即漢字“運’”,這樣單引號之前的轉義符號“/”就被吃調了,從而轉義消毒失敗。
4 寬字節注入漏洞再深入
從寬字節注入漏洞原理可以看出,寬字節注入的關鍵點有兩個:
(1) 設置寬字節字符集;
(2) 設置的寬字符集可能吃掉轉義符號“/”(對應的編碼為0x5c,即低位中包含正常的0x5c就行了)。
理論上,符合第二條的字符集都可能導致寬字節注入漏洞,這里以gbk字符集為典型,介紹寬字符注入漏洞典型案例。
寬字節注入漏洞的另一個關鍵是設置了character_set_client為寬字節字符集,這里有很多中設置的方式,主要包括隱式設置和顯式設置。
隱含方式設置是指charcter_set_client缺省字符集就是寬字節字符集。
顯式設置是指在PHP程序中調用相應的設置函數來實現字符集的設置或直接對字符串進行編碼轉換,設置的函數包括:
(1) mysql_query,如mysql_query("SET NAMES 'gbk'", $conn)、mysql_query("setcharacter_set_client = gbk", $conn)。
(2) mysql_set_charset,如mysql_set_charset("gbk",$conn)。
(3) mb_convert_encoding,如mb_convert_encoding($sql,"utf8","gbk"),將SQL語句從gbk格式轉換為utf8格式時,0x5c被吃掉了。
(4) iconv,如iconv('GBK', 'UTF-8',$sql),原理同上。
新聞熱點
疑難解答