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

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

缺陷编号: WooYun-2014-68362

漏洞标题: 74cms (20140709) 二枚二次注入

相关厂商: 74cms.com

漏洞作者: ′雨。认证白帽子

提交时间: 2014-07-13 14:16

公开时间: 2014-10-11 14:18

漏洞类型: SQL注射漏洞

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

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

Tags标签: 无

6人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-07-13: 细节已通知厂商并且等待厂商处理中
2014-07-16: 厂商已经确认,细节仅向厂商公开
2014-07-19: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2014-09-09: 细节向核心白帽子及相关领域专家公开
2014-09-19: 细节向普通白帽子公开
2014-09-29: 细节向实习白帽子公开
2014-10-11: 细节向公众公开

简要描述:

不好好的通过修改造成漏洞的代码 而是通过修改过滤函数。
现在的过滤函数, 虽然我是绕不过去了。
但是还是能找到几处能出数据的。
之前未通过,这次两个打个包来。

P.S:这很不好意思 之前测试demo的时候 因为有个是个update的点 忘记加where限制条件了 导致给某处全部都出数据了。。。。。
不只应该修改过滤函数,而且也应该在造成漏洞的代码好好的修复一下。

详细说明:

第一枚。 第一枚就不分析代码了。



首先注册一个企业会员 然后创建企业

7 5.jpg



单引号会被转义 然后转义入库。

找找出库的地方。



然后创建好企业后 发布招聘 如下。

7 6.jpg





7 7.jpg





点击发布后 可以看到报错了。 这里刚才的企业名出库了 而且带入到了查询当中。



这里稍微构造下还是能出数据。 这个咋出数据就不多说了, 第二处再来说说出数据。



_____________________________________________________________________________





第二处

与上个不同的是 这个是注册一个个人会员

然后发布简历。



来看代码



在user/personal/personal_resume.php中



code 区域
elseif ($act=='make4_save')
{
$resume_education=get_resume_education($_SESSION['uid'],$_REQUEST['pid']);

if (count($resume_education)>=6) showmsg('教育经历不能超过6条!',1,$link);
$setsqlarr['uid']=intval($_SESSION['uid']);
$setsqlarr['pid']=intval($_REQUEST['pid']);
if ($setsqlarr['uid']==0 || $setsqlarr['pid']==0 ) showmsg('参数错误!',1);
$setsqlarr['start']=trim($_POST['start'])?$_POST['start']:showmsg('请填写开始时间!',1,$link);
$setsqlarr['endtime']=trim($_POST['endtime'])?$_POST['endtime']:showmsg('请填写结束时间!',1,$link);
$setsqlarr['school']=trim($_POST['school'])?$_POST['school']:showmsg('请填写学校名称!',1,$link);
$setsqlarr['speciality']=trim($_POST['speciality'])?$_POST['speciality']:showmsg('请填写专业名称!',1,$link);
$setsqlarr['education']=trim($_POST['education'])?$_POST['education']:showmsg('请选择获得学历!',1,$link);
$setsqlarr['education_cn']=trim($_POST['education_cn'])?$_POST['education_cn']:showmsg('请选择获得学历!',1,$link);
if (inserttable(table('resume_education'),$setsqlarr))
{
check_resume($_SESSION['uid'],intval($_REQUEST['pid']));





inserttable(table('resume_education')

这里把post来的数据带入到了insert当中 入库。

这里我们提交一个单引号 然后带入insert的时候虽然是转义

但是入库后会消除转义符。

然后继续看 check_resume



code 区域
function check_resume($uid,$pid)
{
global $db,$timestamp,$_CFG;
$uid=intval($uid);
$pid=intval($pid);
$percent=0;
$resume_basic=get_resume_basic($uid,$pid);
$resume_intention=$resume_basic['intention_jobs'];
$resume_specialty=$resume_basic['specialty'];
$resume_education=get_resume_education($uid,$pid);
if (!empty($resume_basic))$percent=$percent+15;
if (!empty($resume_intention))$percent=$percent+15;
if (!empty($resume_specialty))$percent=$percent+15;
if (!empty($resume_education))$percent=$percent+15;
if ($resume_basic['photo_img'] && $resume_basic['photo_audit']=="1" && $resume_basic['photo_display']=="1")
{
$setsqlarr['photo']=1;
}
else
{
$setsqlarr['photo']=0;
}
if ($percent<60)
{
$setsqlarr['complete_percent']=$percent;
$setsqlarr['complete']=2;
}
else
{
$resume_work=get_resume_work($uid,$pid);
$resume_training=get_resume_training($uid,$pid);
$resume_photo=$resume_basic['photo_img'];
if (!empty($resume_work))$percent=$percent+13;
if (!empty($resume_training))$percent=$percent+13;
if (!empty($resume_photo))$percent=$percent+14;
$setsqlarr['complete']=1;
$setsqlarr['complete_percent']=$percent;
require_once(QISHI_ROOT_PATH.'include/splitword.class.php');
$sp = new SPWord();
$setsqlarr['key']=$resume_basic['intention_jobs'].$resume_basic['recentjobs'].$resume_basic['specialty'];
$setsqlarr['key']="{$resume_basic['fullname']} ".$sp->extracttag($setsqlarr['key']);
$setsqlarr['key']=str_replace(","," ",$resume_basic['intention_jobs'])." {$setsqlarr['key']} {$resume_basic['education_cn']}";
$setsqlarr['key']=$sp->pad($setsqlarr['key']);
if (!empty($resume_education))
{
foreach($resume_education as $li)
{
$setsqlarr['key']="{$li['school']} {$setsqlarr['key']} {$li['speciality']}";
}
}
$setsqlarr['refreshtime']=$timestamp;
}
updatetable(table('resume'),$setsqlarr,"uid='{$uid}' AND id='{$pid}'");
updatetable(table('resume_tmp'),$setsqlarr,"uid='{$uid}' AND id='{$pid}'");





$resume_education=get_resume_education($uid,$pid);



这里把刚才入库的查询了出来 所以单引号就出来了。 继续看。



code 区域
$setsqlarr['key']=$resume_basic['intention_jobs'].$resume_basic['recentjobs'].$resume_basic['specialty'];		
$setsqlarr['key']="{$resume_basic['fullname']} ".$sp->extracttag($setsqlarr['key']);
$setsqlarr['key']=str_replace(","," ",$resume_basic['intention_jobs'])." {$setsqlarr['key']} {$resume_basic['education_cn']}";
$setsqlarr['key']=$sp->pad($setsqlarr['key']);
if (!empty($resume_education))
{
foreach($resume_education as $li)
{
$setsqlarr['key']="{$li['school']} {$setsqlarr['key']} {$li['speciality']}";
}
}
$setsqlarr['refreshtime']=$timestamp;
}
updatetable(table('resume'),$setsqlarr,"uid='{$uid}' AND id='{$pid}'");
updatetable(table('resume_tmp'),$setsqlarr,"uid='{$uid}' AND id='{$pid}'");





然后把出库来的给一数组 然后带入到了update中。



造成了注入。 而且这个update 可以控制的点是在set位置的

所以可以是我们想update这table里面的什么就update什么。



77.jpg





78.jpg





报错了 稍微构造一下。



这里我们把address updata成要出的数据



7 8.jpg





79.jpg





成功了对关键字的过滤出数据。





测试了一下demo 也成功



80.jpg





http://**.**.**.**/resume/resume-show-6271.htm

漏洞证明:

见上面。

修复方案:

真的应该好好的修改代码 而不是光修改过滤函数。



对于这种二次注入 由于入库的时候只会调用一次stripcslashes



74cms做了全局转义的 如果再转义一次 那么就算入库也会含有转义符了。 自然出库也有了。



或者就是在出库之后再addslashes一次 都行。

版权声明:转载请注明来源 ′雨。@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2014-07-16 15:41

厂商回复:

感谢反馈!

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

  1. 2014-07-13 14:25 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )
    1

    刚下的74.。。放下74 让我来

  2. 2014-07-13 14:30 | ′ 雨。 认证白帽子 ( 普通白帽子 | Rank:1332 漏洞数:198 | Only Code Never Lie To Me.)
    1

    @roker 黑客 你来吧。 我马上上学去了。

登录后才能发表评论,请先 登录