欢迎投稿

今日深度:

浅析白盒审计中的字符编码及SQL注入(1)

浅析白盒审计中的字符编码及SQL注入(1)


尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如gbk,作为自己默认的编码类型。也有一些cms为了考虑老用户,所以出了gbk和utf-8两个版本。

浅析白盒审计中的字符编码及SQL注入

我们就以gbk字符编码为示范,拉开帷幕。gbk是一种多字符编码,具体定义自行百度。但有一个地方尤其要注意:

通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。在php中,我们可以通过输出

echo strlen("和");

来测试。当将页面编码保存为gbk时输出2,utf-8时输出3。

除了gbk以外,所有ANSI编码都是2个字节。ansi只是一个标准,在不用的电脑上它代表的编码可能不相同,比如简体中文系统中ANSI就代表是GBK。

以上是一点关于多字节编码的小知识,只有我们足够了解它的组成及特性以后,才能更好地去分析它身上存在的问题。

说了这么多废话,现在来研究一下在SQL注入中,字符编码带来的各种问题。

0×01 MYSQL中的宽字符注入

这是一个老话题了,也被人玩过无数遍。但作为我们这篇文章的序幕,也是基础,是必须要提的。

我们先搭建一个实验环境。暂且称之为phithon内容管理系统v1.0,首先先新建一个数据库,把如下压缩包中的sql文件导入:

测试代码及数据库:http://pan.baidu.com/s/1eQmUArw 提取密码:75tu

之后的phithon内容管理系统会逐步完善,但会一直使用这个数据表。

源码很简单(注意先关闭自己php环境的magic_quotes_gpc):

//连接数据库部分,注意使用了gbk编码,把数据库信息填写进去

  1. <?php  
  2. //连接数据库部分,注意使用了gbk编码,把数据库信息填写进去  
  3. $conn = mysql_connect('localhost''root''toor!@#$'or die('bad!');  
  4. mysql_query("SET NAMES 'gbk'");  
  5. mysql_select_db('test'$conn) OR emMsg("连接数据库失败,未找到您填写的数据库");  
  6. //执行sql语句  
  7. $id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;  
  8. $sql = "SELECT * FROM news WHERE tid='{$id}'";  
  9. $result = mysql_query($sql$connor die(mysql_error()); //sql出错会报错,方便观察  
  10. ?>  
  11. <!DOCTYPE html>  
  12. <html>  
  13. <head>  
  14. <meta charset="gbk" />  
  15. <title>新闻</title>  
  16. </head>  
  17. <body>  
  18. <?php  
  19. $row = mysql_fetch_array($result, MYSQL_ASSOC);  
  20. echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";  
  21. mysql_free_result($result);  
  22. ?>  
  23. </body>  
  24. </html> 

SQL语句是SELECT * FROM news WHERE tid='{$id}',就是根据文章的id把文章从news表中取出来。

在这个sql语句前面,我们使用了一个addslashes函数,将$id的值转义。这是通常cms中对sql注入进行的操作,只要我们的输入参数在单引号中,就逃逸不出单引号的限制,无法注入,如下图:

那么怎么逃过addslashes的限制?众所周知addslashes函数产生的效果就是,让’变成\’,让引号变得不再是“单引号”,只是一撇而已。一般绕过方式就是,想办法处理\’前面的\:

1.想办法给\前面再加一个\(或单数个即可),变成\\’,这样\被转义了,’逃出了限制
2.想办法把\弄没有。

我们这里的宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。如果我们输入%df’看会怎样:

浅析白盒审计中的字符编码及SQL注入

我们可以看到,已经报错了。我们看到报错,说明sql语句出错,看到出错说明可以注入了。

为什么从刚才到现在,只是在’也就是%27前面加了一个%df就报错了?而且从图中可以看到,报错的原因就是多了一个单引号,而单引号前面的反斜杠不见了。

这就是mysql的特性,因为gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和后面的\也就是%5c变成了一个汉字“運”,而’逃逸了出来。

因为两个字节代表一个汉字,所以我们可以试试“%df%df%27”:

浅析白盒审计中的字符编码及SQL注入

不报错了。因为%df%df是一个汉字,%5c%27不是汉字,仍然是\’。

那么mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用%df,用%a1也可以:

浅析白盒审计中的字符编码及SQL注入

%a1%5c他可能不是汉字,但一定会被mysql认为是一个宽字符,就能够让后面的%27逃逸了出来。

于是我可以构造一个exp出来,查询管理员账号密码:

浅析白盒审计中的字符编码及SQL注入 


www.htsjk.Com true http://www.htsjk.com/shujukuaq/16938.html NewsArticle 浅析白盒审计中的字符编码及SQL注入(1) 尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语...
评论暂时关闭