PHP函数默认设置引发的安全问题

栏目: PHP · 发布时间: 5年前

内容简介:暑假不学习,和咸鱼并无区别。今天刚好在发掘一下默认配置可能存在问题和一些容易触发漏洞的php函数,这里做一个总结。查阅PHP手册:

PHP函数默认设置引发的安全问题

前言

暑假不学习,和咸鱼并无区别。今天刚好在发掘一下默认配置可能存在问题和一些容易触发漏洞的 php 函数,这里做一个总结。

in_array()函数

相关知识

查阅PHP手册:

(PHP 4, PHP 5, PHP 7)

in_array() — 检查数组中是否存在某个值

大体用法为:

bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )

而官方的解释也很有意思:

大海捞针,在大海(haystack)中搜索针(needle),如果没有设置 strict 则使用宽松的比较。

漏洞问题

我们注意到

bool $strict = FALSE

宽松比较如果不设置,默认是FALSE,那么这就会引来安全问题

如果设置 $strict = True :则 in_array() 函数还会检查 needle 的类型是否和 haystack 中的相同。

那么不难得知,如果不设置,那么就会产生弱类型的问题

例如:

<?php
$whitelist = range(1, 24);
$filename='sky';
var_dump(in_array($filename, $whitelist));
?>

PHP函数默认设置引发的安全问题

此时运行结果为false

但是如果我们将filename改为1sky

PHP函数默认设置引发的安全问题

成功利用弱比较,而绕过了这里的检测

典型案例

上面的实例已说明了问题,其实这个问题是存在于上次文件的检查的

在php-security-calendar-2017-Wish List中

class Challenge {
    const UPLOAD_DIRECTORY = './solutions/';
    private $file;
    private $whitelist;

    public function __construct($file) {
        $this->file = $file;
        $this->whitelist = range(1, 24);
    }

    public function __destruct() {
        if (in_array($this->file['name'], $this->whitelist)) {
            move_uploaded_file(
                $this->file['tmp_name'],
                self::UPLOAD_DIRECTORY . $this->file['name']
            );
        }
    }
}

$challenge = new Challenge($_FILES['solution']);

我们不难看出,代码的意图上是想让我们只传数字名称的文件的

而我们却可以用 1skyevil.php 这样的名称去bypass

由于没有修改in_array的默认设置,而导致了安全问题

可能这比较鸡肋,但在后续对文件的处理中,前一步产生了非预期,可能会直接影响后一步的操作

漏洞修复

将宽松比较设为true即可

PHP函数默认设置引发的安全问题

可以看到,搜索的时候,直接要求前两个参数均为array

PHP函数默认设置引发的安全问题

此时已经不存在弱比较问题

filter_var()函数

相关知识

(PHP 5 >= 5.2.0, PHP 7)

filter_var — 使用特定的过滤器过滤一个变量

mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )

虽然官方说这是过滤器,但是如果用这个函数进行过滤,并且相信他的结果,是非常愚蠢的

漏洞问题

比较常用的当属FILTER_VALIDATE_URL了吧,但是它存在非常多的过滤bypass

PHP函数默认设置引发的安全问题

本应该用于check url是否合法的函数,就这样放过了可能导致SSRF的url

类似的bypass还有:

0://evil.com:80$skysec.top:80/
0://evil.com:80;skysec.top:80/

详细SSRF漏洞触发可参考这篇文章:

http://skysec.top/2018/03/15/Some%20trick%20in%20ssrf%20and%20unserialize()/

除此之外,还能触发xss

javascript://comment%0Aalert(1)

典型案例

// composer require "twig/twig"
require 'vendor/autoload.php';

class Template {
    private $twig;

    public function __construct() {
        $indexTemplate = '<img ' .
            'src="https://loremflickr.com/320/240">' .
            '<a href="{{link|escape}}">Next slide »</a>';

        // Default twig setup, simulate loading
        // index.html file from disk
        $loader = new TwigLoaderArrayLoader([
            'index.html' => $indexTemplate
        ]);
        $this->twig = new TwigEnvironment($loader);
    }

    public function getNexSlideUrl() {
        $nextSlide = $_GET['nextSlide'];
        return filter_var($nextSlide, FILTER_VALIDATE_URL);
    }

    public function render() {
        echo $this->twig->render(
            'index.html',
            ['link' => $this->getNexSlideUrl()]
        );
    }
}

(new Template())->render();

这里不难看出是有模板渲染的,而模板渲染则有可能触发xss

那么寻找可控点,不难发现

public function render() {
        echo $this->twig->render(
            'index.html',
            ['link' => $this->getNexSlideUrl()]
        );
    }

这里的Link是使用了 getNexSlideUrl() 的结果

我们跟进这个函数

public function getNexSlideUrl() {
        $nextSlide = $_GET['nextSlide'];
        return filter_var($nextSlide, FILTER_VALIDATE_URL);
    }

这里的 nextSlide 使用就充分相信了filter_var()的过滤结果

所以导致了XSS:

?nextSlide=javascript://comment%250aalert(1)

漏洞修复

不要轻易的相信filter_var(),它只能当做初步验证函数,结果不能当做是否进入if的后续程序的条件

class_exists()函数

相关知识

(PHP 4, PHP 5, PHP 7)

class_exists — 检查类是否已定义

bool class_exists ( string $class_name [, bool $autoload = true ] )

检查指定的类是否已定义。

漏洞问题

上述操作表面上看起来似乎没有什么问题,和函数名一样,检查指定的类是否已定义

但是关键点就在于选项上,可以选择调用或不调用 __autoload
更值得思考的是,该函数默认调用了 __autoload

什么是 __autoload

PHP手册是这样描述的:

在编写面向对象(OOP) 程序时,很多开发者为每个类新建一个 PHP 文件。 这会带来一个烦恼:每个脚本的开头,都需要包含(include)一个长长的列表(每个类都有个文件)。

在 PHP 5 中,已经不再需要这样了。 spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。

那么自动调用 __autoload 会产生什么问题呢?

我们从下面的案例来看

典型案例

function __autoload($className) {
    include $className;
}

$controllerName = $_GET['c'];
$data = $_GET['d'];

if (class_exists($controllerName)) {
    $controller = new $controllerName($data['t'], $data['v']);
    $controller->render();
} else {
    echo 'There is no page with this name';
}

class HomeController {
    private $template;
    private $variables;

    public function __construct($template, $variables) {
        $this->template = $template;
        $this->variables = $variables;
    }

    public function render() {
        if ($this->variables['new']) {
            echo 'controller rendering new response';
        } else {
            echo 'controller rendering old response';
        }
    }
}

案例同样来自php-security-calendar-2017

乍一看,这样的代码并不存在什么高危的问题,但实际上因为 class_exists() 的check自动调用了 __autoload()
所以我们可以调用php的内置类实现攻击,例如 SimpleXMLElement

正常来说,应该是可以这样触发render():

http://localhost/xxe.php?c=HomeController&d[t]=sky&d[v][new]=skrskr

可以得到回显

controller rendering new response

但此时我们可以使用 SimpleXMLElement 或是 simplexml_load_string 对象触发盲打xxe,进行任意文件读取

构造:

simplexml_load_file($filename,'SimpleXMLElement')

c=simplexml_load_file&d[t]=filename&d[v]=SimpleXMLElement

即可

而这里的$filename使用最常见的盲打XXE的payload即可

这就不再赘述,详细可参看

https://blog.csdn.net/u011721501/article/details/43775691

漏洞修复

对于特点情况,可关闭自动调用

bool $autoload = false

htmlentities()函数

相关知识

(PHP 4, PHP 5, PHP 7)

htmlentities — 将字符转换为 HTML 转义字符

string htmlentities ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $encoding = ini_get("default_charset") [, bool $double_encode = true ]]] )

本函数各方面都和 htmlspecialchars() 一样, 除了 htmlentities() 会转换所有具有 HTML 实体的字符。

如果要解码(反向操作),可以使用 html_entity_decode()。

漏洞问题

从上述知识来看,该函数应该是用来预防XSS,进行转义的了

但是不幸的是

PHP函数默认设置引发的安全问题 该函数默认使用的是 ENT_COMPAT

即不会转义单引号,那么就可能产生非常严重的问题,例如如下案例

典型案例

$sanitized = [];

foreach ($_GET as $key => $value) {
    $sanitized[$key] = intval($value);
}

$queryParts = array_map(function ($key, $value) {
    return $key . '=' . $value;
}, array_keys($sanitized), array_values($sanitized));

$query = implode('&', $queryParts);

echo "<a href='/images/size.php?" .
    htmlentities($query) . "'>link</a>";

由于不会转义单引号

我们可以随意闭合

<a href='/images/size.php?htmlentities($query)'>link</a>

此时我们替换 htmlentities($query)

' onclick=alert(1) //

这样原语句就变成了

<a href='/images/size.php?' onclick=alert(1) //'>link</a>

这样就成功的引起了xss

故此最终的payload为

/?a'onclick%3dalert(1)%2f%2f=c

漏洞修复

必要的时候加上 ENT_QUOTES 选项

openssl_verify()函数

相关知识

(PHP 4 >= 4.0.4, PHP 5, PHP 7)

openssl_verify — 验证签名

int openssl_verify ( string $data , string $signature , mixed $pub_key_id [, mixed $signature_alg = OPENSSL_ALGO_SHA1 ] )

openssl_verify() 使用与pub_key_id关联的公钥验证指定数据data的签名signature是否正确。这必须是与用于签名的私钥相对应的公钥。

漏洞问题

这个函数看起来是用于验证签名正确性的,怎么会产生漏洞呢?

我们注意到它的返回值情况

PHP函数默认设置引发的安全问题

其中,内部发送错误会返回-1

我们知道if判断中,-1和1同样都可以被当做true

PHP函数默认设置引发的安全问题

那么假设存在这样的情况

if(openssl_verify())

那么它出现错误的时候,则同样可以经过check进入后续程序

如何触发错误呢?

实际上只要使用另一个与当前公钥不匹配的算法生成的签名,即可触发错误

典型案例

class JWT {
    public function verifyToken($data, $signature) {
        $pub = openssl_pkey_get_public("file://pub_key.pem");
        $signature = base64_decode($signature);
        if (openssl_verify($data, $signature, $pub)) {
            $object = json_decode(base64_decode($data));
            $this->loginAsUser($object);
        }
    }
}

(new JWT())->verifyToken($_GET['d'], $_GET['s']);

此时我们只需要使用一个不同于当前算法的公钥算法,生成一个有效签名,然后传入参数

即可导致openssl_verify()发生内部错误,返回-1,顺利通过验证,达成签名无效依然可以通过的目的

漏洞修复

if判断中使用

if(openssl_verify()===1)

PHP函数默认设置引发的安全问题

后记

php作为一种功能强大的语言,它的库中还有许多默认配置会引发安全问题,还等我们一一去探索,由于本人很菜,不能一一枚举,在此抛砖引玉了!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python语言程序设计

Python语言程序设计

(美)Y. Daniel Liang / 机械工业出版社 / 2013-3 / 79.00元

本书保持了Liang博士系列丛书中一贯的、标志性的教与学的哲学:以实例教,由实践学。书中采用了他所提出的已经经过实践检验的“基础先行”的方法,即在定义类之前,首先使用清晰简明的语言介绍基本程序设计概念,如选择语句、循环和函数;在介绍面向对象程序设计和GUI编程之前,首先介绍基本逻辑和程序设计概念。书中除了给出一些以游戏和数学为主的典型实例外,还在每章的开始使用简单的图形给出一两个例子,以激发学生的......一起来看看 《Python语言程序设计》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试