PHP 7 的几处函数安全小变化

To Begin With

最近在准备 LANCTF,想把环境迁移到 PHP 7,却想到一些 payload 失效了。想着什么时候总结成一个笔记,恰巧在 FB 发现有人写了一篇博文,拜读后结合 CTF 环境整理了一下,总体来说,弃用了较多不安全的使用方式,但运行环境未过多限制时仍可使用。

测试环境

docker pull php:7.3.3-apache
docker pull php:7.0-apache

函数变化

preg_replace

preg_replace() 不再支持 /e 修饰符,官方曾提到

如果设置了这个被弃用的修饰符, preg_replace() 在进行了对替换字符串的 后向引用替换之后, 将替换后的字符串作为php 代码评估执行(eval 函数方式),并使用执行结果 作为实际参与替换的字符串。单引号、双引号、反斜线(\)和 NULL 字符在后向引用替换时会被用反斜线转义。

Version Description
7.0.0 Support for the /e modifier has been removed. Use preg_replace_callback() instead.
5.5.0 The /e modifier is deprecated. Use preg_replace_callback() instead. See the PREG_REPLACE_EVAL documentation for additional information about security risks.

但在 php 7.0 时,移除了(removed)该修饰符,不能再使用此方式的后门。

create_function

create_function 被废弃

Warning
This function has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.

但目前还是弃用状态,在简单环境下仍可以使用该函数,但在未来的版本中会被移除。后面出现的相似情况不再赘述。

mysql_*

需要使用 mysqli 或者 pdo

unserialize

unserialize 第二个参数( optional )添加了白名单。可以通过unserialize的过滤参数来设定是否过滤指定的类返回__PHP_Incomplete_Class_Name类的对象,__PHP_Incomplete_Class_Name是一个没有方法的类。具体的参数为allowed_classes,其指向需要过滤的类,默认是true,既可以对所有类都可以完全反序列化。

$data = unserialize($serializedObj1 , ["allowed_classes" => true]);
$data2 = unserialize($serializedObj2 , ["allowed_classes" => ["MyClass1", "MyClass2"]]); 

assert

第一个参数为 string 断言的情况被废弃。

Version Description
7.2.0 Usage of a string as the assertion became deprecated. It now emits an E_DEPRECATED notice when both assert.active and zend.assertions are set to 1.
7.0.0 assert() is now a language construct and not a function. assertion can now be an expression. The second parameter is now interpreted either as an exception (if a Throwable object is given), or as the description supported from PHP 5.4.8 onwards.

目前尚可使用。

parse_str

Warning
Using this function without the result parameter is highly DISCOURAGED and DEPRECATED as of PHP 7.2.
Dynamically setting variables in function's scope suffers from exactly same problems as register_globals.
Read section on security of Using Register Globals explaining why it is dangerous.

没有第二个参数的使用方式被弃用,将来第二个参数会是必选。

Version Description
7.2.0 Usage of parse_str() without a second parameter now emits an E_DEPRECATED notice.

session_start

初始化时可传入一个数组来配置 php.ini 中的选项。
http://php.net/manual/en/session.configuration.php
(xctf 2018)

<html>
    <head>
        <title>BabyPHP</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <form action="#" method="post">
            Please input your name:<input type="text" name="name" />
            <input type="submit" value="submit" />
        </form>
    </body>
</html>
<?php
    highlight_file(__FILE__);
    ob_start();
    error_reporting(0);
    ini_set('open_basedir', '/var/www/html:/tmp');
    $file = 'function.php';
    $func = isset($_GET['function'])?$_GET['function']:'filters';
    call_user_func($func,$_GET);
    include($file);
    session_start();
    $_SESSION['name'] = $_POST['name'];
    if($_SESSION['name']=='admin'){
        header('location:admin.php');
    }
?>

杂项

十六进制字符串

如:'0x0e12345' 不再是弱类型

移除了 ASP 和 script PHP 标签

<% %><script language='php'>code</script>不再支持,只能使用<?php ?><?= ?>
此外<? ?>需要看是否开启短标签。

Refer:
1.https://www.freebuf.com/articles/web/197013.html
2.http://php.net/manual/en/function.create-function.php
3.http://php.net/parse_str
4.http://php.net/manual/en/function.assert.php

Updated At: Author:xmsec
Chief Water dispenser Manager, delivering but striving.
Github
comments powered by Disqus