Base orientada a objetos da vulnerabilidade de desserialização do PHP

1. Fundação PHP orientada a objetos

Para falar sobre a desserialização do PHP, você precisa envolver orientação a objetos, porque a maioria das explorações de desserialização envolve a desserialização de "objetos". Portanto, você precisa entender os fundamentos da orientação a objetos.

Orientação a objetos é uma espécie de idéia de programação centrada em "objetos", que decompõe o problema a ser resolvido em vários "objetos".O objeto é um todo composto de informações e a descrição do processamento da informação.

1. Conceitos básicos

  • Objetos
    Objetos são representações abstratas de coisas. Na terminologia orientada a objetos, tudo é um objeto, e um objeto representa uma operação funcional específica.Não precisamos saber como esse objeto implementa uma determinada operação, precisamos apenas saber quais operações o objeto pode concluir.

  • Abstract
    Abstraction ( Abstract) é ignorar as características não essenciais em coisas que não têm nada a ver com o objetivo atual e prestar mais atenção às características essenciais relacionadas ao objetivo atual, de modo a descobrir a semelhança das coisas e classificar as coisas com semelhança em uma categoria para obter um conceito abstrato de.

  • Encapsulamento Encapsulamento
    ( Encapsulation) refere-se à combinação das propriedades e comportamento de um objeto em uma unidade independente e ocultar os detalhes internos do objeto tanto quanto possível.

    De um modo geral, o encapsulamento tem dois significados:

    • Combine todas as propriedades e comportamentos do objeto para formar uma unidade independente indivisível. Os valores de propriedade do objeto (exceto os valores de propriedade pública) só podem ser lidos e modificados pelo comportamento deste objeto;
    • Oculte os detalhes internos do objeto o máximo possível, formando uma barreira para o mundo exterior, e a conexão com o exterior só pode ser realizada por meio da interface externa
  • Herança Herança
    ( Inheritance) é um modelo hierárquico que conecta classes a classes. Herança significa que os objetos de uma classe particular possuem os atributos e comportamentos de sua classe geral. Herança significa "posse automática", ou seja, a classe especial não precisa redefinir as propriedades e comportamentos que foram definidos na classe geral, mas automaticamente e implicitamente possui as propriedades e comportamentos de sua classe geral. Quando essa classe especial é herdada por sua classe especial de nível inferior, seus atributos e comportamentos herdados e autodefinidos são herdados pela classe especial de nível seguinte. A herança é, portanto, transitiva, incorporando a relação do particular e do geral na natureza.

    Classe pai: Uma classe é herdada por outras classes, que podem ser chamadas de classe pai, ou classe base, superclasse Subclasse
    : Uma classe que integra outras classes é chamada de subclasse, também conhecida como classe derivada

Os conceitos acima podem ser abstratos e obscuros para iniciantes. Existem muitos conceitos em orientação a objetos, como classe, objeto, herança, polimorfismo, etc. O cultivo de ideias de programação orientada a objetos precisa ser continuamente acumulado no processo de aprendizado. Para aprender o conhecimento da vulnerabilidade de desserialização do PHP, primeiro entenda o conhecimento básico de "classe", "objeto", "instanciação" e outros conhecimentos básicos, e então siga O aprofundamento do conhecimento relevante pode aprofundar a programação orientada a objetos.

2. Classes e Objetos

Uma classe é um recurso abstrato que define uma coisa. Ela encapsula a forma dos dados e as operações nesses dados. O interior de uma classe consiste em variáveis ​​de membro (atributos) e funções de membro (métodos),

  • Variável de membro: Uma variável definida dentro da classe. O valor da variável é invisível para o mundo externo, mas pode ser acessado por meio de funções de membro. Depois que a classe é instanciada como um objeto, a variável pode se tornar um atributo do objeto
  • Funções de membro: define funções associadas a um determinado objeto dentro de uma classe. As funções de membro também são conhecidas como métodos, que são usados ​​para executar operações específicas e podem acessar e manipular atributos da classe, usando palavras-chave functionpara definir funções de membro.
// 定义类的语法格式
class class_name
{
    
    
    //类中定义的属性和方法
}
// 定义一个Person类
class Person
{
    
    
    //类中定义的属性和方法
    // 属性
    public $name;        // 姓名
    public $age;         // 年龄
    // 成员函数
    public function tell(){
    
    
        print($this->name."今年".$this->age."岁!");                        
    } 
}

Os objetos são o resultado da instanciação da classe. Depois de definir uma classe em PHP, você pode usar newa palavra-chave para instanciar um objeto de uma classe. Seu formato de sintaxe é o seguinte:

$object_name = new class_name();
<?php
    class Person
    {
    
    
        public $name;        // 姓名
        public $age;         // 年龄
        // 成员函数
        public function tell(){
    
    
            print($this->name."今年".$this->age."岁!");                        
        } 
    }
    $p = new Person();		  // 创建 Person 类的实例,即对象,名为$p
    $p -> name = "张三";	  // 给对象的 name 属性赋值
    $p -> age = 18;			  //
    echo $p -> tell();		  // 张三今年18岁!
?>

3. Introdução aos modificadores comuns de classes

  • private
    privateIndica campos privados privatee métodos modificados por palavras-chave 只能在类的内部使用, que não podem ser chamados pelo objeto instanciado da classe, nem pela subclasse da classe.
  • protected
    protegido significa protegido, 只能在类本身和子类中使用.
  • public
    publicUm campo ou método modificado por uma palavra-chave indica que é público, ou seja, o campo e o método podem ser acessados ​​através do nome do objeto em qualquer lugar do PHP. Ao mesmo tempo, publictambém é o modificador padrão para campos e métodos.

4. Construtor e destruidor

O construtor é executado automaticamente quando o objeto da classe é instanciado, onde os membros podem ser inicializados ou algumas operações especiais podem ser executadas. Correspondente a ele está um destruidor, que é executado automaticamente quando o objeto instanciado é destruído. Geralmente é usado para executar algum trabalho para limpar recursos, como liberar memória, excluir variáveis ​​e fechar conexões de banco de dados, etc.

1), construtor

Em PHP, o nome do construtor é nomeado uniformemente __construct(). Ou seja, se uma função nomeada for declarada em uma classe __construct(), a função será tratada como um construtor e executada quando uma instância do objeto for criada. O formato de sintaxe do construtor é o seguinte:

function __construct([参数列表]){
    
    
    // 构造函数体
}
<?php
    class Student{
    
    
        private $name;
        private $age;
        function __construct()
        {
    
    
            $this->name = "zhangsan";
            $this->age = 18;
        }
        public function toString(){
    
    
            echo $this->name."今年".$this->age."岁。";
        }
    }
    $s = new Student();		// 实例化对象的时候,自动去调用构造函数__construct,对属性进行初始化
    $s->toString();
?>

2), destruidor

O destruidor também possui uma nomenclatura uniforme, ou seja __destruct(), . Os destruidores permitem que um código arbitrário seja executado depois que um objeto é usado para limpar a memória. Por padrão, apenas a memória ocupada pelas propriedades do objeto é liberada e os recursos relacionados ao objeto são excluídos. Ao contrário dos construtores, os destruidores não aceitam nenhum parâmetro.

<?php
    class Counter{
    
    
        private static $count = 0;
        function __construct()
        {
    
    
            self::$count++;
        } 
        function __destruct()
        {
    
    
            self::$count--;
        }
        function getCount()
        {
    
    
            return self::$count;
        }
    }
    $num1 = new Counter();				// 实例化对象,触发构造方法,count的值+1,变为1
    echo $num1->getCount()."<br>";		// 1
    $num2 = new Counter();				// 实例化对象,count的值+1,变为2
    echo $num2->getCount()."<br>";      // 2
    $num2 = NULL;                   	// 销毁对象$num2,count的值-1,变为1
    echo $num1->getCount()."<br>";      // 1
?>

2. Conhecimento básico de serialização

1. O papel da serialização

A serialização é o processo de conversão das informações de estado de um objeto (atributos) em uma string que pode ser armazenada ou transmitida. Converta objetos ou arrays em strings que podem ser armazenadas/transmitidas

Use funções em php serialize()para serializar objetos ou arrays e retornar uma string contendo fluxos de bytes para representar

2. Expressão após a serialização

// 所有序列化之后的格式第一位都是数据类型的英文字母的简写
<?php
	echo serialize(null);            // N;
	echo serialize(666);             // i:666;
	echo serialize(66.6);            // d:66.599999999999994315658113919198513031005859375;
	echo serialize(true);            // b:1;
	echo serialize(false);           // b:0;
	echo serialize("benben");        // s:6(长度):"benben";(如果字符串中有双引号“"”,序列化之后,被双引号闭合,正因为有前面字符串的长度,所以才可以区分哪个是字符串内容中的双引号)
	echo serialize(array('benben','dazhuang','laoliu'))        //  a:3:{i:0;s:6:"benben";i:1;s:8:"dazhuang";i:2;s:6:"laoliu";}
?>

Tipos de dados comuns após a serialização:

  • a: arraytipo de matriz
  • b: booleanBooleano
  • d: doubleflutuar
  • i: integertipo inteiro
  • r: objec referencereferência de objeto
  • s: non-escaped binary stringstring binária sem escape
  • S: escaped binary stringstring binária com escape
  • C: custom objectobjeto personalizado
  • O: classobjeto
  • N: nullvazio
  • R: pointer referencereferência do ponteiro
  • U: unicode string Unicodestring codificada

3. Serialização de objetos

  • "Classe" não pode ser serializado, "objeto" pode ser serializado; apenas variáveis ​​de membro são serializadas, funções de membro não são serializadas

    <?php
    class test{
          
          
        public $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    }
    $a = new test();
    echo serialize($a);        // O:4:"test":1:{s:3:"pub";s:6:"benben";}
    ?>
    

    Explicação após a serialização do "objeto":

    • OObject
    • 4: comprimento do nome da classe
    • "test": Indica o nome da classe
    • 1: número de atributos de membro
    • s: O tipo da variável nome pub é uma string
    • 3: o comprimento do nome da variável
    • "pub":nome variável
    • s: O tipo do valor da variável é uma string
    • 6: o comprimento do valor da variável
    • "benben":variável
  • Depois que privatea propriedade privada decorada com o modificador for serializada, adicione " %00类名%00" antes do nome da propriedade privada (aqui %00está a codificação de URL do caractere nulo ( Null), que na verdade é invisível).

    <?php
    	class test{
          
          
        private $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    	}
    	$a = new test();
    	echo serialize($a);               // O:4:"test":1:{s:9:"testpub";s:6:"benben";}
    	echo urlencode(serialize($a));    // O%3A4%3A%22test%22%3A1%3A%7Bs%3A9%3A%22%00test%00pub%22%3Bs%3A6%3A%22benben%22%3B%7D
    ?>
    

    Quando o atributo $pubé privatemodificado por modificadores, depois que o "objeto" é serializado, a diferença do exemplo anterior é: , s:9:"testpub"se você usar codificação de URL para saída, verá que testhaverá antes e depois %00, portanto, o comprimento do membro nome do atributo é9

  • Após protecteda serialização, os atributos do membro decorados com modificadores adicionarão " %00*%00" antes do nome da variável (aqui %00está a codificação de URL do caractere nulo ( Null), que na verdade é invisível).

    <?php
    class test{
          
          
        protected $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    }
    $a = new test();
    echo serialize($a);        // O:4:"test":1:{s:6:"*pub";s:6:"benben";}
    ?>
    
  • Quando serializamos um objeto, o valor da variável membro do objeto é outro objeto após a instanciação, após a serialização, o valor da variável é o valor serializado de outro objeto.

    <?php
    class test1{
          
          
        var $pub='benben';
        function jineng(){
          
          
            echo $this->pub;
        }
    }
    class test2{
          
          
        var $ben;
        function __construct(){
          
          
            $this->ben=new test1();
        }
    }
    $a = new test2();
    echo serialize($a);           // O:5:"test2":1:{s:3:"ben";O:5:"test1":1:{s:3:"pub";s:6:"benben";}}
    ?>
    

3. Desserialização

1. O papel da desserialização

Restaurar a string serializada para um objeto instanciado
insira a descrição da imagem aqui

2. As características da desserialização

  • O conteúdo após a desserialização é um objeto

    <?php
    class test {
          
          
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
          
          
            echo $this->a;
        }
    }
    $d = serialize(new test());
    echo $d;                     // "对象"序列化:O:4:"test":3:{s:1:"a";s:6:"benben";s:4:"*b";i:666;s:7:"testc";b:0;}
    var_dump(unserialize($d));   // object(test)#1 (3) {  ["a"]=>  string(6) "benben"  ["b":protected]=>  int(666)  ["c":"test":private]=>  bool(false)}
    ?>
    
  • O valor no objeto gerado pela desserialização é fornecido pelo valor na desserialização; não tem nada a ver com o valor predefinido da classe original

    <?php
    class test {
          
          
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
          
          
            echo $this->a;
        }
    }
    // 将序列化之后的字符串中变量a的值,改为dazhang,将私有属性c的值改为true
    $d = 'O:4:"test":3:{s:1:"a";s:8:"dazhuang";s:4:"%00*%00b";i:666;s:7:"%00test%00c";b:1;}';
    $d = urldecode($d);
    // 反序列化之后对象的值与原有类中的值无关,而只与反序列化中的值有关
    var_dump(unserialize($d));  // object(test)#1 (3) {  ["a"]=>  string(8) "dazhuang"  ["b":protected]=>  int(666)  ["c":"test":private]=>  bool(true)}
    ?>
    
  • A desserialização não aciona os métodos membros da classe (exceto o método mágico); ela precisa chamar o método antes que possa ser acionado (a classe original deve existir)

    <?php
    class test {
          
          
        public  $a = 'benben';
        protected  $b = 666;
        private  $c = false;
        public function displayVar() {
          
          
            echo $this->a;
        }
    }
    $d = 'O:4:"test":3:{s:1:"a";s:8:"dazhuang";s:4:"%00*%00b";i:666;s:7:"%00test%00c";b:1;}';
    $e = urldecode($d);
    $f = unserialize($e);
    $f->displayVar();        // 反序列化后,生成对象,调用displayVar(),输出:dazhuang
    ?>
    

O resumo de conhecimento acima vem do aprendizado de vulnerabilidade de desserialização php da Orange Technology , combinado com meu próprio entendimento.

Acho que você gosta

Origin blog.csdn.net/weixin_45954730/article/details/131852957
Recomendado
Clasificación