寬字節注入詳解

http://netsecurity.51cto.com/art/201404/435074.htm

 

科普:寬字節注入詳解

在mysql中,用於轉義的函數有addslashes,mysql_real_escape_string,mysql_escape_string等,還有一種情況是magic_quote_gpc,不過高版本的PHP將去除這個特性。

  • 作者:lxsec來源:網絡安全***實驗室|2014-04-08 16:02

  •  移動端

    wKiom1kvkpKBgQFIAACDBen2-dg668.jpg

    51CTO技術棧

    wKioL1i40HrAObC6AAAcvPVCCV0975.jpg

    51CTO微站服務號

    wKioL1i40HrQZy_TAAAcDOkrRAE327.jpg

    51CTO學院客戶端

     收藏                

      分享

前言

在mysql中,用於轉義的函數有addslashes,mysql_real_escape_string,mysql_escape_string等,還有一種情況是magic_quote_gpc,不過高版本的PHP將去除這個特性。

科普:寬字節注入詳解

首先,寬字節注入與HTML頁面編碼是無關的,筆者曾經看到

<meta charset=utf8>

就放棄了嘗試,這是一個誤區,SQL注入不是XSS。雖然他們中編碼的成因相似,不過發生的地點不同。

很多網上的材料都說程序使用了寬字節來處理程序,卻又不指出具體是指什麼程序。本文就介紹一下具體漏洞發生的原理與簡單的利用。在這裏我們限定使用的語言是PHP5.4,數據庫MYSQL5.6。

涉及到的一些概念

字符、字符集與字符序

字符(character)是組成字符集(character set)的基本單位。對字符賦予一個數值(encoding)來確定這個字符在該字符集中的位置。

字符序(collation)指同一字符集內字符間的比較規則。

UTF8

由於ASCII表示的字符只有128個,因此網絡世界的規範是使用UNICODE編碼,但是用ASCII表示的字符使用UNICODE並不高效。因此出現了中間格式字符集,被稱爲通用轉換格式,及UTF(Universal Transformation Format)。

寬字節

GB2312、GBK、GB18030、BIG5、Shift_JIS等這些都是常說的寬字節,實際上只有兩字節。寬字節帶來的安全問題主要是吃ASCII字符(一字節)的現象。

MYSQL的字符集轉換過程

1. MySQL Server收到請求時將請求數據從character_set_client轉換爲character_set_connection;

2. 進行內部操作前將請求數據從character_set_connection轉換爲內部操作字符集,其確定方法如下:

使用每個數據字段的CHARACTER SET設定值;

若上述值不存在,則使用對應數據表的DEFAULT CHARACTER SET設定值(MySQL擴展,非SQL標準);

若上述值不存在,則使用對應數據庫的DEFAULT CHARACTER SET設定值;

若上述值不存在,則使用character_set_server設定值。

將操作結果從內部操作字符集轉換爲character_set_results。

重點:寬字節注入發生的位置就是PHP發送請求到MYSQL時字符集使用character_set_client設置值進行了一次編碼。

PHP測試代碼:

<!DOCTYPE html>  <meta charset="gbk"><!--僅用於基礎的顯示,換成utf8也行就是不好看-->  <?php  error_reporting(0);  $conn = mysql_connect('127.0.0.1','root','');  mysql_select_db('mysql',$conn);  mysql_query("set names gbk");  //不安全的編碼設置方式  $res = mysql_query("show variables like 'character%';"); //顯示當前數據庫設置的各項字符集  while($row = mysql_fetch_array($res)){  var_dump($row);  }  $user = addslashes($_GET['sql']); //mysql_real_escape_string() magic_quote_gpc=On addslashes() mysql_escape_string()功能類似  $sql = "SELECT host,user,password FROM user WHERE user='{$user}'";  echo $sql.'</br>';  if($res = mysql_query($sql)){  while($row = mysql_fetch_array($res)){  var_dump($row);  }  }  else{  echo "Error".mysql_error()."<br/>";  }  ?>
http://localhost/xl.php?sql=root%df%27%20or%201=1%23

是可以執行成功的!

科普:寬字節注入詳解

URL解碼sql=root’ or 1=1#

解析過程:

$_GET[‘sql’] 經過 addslashes編碼之後帶入了‘\’
1、root%df%5C%27%20or%201=1%23
2、帶入mysql處理時使用了gbk字符集
%df%5c -> 運 成功的吃掉了%5c
%27 -> ‘ 單引號成功閉合

執行了插入的sql語句。

怎麼吃的:

GBK編碼,它的編碼範圍是0×8140~0xFEFE(不包括xx7F),在遇到%df(ascii(223)) >ascii(128)時自動拼接%5c,因此吃掉‘\’,而%27、%20小於ascii(128)的字符就保留了。

補充:

GB2312是被GBK兼容的,它的高位範圍是0xA1~0xF7,低位範圍是0xA1~0xFE(0x5C不在該範圍內),因此不能使用編碼吃掉%5c。

其它的寬字符集也是一樣的分析過程,要吃掉%5c,只需要低位中包含正常的0x5c就行了。

安全過濾

上文中代碼使用了mysql_query(“set names gbk”)來設置編碼,其實在mysql中是推薦mysql_set_charset(“gbk”);函數來進行編碼設置的,這兩個函數大致的功能相似,唯一不同之處是後者會修改mysql對象中的mysql->charset屬性爲設置的字符集。

同時配套的過濾函數爲mysql_real_escape_string()。上面代碼中列出了幾個過濾的函數,他們之間的區別就是mysql_real_escape_string()會根據mysql對象中的mysql->charset屬性來對待傳入的字符串,因此可以根據當前字符集來進行過濾。

具體差別可參考:http://www.laruence.com/2010/04/12/1396.html

同理可得

由上文可得寬字節注入是由於轉編碼而形成的,那具有轉編碼功能的函數也成了漏洞的成因。

轉碼函數

mb_convert_encoding()

iconv()

以下用iconv()來演示,修改上面的代碼:

<!DOCTYPE html>  <meta charset="gbk">  <?php  error_reporting(0);  $conn = mysql_connect('127.0.0.1','root','');  mysql_select_db('mysql',$conn);  mysql_set_charset("utf8"); //推薦的安全編碼  $user = mysql_real_escape_string(($_GET['sql'])); //推薦的過濾函數  $user = iconv('GBK', 'UTF-8',$user);  $sql = "SELECT host,user,password FROM user WHERE user='{$user}'";  echo $sql.'</br>';  $res = mysql_query($sql);  while($row = mysql_fetch_array($res)){  var_dump($row);  }  ?>


http://localhost/xl.php?sql=root%e5%27or%201=1%23

同樣可以執行成功,編碼解析的過程依然如上。

總結一下漏洞成因:

代碼一

1、使用了不安全的字符集設置函數與過濾函數。

2、漏洞發生在PHP請求mysql時使用character_set_client值進行一次轉碼。

代碼二

1、使用了推薦的設置函數與過濾函數。

2、解析錯誤發生在iconv()函數轉碼時,GBK轉向UTF8吃掉了“\”

3、PHP請求mysql時轉碼安全。

另外:

當改變編碼方向時$user = iconv(‘UTF-8′, ’gbk’,$user);

通過訪問http://localhost/xl.php?sql=root%e9%8c%a6可以帶入一個\,進而註釋掉單引號。

這種情況下需要兩個參數來配合注入。

例如:

http://localhost/xl.php?sql=root%e9%8c%a6=%20or%201=1%23

總結:

寬字節注入跟HTML頁面編碼無關。

Mysql編碼與過濾函數推薦使用mysql_real_escape_string(),mysql_set_charset()。

轉編碼函數同樣會引起寬字節注入,即使使用了安全的設置函數。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章