作者:綠盟科技
來源:http://blog.nsfocus.net/drupal8-cve-2017-6926/
近期,著名的Drupal CMS網站爆出7個漏洞,其中1個嚴重漏洞CVE-2017-6926,具有發表評論權限的用戶可以查看他們無權訪問的內容和評論,并且還可以為該內容添加評論。綠盟科技于上周發布了《Drupal下周將發布重要安全補丁威脅預警通告》。
本篇文章對Drupal 8 – CVE-2017-6926漏洞進行了詳細分析。
CVE-2017-6926 漏洞詳情
先看下drupal官網的通告:
https://www.drupal.org/sa-core-2018-001

有發布評論權限的用戶,可以查看他們無權訪問的內容和評論。
并且還可以為此內容添加評論。
想要觸發這個漏洞,必須啟用評論系統,并且攻擊者必須有權發布評論。
從漏洞描述來看,問題可能出在評論的權限控制上了。
但是這里有一個坑,筆者當時就掉進去了:這里的權限,指的是文章的權限?還是評論的權限呢?是攻擊者可以訪問他們不公開的評論呢?還是攻擊者可以訪問不公開的文章的公開評論呢?下面我會詳細的分析這個漏洞,并給出上面問題的答案。
漏洞是在8.4.5上解決的,看一下8.4.5修改的內容:

這里在CommentController.php(評論控制器)里加上了一個對entity實體是否有view權限的判斷。
這個好理解,之前沒有對entity的權限進行判斷,導致不可view的entity也通過了權限檢查,從而導致了越權。
我們看下關于entity的介紹:

我們再看下漏洞存在的函數
\core\modules\comment\src\Controller\CommentController.php
public function replyFormAccess(EntityInterface $entity, $field_name, $pid = NULL) {
// Check if entity and field exists.
$fields = $this->commentManager->getFields($entity->getEntityTypeId());
if (empty($fields[$field_name])) {
throw new NotFoundHttpException();
}
$account = $this->currentUser();
// Check if the user has the proper permissions.
$access = AccessResult::allowedIfHasPermission($account, 'post comments');
$status = $entity->{$field_name}->status;
$access = $access->andIf(AccessResult::allowedIf($status == CommentItemInterface::OPEN)
->addCacheableDependency($entity));
再來看下這個方法的路由
\core\modules\comment\comment.routing.yml
comment.reply:
path: '/comment/reply/{entity_type}/{entity}/{field_name}/{pid}'
defaults:
_controller: '\Drupal\comment\Controller\CommentController::getReplyForm'
_title: 'Add new comment'
pid: ~
requirements:
_custom_access: '\Drupal\comment\Controller\CommentController::replyFormAccess'
options:
parameters:
entity:
type: entity:{entity_type}
可見replyFormAccess其實是getReplyForm方法的權限檢查模塊,傳入replyFormAccess方法的參數將會是{entity_type}/{entity}/{field_name}/{pid}
我們實際測一下,訪問這個模塊,看看發送的參數是什么樣子的:
對kingsguard test評論進行評論:


注意看url:http://127.0.0.1/d/drupal4/comment/reply/node/1/comment/1
{entity_type}:node
{entity}:1
{field_name}:comment
{pid}:1
現在可以明確了,傳入replyFormAccess里的entity類型是node節點類型,接著下斷看下entity的數據

在大概知道$entity是什么之后,我們再來看下補丁代碼:

可見補丁加了一個判斷
andIf(AccessResult::allowedIf($entity->access('view')));
看下allowedIf方法是怎么實現的:
public static function allowedIf($condition) {
return $condition ? static::allowed() : static::neutral();
}
可見allowedIf通過傳入的參數的True/False來判斷是否有權限進行操作。
這樣看來,$entity->access(‘view’)只有True/False兩種可能出現的值。
我們在后臺下斷,并且構造一個entity->access(‘view’),下斷看看$test何時能為False:

首先來找找,關于回復評論處的權限設置:
我們在admin賬號下,發表一片名為kingsguard的文章,此文章有一個kingsguard test的評論:

我們將kingsguard test 這條評論的權限編輯成不公開

我們用admin賬號回復一下這個評論,后臺看下$$test = $entity->access(‘view’);的值:


毫無疑問,$test的值是true
現在用另一個賬號登錄,也訪問http://127.0.0.1/d/drupal4/comment/reply/node/2/comment/6這個連接試試:

$test仍然為true。
當時筆者就是掉到這個坑里了,明明這條評論設置為不公開,為什么不同用戶訪問,$entity->access(‘view’)都是true呢?
后來證明了,其實這里的entity->access(‘view’)也同樣不是單條評論的是否有view權限,而是這篇文章是否有view權限。
其實觀察url就可以發現這個問題了:
http://127.0.0.1/d/drupal4/comment/reply/node/1/comment/6(回復第一篇文章的第六個評論)
http://127.0.0.1/d/drupal4/comment/reply/node/2/comment/6(回復第二篇文章的第六個評論)
顯然這里的1和2,指的是文章的編號,同時也是entity的編號,那顯然entity指的是文章而不是評論。
我們用admin賬號編輯kingsguard這篇文章,把published選項的勾去掉:

這時候用admin賬號回復kingsguard test這條評論:

對于admin賬號來說,$entity->access(‘view’);仍為true
再用其他賬號登錄:

因為admin賬號發布的文章都被admin賬號設置為不公開了,所以這里看不到任何文章。
繼續用這個賬號訪問:
http://127.0.0.1/d/drupal4/comment/reply/node/2/comment/6

可以看到,雖然文章不公開,仍然可以看到不公開文章的評論,并且還能對評論進行回復。
再看下后臺下的斷點:

此時的$entity->access(‘view’)變成了false
利用驗證
假設id為{node_id}的文章被作者設置為不公開,想查看/回復此文章的id為{comment_id}的評論。
訪問http://x.x.x.x/comment/reply/node/{node_id}/comment/{comment_id}
漏洞修復
升級Drupal至最新版本
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/559/
暫無評論