前言

总觉得作一些专题性的总结会比四处看题来的有效果吧?XD

eval()执行代码

说起RCEeval函数自然是应该排在首位,一句话木马就经常用它吧,CMS出现它,只要参数可控就很可能存在代码执行的可能性。PHP手册对该函数做出如下定义,其中关键点是该字符串必须是合法的 PHP 代码,且必须以分号结尾。这对构造payload是非常关键的一点。

定义和用法

eval() 函数把字符串按照 PHP 代码来计算。

该字符串必须是合法的 PHP 代码,且必须以分号结尾。

如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false

下图可以看出,进过各种闭合后,得到了一个符合PHP语法的语句,于是phpinfo就被执行了。

assert()的代码执行

这个函数和eval有些不一样。assert把整个字符串参数当php代码执行,eval把合法的php代码执行

还是太菜了,试了半天没有试出这两个的函数的区别。通过构造闭合都成功了执行了phpinfo()还行吧。

php还支持一种非常酷炫的函数调用方式

注意到这边是没用;,但是在eval中,如果没有封号语句是不执行,这也就是assert的语法规范并不明显。在平时写一句话木马中,常用的应该是assert,原因是多数系统会选择禁用掉eval函数。而assert常常用来作为判断一个表达式是否存在时有很大的便利。

preg_replace修正符的命令执行

preg_replace函数主要用来执行正则表达式的搜索和替换,如php手册介绍如下。

preg_replace

(PHP 4, PHP 5, PHP 7)

preg_replace — 执行一个正则表达式的搜索和替换

说明

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

搜索subject中匹配pattern的部分, 以replacement进行替换。

第一个参数$pattern:搜索的模式,可以是一个字符串或者字符串数组,可以加\e修正符。

第二个参数$replacement:要替换的字符。

第三个参数$subject:需要被处理的字符串。

问题出在第一个参数的\e修正符上。当加上了\e修正符号时,$replacement会被当做php代码片段执行。这个环境需要在php5.4下。php7.0完全放弃了该函数,php5.5的后续版本会爆出提示,要求preg_replace_callback()来代替该函数。

create_function()

这个函数可以方便的创建一个简单的函数。但是再参数可控的情况下,可能出现执行任意代码的漏洞。之前博客也写过这个相关的了,贴上链接,这里就不赘述。

https://zhhhy.github.io/2018/10/14/RCE/

array_map

先看看php手册上的定义和用法

定义和用法

array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。

回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致。

语法

1
2
> array_map(myfunction,array1,array2,array3...
>

很明显吧。可以很简单粗暴的理解成调用一个函数,函数的参数是数组里的值。并且,函数的参数个数要和数组中元素数量相等。

call_user_func()/call_user_func_array()

这两个函数的基本原理和array_map基本一致,都是调用assert函数,再传参。导致的任意代码执行。例子就参考array_map()的吧。

总结一下

除去几个原本就能执行系统命令函数,剩下的其实就是通过各种方式去调用这些函数。在系统命令禁用了这些函数的时候,就需要想各种办法绕过了。绕过方式千奇百怪,真的是一个考验脑洞的事情。不过万变不离其宗,防御手段只要将本质问题给修补了,也就无法绕过了。