命名空间
参考:
\phpinfo()也可以执行
如下代码是phti0n师傅code-breaking的function这道题目。
<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';
if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
show_source(__FILE__);
} else {
$action('', $arg);
}
简单判断,我们可以利用create_function
函数注入。但以上代码变量$action必须包含[a-z0-9_]
之外的字符,才会执行$action('',$arg);
。
可以使用%5c(\)
绕过,可以测试:
<?php
\phpinfo();
原因:
code-breaking puzzles第一题,function,为什么函数前面可以加一个%5c? 其实简单的不行,php里默认命名空间是\,所有原生函数和类都在这个命名空间中。普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。
可以理解,类似<?php echo "1";?>
这样的简单,不涉及命名空间的的php脚本,其实这个脚本本身就处于一个默认的命名空间下,这个命名空间就是\
。类似的我们也可以namespace
其他的命名空间,并通过命名空间调用函数
<?php
namespace test1{
function a(){
echo 'a';
}
}
namespace test2{
function b(){
echo 'b';
}
function phpinfo(){
echo 'phpinfo changed';
}
}
namespace{
\test1\a(); # a
\test2\b(); # b
}
非主命名空间下重写内置函数
在非主命名空间下(namespace{}
和默认)下,我们可以更改php内置函数。
主命名空间下
先尝试在namespace{}
和默认
情况下重写内置函数会是什么情况
<?php
// 默认
function phpinfo(){
echo "phpinfo changed\n";
} # 报错:PHP Fatal error: Cannot redeclare phpinfo() in
<?php
// namespace{}
namespace{
echo "phpinfo changed\n";
} # 报错:PHP Fatal error: Cannot redeclare phpinfo() in
非主命名空间下
<?php
namespace test2{
function b(){
echo 'b';
}
function phpinfo(){
echo 'phpinfo changed';
}
}
namespace{
\test2\phpinfo();
}
可以看到已经更改了函数phpinfo()
此外还可以参见另一篇文章:重构函数和反射