Ícone do site Conviso AppSec

Nova CVE-2023-4314 identificada em plugin do WordPress

plugin do WordPress

Neste artigo, vamos analisar um estudo de caso de uma CVE encontrada em um plugin do WordPress – wpDataTables, quando anterior à versão 2.1.66, que consiste em uma vulnerabilidade da categoria A8: Insecure Deserialization (desserialização insegura).

Estudo de Caso: plugin do WordPress

Recentemente foi identificada uma vulnerabilidade em um plugin do WordPress – wpDataTables, classificada como CWE-502: Deserialization of Untrusted Data. Esta  vulnerabilidade pode ser classificada como A8: Insecure Deserialization.

Através desta vulnerabilidade, tecnicamente, é possível passar conteúdo desserializável por um parâmetro de um endpoint admin ajax do WordPress e realizar injeção de objetos PHP. Além disso, caso seja encontrado um ou múltiplos gadgets chains adequados é possível obter execução remota de comando no sistema. Ademais, a brecha de segurança também pode ser explorada pelo frontend do plugin.

A vulnerabilidade ocorre em uma função chamada serializedPhpRenderData do arquivo class.wpdatatables.php, a qual faz uma requisição HTTP a uma URL externa e desserializa o conteúdo através da função nativa unserialize do PHP.

Exploração

Primeiramente, para explorarmos a vulnerabilidade podemos simular um gadget chain adicionando no final do arquivo source/class.wpdatatables.php do plugin o seguinte código:

class Evil {

  public function __wakeup() : void {

    die(“Arbitrary deserialization”);

  }

}

Este código representa uma classe chamada Evil e possui a função mágica __wakeup que será chamada logo após instanciar a classe através da desserialização insegura e que invocará a função die do PHP para fins de testes. 

Após isso, é necessário armazenar o payload O:4:”Evil”:0:{}; em um arquivo acessível por URL pública (ex.: por webserver, pastebin e etc) para que seja posteriormente executado  pelo plugin. Este é o payload que vai instanciar a classe Evil do gadget chain que adicionamos no código para fins de testes durante a desserialização insegura.

Em seguida, entramos na página wpDataTables > Create a Table > Create a data table linked to an existing data source.

Na entrada de seleção Input data source type selecionamos Serialized PHP array.

Em Input file path or URLcolocamos a URL contendo o payload e pressionamos Save Changes.

Após salvar as alterações, é possível observar o payload sendo executado e retornando como resposta “Arbitrary deserialization”.

Análise da vulnerabilidade

Ao identificar a utilização da função unserialize, foi necessário pensar em explorar a sequência de funções antecedentes e encontrar o endpoint raíz.

Através da análise do código fonte do plugin, foi possível chegar a uma ajax action no arquivo wdt_admin_ajax_actions.php que dava início a sequência de chamadas necessárias para alcançar a função serializedPhpRenderData.

Esta ajax action chama a função wdtSaveTableWithColumns que recebe um parâmetro POST table e que ao final da função invoca a função saveTableConfig passando o valor do table como um JSON.

Entrando na função saveTableConfig do arquivo class.wdtconfigcontroller.php, foi possível identificar que a função chama tryCreateTable passando os valores table_type e content do JSON passado no parâmetro POST citado anteriormente. Vale ressaltar que, foi preciso definir o valor da chave table_type do JSON como “serialized” para a desserialização ser engatilhada nas funções posteriores e o valor da chave content como a URL do webserver contendo o nosso payload.

Posteriormente, analisando a função tryCreateTable do arquivo class.wdtconfigcontroller.php foi possível identificar que é instanciada uma variável chamada $tableData onde será definida algumas propriedades baseadas nos valores que passamos por POST anteriormente, e, em seguida, ser passada na função fillFromData na linha 708.

Já na função fillFromData do arquivo class.wpdatatable.phpé possível identificar na linha 2268 um switch condicional que verifica o valor de $tableData->table_type. Se o valor for serialized então ele passa o content para a função serializedPHPBasedConstruct, como pode ser visto na linha 2296.

Entrando na função serializedPHPBasedConstruct do arquivo class.wpdatatable.php é possível perceber que o primeiro parâmetro da função é chamado $url, assim, é conclusivo que o content é utilizado como uma URL posteriormente. Esse parâmetro é passado na função sourceRenderData na linha 1647.

Fazendo uma análise da função sourceRenderData do arquivo class.wpdatatable.php foi possível identificar que na linha 1799 é verificado se o sourceType é serialized e sem seguida passado o parâmetro $source (nossa URL) na função serializedPhpRenderData.

Ao explorar a função serializedPhpRenderData do mesmo arquivo, é possível identificar que na segunda linha é realizada uma requisição para a nossa URL, salvo em uma variável chamada $serialized_content, e, em seguida, desserializada na nossa função alvo que é a unserialize.

Conclusivamente, a ordem da sequência de funções seria essa:

  1. add_action(‘wp_ajax_wpdatatables_save_table_config’, ‘wdtSaveTableWithColumns’);
  2. saveTableConfig
  3. WDTConfigController::tryCreateTable
  4. $tbl->fillFromData($tableData, array())
  5. $this->serializedPHPBasedConstruct(…
  6. $PHPArray = self::sourceRenderData($this, ‘serialized’, $url);
  7. $sourceArray = self::serializedPhpRenderData($source, $wpId);
  8. unserialize

Impacto

A vulnerabilidade requer um privilégio mínimo de administrador no WordPress, além disso, ela permite que sejam realizados ataques em um ambiente multisite. O multisite é um recurso especial do WordPress que as empresas e marcas utilizam para gerenciar vários sites a partir de um único painel do CMS (Content Management System), ou seja, é possível ampliar a invasão para outros sites além do atual.

Além disso, caso seja encontrado um gadget chain apropriado, é possível obter execução remota de comandos.

Mitigação

Neste contexto, podem existir diversas maneiras de mitigar essa vulnerabilidade, algumas delas são:

Caso seja necessário a utilização do unserialize:

Outras alternativas ao unserialize:

Referências

Sair da versão mobile