PHP文件包含&phpMyAdmin4.8.1漏洞分析

文件包含所涉及的函数

include:
被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照 [include_path] 指定的目录寻找。如果在 [include_path]下没找到该文件则 include 最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则 include 结构会发出一条警告;这一点和 [require]不同,后者会发出一个致命错误。
include_once:
include_once 语句在脚本执行期间包含并运行指定文件。此行为和 [include] 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含。如同此语句名字暗示的那样,只会包含一次。
require:
require 和 [include] 几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 [include] 只产生警告(E_WARNING),脚本会继续运行。
require_once:
require_once 语句和 [require] 语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

以上函数通俗易懂地理解方式就是将所包含内容原封不动的复制覆盖掉当前include语句

演示环境搭建

phpstudy_pro + PHP5.6.9
allow_url_fopen=On
allow_url_include=On
演示文件:


将其命名为include.php

要包含的文件:

将其命名为test.txt

演示

1,直接传入文件名的方式:

Snipaste_2020-08-13_14-37-34.png
http://127.0.0.1/include.php?url=test.txt

我们看到已经成功包含和运行了test.txt文件中的phpinfo()函数

2,利用PHP支持的协议进行传递

Snipaste_2020-08-13_14-43-11.png

以上是PHP官方文档中列出的PHP所支持的协议

1,[file://] 协议

使用方法:

file://[文件的绝对路径and文件名]
相对路径./[文件名]

绝对路径:


file.png

相对路径:


Snipaste_2020-08-13_15-01-44.png

2,[http://]协议

用法:

http://[网址]+[文件名]
Snipaste_2020-08-13_15-06-27.png

3,[php://]协议

用法:

php://input
post->[要执行的php代码]
Snipaste_2020-08-13_15-13-01.png

4,[Data://]协议

用法:

data://text/plain,[要执行的php代码]
data://text/plain;base64,[要执行的php代码base64的编码]

1,没有base64编码的:


Snipaste_2020-08-13_15-21-59.png

2,经过base64编码的:


Snipaste_2020-08-13_15-24-54.png

PHPMyAdmin 4.8.1 文件包含漏洞分析

分析

漏洞文件:
index.php


Snipaste_2020-08-13_15-29-05.png

根据代码分析,我们要满足五个条件才能执行include语句


Snipaste_2020-08-13_15-39-57.png

为了满足条件4我们找到了这个数组
Snipaste_2020-08-13_15-42-46.png

现在我们为了满足条件5还需要知道checkPageValidity函数是如何定义的

利用Seay代码审计工具右键定位到此函数


Snipaste_2020-08-13_15-47-55.png

这里给定了两个参数 $page和$whitelist其中$whitelist 默认是一个空数组
第一个if :
if (empty($whitelist)) {
            $whitelist = self::$goto_whitelist;
        }

如果$whitelist数组为空时则$whitelist=self::$goto_whitelist

self::$goto_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',
    );

第二个if:

if (! isset($page) || !is_string($page)) {
            return false;
        }

如果$page没有定义或为空时 or 不是字符串时return false

第三个if:

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

如果$page在$whitelist数组中时返回True

456~460行:

    $_page = mb_substr(
            $page,
            0,
            mb_strpos($page . '?', '?')
        );

获取$page?之前的所有字符并赋值给$_page

第四个if

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

如果$_page在$whitelist数组中则返回True

465~470行

$_page = urldecode($page);
        $_page = mb_substr(
            $_page,
            0,
            mb_strpos($_page . '?', '?')
        );

这里和456~460行大体一样,就是将$page进行了解码

第五个if和第四个一样
这里我们只需要满足条件返回True就够了
我们只需要在$whitelist 中找一个不在黑名单中的文件进行包含就可以了
这里解码我们只需要给它"套层皮"就行了
?->%3F->%253F
想象将现在仅仅只是被去了层皮

Getshell

因为这个包含漏洞需要一个登陆权限
所以无法直接包含连接
所以我们要写入一个文件用于生产木马(包含漏洞会解析一切类型的文件)
我们先在目标上写入一个txt或任何类型的文件内容如下:


Snipaste_2020-08-13_16-52-39.png

这个脚本的意思为在当前路径写入一个名为shell.php的文件内容为" 我们现在包含它


Snipaste_2020-08-13_17-00-02.png

什么都没有发生看看文件写入了吗?
因为是在index.php中包含的所以应该和它同级
Snipaste_2020-08-13_17-02-19.png

成功写入
菜刀连接:
Snipaste_2020-08-13_17-03-50.png

连接成功,可以继续渗透服务器了.

你可能感兴趣的:(PHP文件包含&phpMyAdmin4.8.1漏洞分析)