CVE-2018-12613_phpmyadmin文件包含漏洞分析

前言

在做代码审计的时候我想起了之前那个让我记忆深刻的漏洞,没错就是CVE-2018-12613.当时在 SCTF 中有这个漏洞的题目,应该是chamd5 的文章出来不久, 复现了一把.后来HCTF 出了一道类似的题目,印象就一直比较深,这次回忆起来想看一下能不能把那个漏洞仔细分析下,便有此文.

正文

漏洞分析

文章的描述已经很详尽了,请看:https://mp.weixin.qq.com/s/HZcS2HdUtqz10jUEN57aog

index.php 中存在一段代码,可以造成 LFI,

<?php 
$target_blacklist=array(
  'import.php','export.php'
);
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 个条件,过了就能包含.分别是不空,字符串,不以 index 开头,不在黑名单里,以及漏洞函数checkPageValidity. 跟进该函数:

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;
    }

windows 下的 payload 为:

file=source.php%253f/../../../windows\win.ini

linux 下的 payload 为:

file=source.php%3f/../../../etc/passwd

中间件在解析get请求的时候先做一遍 url 解码.

通过 payload 的步进,我们可以看到$page 的值一直在变化:

payload

终于在最后一个 return true 的地方返回了 true.那么为什么一定要在最后一个 return 的地方返回呢?

windows 文件命名特性

看了很多人的文章,大家不约而同的提到:双重编码可以使 windows 下直接包含文件. 首先我测试了下,如果 payload 里的%25被去掉了会变成什么样,如图:

winerror

可以看到,确实报错了,但报的不是 no such file or directory而是no error很奇怪的一个错误是吧.

我又对比了下 linux 的

Linuxerror

(这里我故意把文件名写错,如果不写错的话是直接可以包含不会报错的,因此为了更鲜明的对比,我把它报错信息整出来了)

可以看到这里虽然 linux 下由 apache 传递给 php 时也是获得了 source.php?/这一个路径,但是很明显已经不返回 No error了.所以为什么?

下面我测试了一段代码,

<?php
include($_REQUEST['file']);
?>

然后 fuzz 了 payload 中的问号字符: ?file=source.php%3f/../../../.superId

burp

从图里可以看到,包括%22,%3f,%2e在内的字符串都会导致文件无法包含.这到底是为什么?

经过不断的资料翻找,我翻到了有国人在 php 论坛上争论这到底是不是 php 的 bug

https://bugs.php.net/bug.php?id=76519 这个我认为和 php 无关吧,你总不能 include 一个变量让用户可控吧.

最后终于看到了https://github.com/vulnspy/vulnspy.github.io/issues/1提到这篇文章windows_nameing-a-file

filename

这里明确地指出了,windows文件命名时不能带哪些字符.OK,和我 fuzz 的结果是一致的,可以认为问题确实是这样,为什么双重 url 编码能过?是因为解了一层 url 后% 3 f 这三个字符都是 属于windows 可以命名文件的字符.

如果漏洞代码里不是?而是一个其他的字符比如_,那就不需要双重编码了.

REFENCE

https://mp.weixin.qq.com/s/HZcS2HdUtqz10jUEN57aog

https://github.com/vulnspy/vulnspy.github.io/issues/1

https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file

END

没有人说这是什么原因,只解释为特性.

如果你做过相关研究,应该发现文章有一点小问题,因为它和真正的path 处理有点不一样,windows 下 cd 一个不存在的目录/../是可以到上层的,但 linux 下不行.这和我们谈的 windows 下不能包含?/文件而 linux可以包含,恰恰是相反的.https://zsxq.tricking.io/topic/873/

我个人认为cd 和文件包含是完全两个不同的东西,文件包含触发的机制应该属于 php 的范畴,至于究竟为何,目前需要继续深入的跟踪下去.

posted @ 2020-08-10 01:28  p4ssw0rd  阅读(19)  评论(0)    收藏  举报