最新消息:图 床

Drupal 7 – CVE-2018-7600 PoC Writeup

COOL IAM 327浏览 0评论

作者:Ricter Z
作者博客:https://ricterz.me/posts/Drupal%207%20-%20CVE-2018-7600%20PoC%20Writeup

0x00 前言

前幾天我分析了 Drupal 8.5.0 的 PoC 構造方法,但是 Drupal 7 還是仍未構造出 PoC。今天看到了 Drupalgeddon2 支持了 Drupal 7 的 Exploit,稍微分析了下,發現 PoC 構建的十分精妙,用到了諸多 Drupal 本身特性,我構造不出果然還是太菜。

首先,Drupal 7 和 Drupal 8 這兩個 PoC 本質上是同一原因觸發的,我說的同一個原因並不是像是 #pre_render 的 callback 這樣,而是都是由於 form_parent 導致 Drupal 遍歷到用戶控制的 #value,接着進行 render 的時候導致 RCE。Drupal 8 中的 element_parents 十分明顯,且從 $_GET 中直接獲取,所以很容易的能分析出來,而 Drupal 7 中的 form_parent 就藏得比較隱晦了。

那麼,這個 PoC 用到了 Drupal 中的哪些特性呢?

  • Drupal 的 router 傳參

  • Drupal 的 form cache

那麼,先從 router 講起。

0x01 Router

當訪問 file/ajax/name/#default_value/form-xxxx 的時候,在 menu.inc 中,Drupal 是這樣處理的:

function menu_get_item($path = NULL, $router_item = NULL) {
  $router_items = &drupal_static(__FUNCTION__);
  if (!isset($path)) {
    $path = $_GET['q'];
  }
    var_dump($router_items);
  if (isset($router_item)) {
    $router_items[$path] = $router_item;
  }
  if (!isset($router_items[$path])) {
    // Rebuild if we know it's needed, or if the menu masks are missing which
    // occurs rarely, likely due to a race condition of multiple rebuilds.
    if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) {
      if (_menu_check_rebuild()) {
        menu_rebuild();
      }
    }
    $original_map = arg(NULL, $path);

    $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
    $ancestors = menu_get_ancestors($parts);
    $router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' => $ancestors))->fetchAssoc();

    if ($router_item) {
      // Allow modules to alter the router item before it is translated and
      // checked for access.
      drupal_alter('menu_get_item', $router_item, $path, $original_map);

      $map = _menu_translate($router_item, $original_map);
      $router_item['original_map'] = $original_map;
      if ($map === FALSE) {
        $router_items[$path] = FALSE;
        return FALSE;
      }

看不動?沒關係,我來解釋下:

  • $_GET["q"] 取出 path;
  • 將 path 分割後進行組合,得到一個數組;
  • 數組進入數據庫查詢;

組合的結果大概是這樣:

0 = file/ajax/name/#default_value/form-xxxx
1 = file/ajax/name/#default_value/%
2 = file/ajax/name/%/form-xxxxx
3 = file/ajax/name/%/%
4 = file/ajax/%/%/%
5 = file/%/name/%/form-xxxxx
....
12 = file/%/name
13 = file/ajax
14 = file/%
15 = file

這些是什麼呢?實際上這些是 Drupal 的 router,在數據庫的 menu_router 表裡。這麼一串 array 最終和數據庫中的 file/ajax 相匹配。Drupal 會根據數據庫中的 page_callback 進行回調,也就是回調到 file_ajax_upload 函數。回調的現場:

转载请注明:IAMCOOL » Drupal 7 – CVE-2018-7600 PoC Writeup

0 0 vote
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x