Voltar ao início

Desserialização Insegura em PHP

Por quê “Desserialização Insegura” ? Percebi que é uma falha muita interessante e, lembrando de quando havia iniciado nessa área, percebi pouca visibilidade da mesma. Então irei explicar um pouco sobre ela e como pode ser explorada na linguagem de programação PHP.

Serialização é o processo de quando um objeto é transformado em uma cadeia de bytes e desta forma pode ser manipulado de maneira mais fácil, seja através de transporte pela rede ou salvo no disco.

Desserialização já é o contrário de serialização, transforma uma cadeia de bytes em objeto.

Mas o que é Desserialização Insegura?

A desserialização insegura é uma falha de quando ocorre, como o próprio nome já diz, uma desserialização de forma insegura, havendo possibilidades de modificação do objeto através de códigos e afetando alguma funcionalidade da aplicação.

Um exemplo bem simples de um código em PHP vulnerável a esta falha, está logo abaixo:

<?php
Class  Pessoas
{
    public $nome = 'Doka';
    public $time = 'GA';
    public $idade = 17;
    public $funcao = 'Estagiário';
    public $contaAdmin = False; // Se for True a conta é administrativa, caso seja False, não é administrativa.
    public  function  validateAdmin(){
    if ($this->contaAdmin){             // checando o valor da variavel $contaAdmin
        echo  ' [+] '  .  $this->nome .  ' é administrador\n';
    } else {
        echo  ' [+] '  .  $this->nome .  ' NÃO é administrador\n';
        }
    }
}
$objeto_pessoa =  new  Pessoas();
echo  serialize($objeto_pessoa);
?>

Como vemos, o código acima está serializando o objeto $objeto_pessoa e, dentro dele, checando se o valor da variável $contaAdmin é True ou False, caso seja True, a conta será administrativa e vice-versa.

Este código gera o seguinte valor para gente:

O:7:"Pessoas":5:{s:4:"nome";s:4:"Doka";s:4:"time";s:2:"GA";s:5:"idade";i:17;s:6:"funcao";s:11:"Estagiário";s:10:"contaAdmin";b:0;}

Este valor é a representação do objeto serializado. Para entendermos melhor, destrincharemos abaixo.

O → Representa um objeto
0:7:"Pessoas":5:
O: quantidade_de_caracteres: nome_da_classe: quantidade_de_propriedades:
s → Representa uma string
s:4:"Doka";
s: quantidade_de_caracteres: string
i → Representa um valor inteiro
i:17;
i:valor_inteiro;
b → Representa um valor booleano(True/False)
b:0;
b:valor_booleano;

A estrutura do nosso objeto serializado contém 5 propriedades, sendo elas:

“Nome”: ”Doka”;

“Time”: “GA”;

“idade”: 17;

“funcao”: “Estagiário”;

“contaAdmin”: 0.

Desserialização

Para desserializar o valor, basta usar a função built-in do PHP unserialize($objeto_serializado). Como é mostrado no código abaixo:

<?php
Class  Pessoas
{
    public $nome = 'Doka';
    public $time = 'GA';
    public $idade = 17;
    public $funcao = 'Estagiário';
    public $contaAdmin = False; // Se for True a conta é administrativa, caso seja False, não é administrativa.
    public  function  validateAdmin(){
    if ($this->contaAdmin){             // checando o valor da variavel $contaAdmin
        echo  ' [+] '  .  $this->nome .  ' é administrador\n';
    } else {
        echo  ' [+] '  .  $this->nome .  ' NÃO é administrador\n';
        }
    }
}
$objeto_pessoa =  new  Pessoas();
$objeto_serializado = serialize($objeto_pessoa);

$admin = unserialize($objeto_serializado);
echo $admin->validateAdmin();
?>

O valor gerado por ele é este: “[+] Doka NÃO é administrador”, justamente pelo fato da função validateAdmin() estar validando o valor da variável $contaAdmin, que é False. Caso $contaAdmin fosse True, retornaria o seguinte valor: “[+] Doka é administrador”.

Métodos mágicos PHP

Métodos mágicos são algumas funções especiais que sobrescrevem algumas ações padrões do PHP e são chamadas de forma antecedente quando são executadas em um objeto.

Estão disponíveis os seguintes métodos mágicos em PHP: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone(), e __debugInfo().

Mas os mais interessentes para nós, neste momento, são o __sleep() e o __wakeup().

serialize() checa se a classe tem uma função com o nome mágico __sleep(), caso tenha, será executada de forma prioritária, esse método retorna um array com as propriedades do objeto a ser serializado, como visto anteriormente.

Já a função __wakeup() é utilizada para restabelecer quaisquer conexões de banco de dados que possam ter sido perdidas durante a serialização e executar outras tarefas de reinicialização.

E se isto fosse colocado em produção?

Explorando Desserialização Insegura

Para demonstrar como seria um ambiente simples e vulnerável à essa falha, utilizaremos um laboratório da PortSwigger.

Ao autenticarmos na aplicação, olhando os cookies, percebe-se que existe um objeto encodado em base64.

Após decodar, vemos que a propriedade “admin” está com o valor booleano 0. Modificando o mesmo para 1, convertendo para base64 novamente e trocando o cookie original pelo novo gerado, obtemos uma conta administrativa na aplicação.

Como é fácil explorar uma falha assim né? Felizmente, hoje temos mais recursos para proteger códigos de vulnerabilidades como essa, o único problema é que, ás vezes, o código não está vulnerável, mas sim a administração de funcionalidades de um site, por exemplo.

Gosto bastante de falhas WEB, pretendo trazer mais uma ou duas para cá, se gostarem, claro.

Enfim, foi isso! Espero que tenham gostado!

Um ótimo dia, uma ótima tarde e uma ótima noite a todos 😉


Referências

https://portswigger.net/web-security/deserialization

https://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic

https://www.oracle.com/br/technical-resources/articles/java/serialversionuid.html