Encontrando vulnerabilidades no núcleo WordPress: A trilogia de um caçador de bugs, Parte II – Supremacy

Na parte 1, mostramos como qualquer usuário assinante de um site pode ignorar várias verificações de permissão e códigos de acesso para criar e editar mensagens, utilizando uma determinada execução. Com a nossa nova superfície de ataque, continuamos a nossa caça por falhas que permitam uma maior exploração.

Examinando a nova superfície, agora podemos chegar a funcionalidade de edição de todos os comentários existentes no nosso post recém criado. Como autores do post, a ação ‘editedcomment’ em comment.php convenientemente nos permite alterar a maioria dos campos de banco de dados do comentário, incluindo autor, o conteúdo do comentário e até mesmo seu status de aprovação.

Antes de podermos fazer isso, primeiro temos que criar um comentário para o nosso post. Esta tarefa aparentemente simples, revela-se bastante difícil. Nossa mensagem é criada e editada no estado lixeira (que é uma das condições para o nosso escalonamento de privilégios ao trabalho – consulte a Parte I), enquanto o WordPress estritamente proíbe comentários em posts na lixeira.

Tal código de validação pode ser encontrando em muitos lugares, incluindo:

1

O código primeiramente verifica se o post que estamos tentando comentar existe, então podemos editá-lo e, finalmente, verifica que não é um rascunho, pendentes ou post da lixeira. Para contornar esta verificação, é preciso ser criativo novamente. Para isso, vamos apresentá-lo para postar revisões.

As revisões são registros de rascunhos ou atualizações de qualquer post. Internamente, o WordPress implementa revisões como mensagens completas e armazena-os na tabela de banco de dados de mensagens com ‘post_type’ definido como ‘revisão’. Cada revisão tem um campo ‘post_parent’, apontando para o post original a revisão se baseia.

Ao tentar editar uma revisão, a verificação de validação é feita atualmente seguindo o ponteiro ‘post_parent’, em vez da própria revisão. Acontece que, este fornece a propriedade única que estávamos procurando. Se criarmos uma pequena revisão, além do nosso post original, podemos definir seu status como algo diferente de ‘lixo’, mantendo o post original no lixo.

Usando este truque, podemos editar esta “revisão fantoche” e livremente adicionar comentários, enquanto o post da lixeira original está sendo verificado para permitir nossas ações.

Agora que temos um comentário, somos capazes de editar os campos de comentário, como mencionado anteriormente. Embora o código permita editar quase todos os campos de comentário, a nossa entrada fica estritamente filtrada e higienizada contra vários ataques como SQL Injection e ataques Cross-Site Scripting (XSS), bloqueando efetivamente os vetores de ataque “padrão”. Precisamos ir mais fundo.

Vamos examinar o processo de colocar e tirar do lixo uma postagem. Estas são realizadas usando ‘wp_trash_post ()’ e ‘wp_untrash_post ()’. Vamos começar colocando na lixeira:

2

Primeiro, o código verifica se o post existe e garante que não esteja na lixeira. Em seguida, ele muda seu status para “lixo” e atualiza o post no banco de dados. Finalmente, ele joga no lixo os comentários. Isso parece bastante simples. Mas o que faz ‘wp_trash_post_comments ()’?

3

O código extrai todos os comentários do banco de dados e armazena todos os comentários  (como “aprovado”, “spam” e assim por diante) em uma matriz dentro de um post “metadados” denominado ‘_wp_trash_meta_comments_status’.

Esta funcionalidade é útil no caso de um autor desista de ter enviado o post para a lixeira e queira restaurá-lo. Neste caso WordPress redefine os comentários para o seu estado anterior. Mas como isso funciona, exatamente? Para isso, vamos verificar wp_untrash_post_comments ‘()’:

4

Uma surpreendente SQL UPDATE, no núcleo do WordPress! Ela restaura o campo ‘comment_approved’ ao seu valor anterior antes da operação de jogar no lixo. Mas não podemos controlar esse valor? Como visto acima, é extraído diretamente do campo de metadados ‘_wp_trash_meta_comments_status’. Espere, não foi esse que escapou antes? Bem, sim, quando foi introduzido. A recuperação no banco de dados do get_post_data () retorna nossos dados diretamente para a declaração UPDATE.

Temos agora um SQL Injection em uma instrução de atualização conveniente. Ainda assim, a fim de provocá-lo, precisamos descobrir: como é que jogamos fora um post que já está na lixeira?

Na verdade, nós não precisamos. Tudo o que temos a fazer é de alguma forma criar os metadados ‘wp_trash_meta_comments_status’ anexados ao nosso post contendo nossa injeção de status de comentário, e, em seguida, tirá-lo da lixeira.

Para isso, vamos reutilizar o mesmo truque que usamos para comentar no nosso post – vamos usar um fantoche. Quando comentamos em nosso fantoche, o comentário de pós ID é da nossa revisão pós ID, então quando nós descartamos nossa revisão seus próprios comentários são de fato as que estão sendo descartados e inseridos no metadados ‘wp_trash_meta_comments_status’. E, no entanto, quando  o WordPress insere metadados para uma revisão post, que é o nosso post original, permitindo que nós recuperemos da lixeira e adicionemos SQLi. QED

As implicações de segurança para este SQL Injection são graves. Exploits simples poderiam ter um atacante aprovando qualquer comentário. Uma opção mais destrutiva seria inutilizar o sistema de comentários, adicionando um comentário com um ID malicioso que quebra a atribuição de ID de incremento automático. Com algum esforço, este também pode ser convertido em um comentário XSS no visor.

Esta vulnerabilidade foi atribuída ao CVE-2015-2213, e foi corrigida na versão 4.2.4 do WordPress.

Nossa próxima e última parte para esta trilogia irá descrever um ataque Cross-Site Scripting (XSS) distinto no conteúdo do post, que ainda é uma vulnerabilidade 0-day, afetando cada instalação do WordPress.

Estamos trabalhando em conjunto com os desenvolvedores principais do WordPress e pretendemos divulgar esta informação só depois que uma correção for disponibilizada na próxima versão do WordPress.

Gostaríamos de agradecer à equipe principal de desenvolvedores do WordPress pela a sua resposta responsável e esforços de comunicação abertos.

5

Acesse o conteúdo original (em inglês) no link.