Recentemente, ao verificar a segurança dos recursos da web do banco, encontramos uma vulnerabilidade no servidor de e-mail Exim 4.89, que pode levar à execução remota de código. A vulnerabilidade é conhecida como CVE-2018-6789. Usando um exploit PoC, obtivemos um Shell reverso na máquina remota e, em seguida, acessamos o site do banco.

Naturalmente, nos perguntamos por que essa exploração da vulnerabilidade se tornou possível.
De onde veio o CVE-2018-6789?
Resumindo, a vulnerabilidade se deve a um erro no cálculo do comprimento do buffer na função base64.c: b64decode usada pelo Exim. Você pode ler mais sobre isso aqui (em inglês).
Se você inserir uma string de comprimento especial, poderá sobrescrever um byte de informação e, usando ações simples, alterar os comandos do servidor, executando assim o código arbitrário (RCE).
Exim aloca um buffer de 3 * (len / 4) +1 bytes para armazenar os dados decodificados. No entanto, se uma string base64 incorreta for fornecida à entrada da função, por exemplo, 4n + 3 long, então o Exim alocará 3n + 1 bytes para o buffer. Mas, ao mesmo tempo, ele gravará 3n + 2 bytes de dados no buffer. Isso faz com que um byte seja sobrescrito no heap.
O Exim fornece store_malloc_3 e store_free_3, que são invólucros para o malloc e funções livres do Glibc. Glibc aloca um grande bloco de dados, então armazena seus metadados nos primeiros 0x10 bytes e retorna um ponteiro para a memória onde o usuário pode escrever seus dados. É assim que se parece: Os

metadados incluem o tamanho do bloco anterior (aquele na memória acima), o tamanho do bloco atual e alguns sinalizadores. Os primeiros três bits do tamanho são usados para armazenar sinalizadores. No exemplo, o tamanho 0x81 implica que o bloco atual é de 0x80 bytes e o bloco anterior já está em uso.
Os blocos liberados, uma vez usados pelo Exim, são colocados em uma lista duplamente vinculada. O Glibc o mantém de acordo com os sinalizadores e mescla blocos liberados contíguos em um bloco maior para evitar a fragmentação. Para cada solicitação de alocação de memória, Glibc examina esses pedaços em ordem FIFO e os reutiliza.

Para melhorar o desempenho, o Exim usa seu próprio add-on de gerenciamento de memória; é baseado na estrutura de storeblock. A principal característica do storeblock é que cada um deles tem pelo menos 0x2000 bytes de tamanho, o que se torna uma limitação para exploração. Observe que o storeblock também é um bloco de dados. Isto é o que parece na memória:

Comandos suportados pelo servidor de e-mail para organizar dados no heap:
- EHLO hostname. EHLO hostname sender_host_name. , store_free store_malloc .
- . , , Exim .
- AUTH. Exim base64 . , store_get (). store_get().
- Reset EHLO/HELO, MAIL, RCPT. , Exim smtp_reset. store_reset , « ». , storeblock- store_get .
Para usar um estouro de um byte no heap, devemos ser capazes de liberar o bloco de dados que está sob a string decodificada em base64. Sender_host_name é adequado para isso.
O heap deve ser formado de forma a deixar o bloco de dados liberado acima do bloco que contém o nome_do_sender_host.

Para fazer isso, você precisa:
1. Colocar um bloco grande na bandeja não classificada. Em primeiro lugar, enviamos uma mensagem EHLO com um nome de host superdimensionado para que aloque e libere um pedaço de comprimento 0x6060 em um compartimento não classificado.
2. Selecione o primeiro storeblock. Em seguida, enviamos um comando não reconhecido para chamar store_get () e alocar o storeblock dentro do pedaço liberado.
3. Selecione o segundo bloco e libere o primeiro. Enviamos EHLO para receber o segundo bloco. O primeiro bloco é liberado sequencialmente devido a smtp_reset chamado após a conclusão de EHLO.
Depois que o heap estiver preparado, podemos usá-lo para sobrescrever o tamanho do bloco original. Modificamos 0x2021 para 0x20f1, o que expande ligeiramente o bloco.

4. Envie dados base64 e transborde 1 byte no heap. Execute o comando AUTH para enviar dados base64.
5. Crie e envie uma string de tamanho adequado. Como expandimos o bloco de dados, o início do próximo bloco agora estará em algum lugar dentro. Agora precisamos consertá-lo para passar na verificação de integridade do Glibc. Estamos enviando outra string base64 aqui.
6. Libere o bloco estendido. Para controlar o conteúdo do bloco estendido, precisamos primeiro liberar o bloco, porque não podemos editá-lo diretamente. Ou seja, temos que enviar uma nova mensagem EHLO para liberar o nome do host antigo. No entanto, o processamento do comando EHLO chama smtp_reset após a execução bem-sucedida. Isso pode levar à interrupção do programa ou término anormal. Para evitar isso, estamos enviando um nome de host inválido como um +.
7. Substitua o próximo ponteiro do storeblock sobreposto.

Depois que o bloco é liberado, podemos obtê-lo com AUTH e sobrescrever parte do storeblock sobreposto. Aqui usamos uma técnica chamada "registro parcial". Isso nos permite mudar o ponteiro sem quebrar o ASLR. Alteramos parcialmente o seguinte ponteiro para um bloco contendo linhas ACL. As linhas ACL são especificadas por um conjunto de globais, por exemplo uschar * acl_smtp_helo;
Esses ponteiros são inicializados no início do processo Exim e definidos de acordo com a configuração. Por exemplo, se a configuração contém a linha acl_smtp_mail = acl_check_mail, o ponteiro acl_smtp_mail aponta para a linha acl_check_mail.
Cada vez que o servidor recebe um comando MAIL FROM, o Exim executa uma verificação ACL, que primeiro expande acl_check_mail. Na expansão, se o Exim encontrar a linha $ {run {cmd}}, ele tentará executar o comando cmd, para que um invasor remoto possa fazer com que o código seja executado.
8. Redefina o storeblock e obtenha o storeblock que contém a ACL. O bloco ACL agora está no blockchain. Ele será liberado após smtp_reset (), e então podemos recuperá-lo novamente alocando alguns blocos.
9. Substitua as linhas ACL e execute a verificação ACL. Por fim, reescrevemos todo o bloco contendo as linhas ACL. Agora enviamos comandos como EHLO, MAIL, RCPT para executar a verificação de ACL.
A propósito, a exploração da vulnerabilidade foi facilitada pelo ASLR desabilitado por algum motivo desconhecido para nós.
Que problemas o cliente teve?
O primeiro é a falta de gerenciamento de atualizações. Devido ao fato de que a versão antiga do Exim foi usada, foi possível organizar um compromisso do sistema. Para evitar isso, recomendamos que você organize a verificação e instalação regulares de atualizações de segurança nos componentes da infraestrutura de informações.
Recomendamos verificar se há novas atualizações de segurança e críticas pelo menos uma vez por mês. Para verificar se há atualizações, é melhor usar os sites / listas de discussão de fabricantes de equipamentos ou informações dos repositórios.
O banco também carecia de um processo de gerenciamento de vulnerabilidade, razão pela qual a vulnerabilidade não foi detectada a tempo. O uso de scanners de vulnerabilidade especializados, por exemplo, OpenVAS, Nessus, xSpider, etc., ajudaria a corrigir a situação. Testes de penetração regulares e monitoramento do tempo de eliminação da vulnerabilidade também ajudariam.
E por último mas não menos importante. O banco carecia de um processo de gerenciamento de mudanças. Todas as alterações foram feitas por administradores no ambiente de produção. Consequentemente, ninguém controlou ou monitorou isso. Isso levou ao fato de que o ASLR foi desabilitado no servidor.
Resultado
Várias violações aparentemente não relacionadas resultaram no comprometimento do site do banco. Isso poderia ser usado por malfeitores para, por exemplo, alterar os dados bancários para seus próprios.
A história terminou bem. Após o acordo, imediatamente notificamos o cliente da situação. O banco atualizou urgentemente o servidor Exim para a versão atual, para a qual a vulnerabilidade não é mais relevante. No entanto, se a vulnerabilidade não tivesse sido identificada durante o teste de penetração, mas por invasores reais, o resultado poderia ter sido diferente.