Интересные уязвимости PostgreSQL

PostgreSQL уязвимость

Несколько раз в год у PostgreSQL выходит новый релиз с парой уяз­вимос­тей. Как правило уязвимости поз­воля­ют прев­ратить неп­ривиле­гиро­ван­ного поль­зовате­ля в superuser. В Postgres все прос­то — устанавливаем пат­чи в момент выхода обновле­ния и продолжаем спать спокойно. Но многие форки оста­ются уяз­вимыми. Я проанализировал пару интересных уязвимостей PostgreSQL в поис­ках инте­рес­ных лазе­ек и нашел там очень мно­го инте­рес­ного.

Еще по теме: Ускорение и автоматизация слепой SQL-инъекции

Анализ интересных уязвимостей PostgreSQL

Во­обще, у Postgres есть куча фор­ков. Потен­циаль­но все они уяз­вимы ко все­му, что будет перечис­лено в этой статье. В резуль­тате на таких базах май­нят или происходят исто­рии как с фотографиями Scarlett.

Мо­жет показать­ся, что эпич­ные уязвимости — вер­ный приз­нак «решета», которым луч­ше не поль­зовать­ся. Это не так. Откры­тая пуб­ликация всех исто­ричес­ких уяз­вимос­тей — то, что не дает заметать под ковер zero day.

Что ж, давайте перей­дем, к сути. Что можно сделать с недопат­ченным «Пост­грес»?

Статья в образовательных целях и предназначается для пенстеров (белых хакеров). Взлом и несанкционированный доступ уголовно наказуем. Ни редак­ция spy-soft.net, ни автор не несут ответс­твен­ность за ваши действия.

Уязвимость PostgreSQL CVE-2020-25695

Уяз­вимос­ти CVE-2020-25695 под­верже­ны 13.0, 12.4, 11.10, 10.15 и дру­гие мажор­ные вер­сии, нын­че уже дос­тигшие EOL. Overall score 8,8. В уяз­вимос­ти так­же экс­плу­ати­рует­ся ком­бинация из мно­жес­тва нет­риви­аль­ных фич. Тем не менее экс­плу­ата­ция под­ходит для script kiddies — прос­то зафигачить SQL-зап­рос, и готово, никакой воз­ни с под­став­ными реп­ликами, написа­нием кода или чего‑то такого.

Ахил­лесова пята PostgreSQL — про­цесс ваку­уми­зации aka VACUUM. Он уда­ляет вер­сии дан­ных, которые нет необ­ходимос­ти видеть новым тран­закци­ям. Иног­да его запус­кает сисад­мин или cron от име­ни сисад­мина. Иног­да он запус­кает­ся сам — ког­да уда­лилось или обно­вилось дос­таточ­но мно­го строк. В этом слу­чае он называ­ется autovacuum. И запус­кает­ся он от име­ни супер­поль­зовате­ля.

Вот бы добавить какого‑нибудь кода к ваку­уму, что­бы он выпол­нился от име­ни супер­поль­зовате­ля, да? Об этом раз­работ­чики Postgres, конеч­но, подума­ли. На вре­мя ваку­уми­зации кон­крет­ной таб­лицы кон­текст выпол­нения перек­люча­ется на вла­дель­ца таб­лицы. Если мы запили­ли свою таб­лицу — ну, наши фун­кции при ее ваку­уми­зации выпол­нятся с нашими пра­вами. Работа­ет это так.

По­луча­ется, что нам нуж­но во вре­мя ваку­уми­зации отло­жить взлом до момен­та окон­чания тран­закции. Потому что до ком­мита мы выпол­няем­ся с недос­таточ­но кру­тым кон­тек­стом. Решение этой задачи доволь­но прос­тое: мож­но соз­дать триг­гер DEFFERED, который выпол­нится при ком­мите. Вот кусочек кода из advisory отправ­ленно­го при репор­те бага.

Как нам сде­лать, что­бы этот триг­гер выз­вался во вре­мя ваку­ума? Для это­го нуж­но, что­бы ваку­ум встав­лял дан­ные, а он их уда­ляет… Прос­то надо сде­лать так, что­бы ваку­ум одной таб­лицы встав­лял дан­ные в дру­гую!

Ка­кие фун­кции вызыва­ются при ваку­уме? Фун­кции индексов по выраже­нию. Рас­смот­рим код экс­пло­ита пол­ностью.

Здесь ваку­ум exp вызыва­ет sfunc(), которая встав­ляет дан­ные в t0. Затем триг­гер на t0 вызыва­ет string() в кон­це тран­закции с кон­тек­стом супер­поль­зовате­ля, который, в свою оче­редь, вызыва­ет snfunc(). А он гран­тит супер­поль­зовате­ля ата­кующе­му. Для экс­плу­ата­ции этой уяз­вимос­ти нуж­на воз­можность соз­давать таб­лицы и индексы.

CVE-2020-25695 най­дена Эть­еном Стол­мансом aka staaldraad и под­робно опи­сана в его бло­ге. Денис Смир­нов так­же адап­тировал эту уяз­вимость для GreenplumDB.

Уязвимость PostgreSQL CVE-2021-23214

Уяз­вимос­ти CVE-2021-23214 под­верже­ны 14.0, 13.4, 12.8, 11.13, 10.18. Overall score 8,1. А еще уяз­вимы ока­зались все пулеры соеди­нений — PgBouncer, PgPool II и Odyssey.

TLDR: если исполь­зует­ся кли­ент­ская аутен­тифика­ция по TLS-сер­тифика­ту и есть MITM, мож­но в начало соеди­нения добавить выпол­нение сво­его зап­роса.

Пост­грес­ный про­токол обме­на дан­ными пос­тро­ен на со­обще­ниях. Каж­дое сооб­щение начина­ется с 4 байт, содер­жащих информа­цию о раз­мере сооб­щения. Потом идет один байт, опре­деля­ющий тип пакета. Оставше­еся мес­то может быть занято пакетос­пецифич­ными дан­ными.

Нор­маль­ный сер­вер пер­вым делом отпра­вит кли­енту startup-сооб­щение с пред­ложени­ем перей­ти на TLS-шиф­рование, получит сог­ласие кли­ента, передаст сокет биб­лиоте­ке OpenSSL, а от нее уже получит безопас­ный канал для обще­ния, в котором про­ведет аутен­тифика­цию.

В PostgreSQL аутен­тифици­ровать­ся мож­но по‑раз­ному. Нап­ример, по паролю откры­тым тек­стом. Но это стрем­но со всех сто­рон. Мож­но вос­поль­зовать­ся MD5-аутен­тифика­цией: сер­вер приш­лет соль, кли­ент перехе­ширу­ет пароль, себя и соль, а потом отпра­вит сер­веру. Но при этом взло­мав базу и про­читав пред­став­ление pg_authid, мож­но получить дос­таточ­но дан­ных, что­бы зай­ти в базу любым дру­гим поль­зовате­лем с MD5-аутен­тифика­цией.

Мож­но вос­поль­зовать­ся схе­мой SCRAM-SHA-256, при этом взлом базы не поз­волит исполь­зовать получен­ные сек­реты. Даже зай­ти в ту же самую базу по сты­рен­ным дан­ным не получит­ся.

А мож­но вооб­ще «делеги­ровать ответс­твен­ность Фун­ту» — исполь­зовать аутен­тифика­цию по TLS-сер­тифика­там. При этом, ког­да уста­нов­лено TLS-соеди­нение, Common Name сер­тифика­та будет срав­нивать­ся с поль­зователь­ским. Если они сов­пали — зна­чит, у кли­ента есть сер­тификат, выписан­ный доверен­ным цен­тром. У такого под­хода мно­го плю­сов: нап­ример, ротация сек­ретов боль­ше не проб­лема DBA. Пусть кли­ент сам раз­бира­ется, где добыть валид­ный серт, если ста­рый про­тух.

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

У PostgreSQL доволь­но мел­кие пакеты. Нап­ример, пакет ReadyForQuery — 6 байт. Для чте­ния из сокета необ­ходим сис­темный вызов — это дол­го. Поэто­му Postgres и все пулеры чита­ют дан­ные про запас. Кто‑то называ­ет это буфери­заци­ей, кто‑то — readahead. Из буфера readahead бай­ты идут уже на пар­синг пакетов. Буфер readahead напол­няет­ся нап­рямую из сетево­го сокета либо из потока TLS в шиф­рован­ном соеди­нении. А вот в момент сме­ны нешиф­рован­ного соеди­нения про­исхо­дит… а ничего не про­исхо­дит.

В OpenSSL переда­ется не буфер readahead, а само сетевое соеди­нение. Те бай­ты, что приш­ли нешиф­рован­ными, оста­ются лежать как бы счи­тан­ными. Как буд­то получен­ными из шиф­рован­ного соеди­нения. Этим может вос­поль­зовать­ся man in the middle, добавив вслед за startup-сооб­щени­ем сооб­щение SimpleQuery с прос­тым зап­росом:

Ког­да аутен­тифика­ция в OpenSSL будет успешно завер­шена, сер­вер про­дол­жит счи­тывать сооб­щения из буфера readahead и выпол­нит SimpleQuery, как если бы он при­шел от поль­зовате­ля.

Прин­цип работы уяз­вимос­ти CVE-2021-23214
Прин­цип работы уяз­вимос­ти CVE-2021-23214

У этой уяз­вимос­ти есть и сим­метрич­ная кли­ент­ская CVE-2021-23222: MITM может под­сунуть свой ответ на пер­вые зап­росы кли­ента вмес­то того, что говорит сер­вер на самом деле. Но экс­плу­ата­ция этой уяз­вимос­ти тре­бует нефиго­вого зна­ния кода кли­ент­ско­го при­ложе­ния. Нап­ример, как‑то так.

Прин­цип работы уяз­вимос­ти CVE-2021-23222
Прин­цип работы уяз­вимос­ти CVE-2021-23222

В Postgres фикс кли­ент­ской и сер­верной уяз­вимос­тей пред­полага­ет не толь­ко сброс буфера пос­ле startup-пакета, но и запись в лог о попыт­ке нахими­чить с TLS. В акту­аль­ных вер­сиях попыт­ка экс­плу­ата­ции не прой­дет незаме­чен­ной и, веро­ятно, раз­будит монито­рин­ги безопас­ности. Мой фикс для этих уяз­вимос­тей в «Одис­сее» выг­лядит так. В «Одис­сее» они, кста­ти, извес­тны под дру­гими номера­ми: CVE-2021-43766 и CVE-2021-43767.

CVE-2021-23214 и подоб­ные уяз­вимос­ти в PG най­дены Джей­кобом Чем­пионом, пос­ле выхода фик­сов он написал до­воль­но инте­рес­ный спи­сок пожела­ний к про­екту для повыше­ния безопас­ности в будущем.

Заключение…

…тюрем­ное может гро­зить при исполь­зовании этой информа­ции необ­думан­но. Пом­ните, что все эти раз­вле­чения пред­став­лены тут, прос­то что­бы подумать о веч­ном, битах и бай­тах, все такое. Ставьте апдей­ты сво­евре­мен­но. Исполь­зуйте экс­пло­иты, толь­ко что­бы учить­ся, иссле­довать и этич­но репор­тить о проб­лемах безопас­ности. И не забывайте вов­ремя делать резер­вные копии!

Еще по теме: Лучшие сайты для поиска уязвимостей

Дима (Kozhuh)

Эксперт в кибербезопасности. Работал в ведущих компаниях занимающихся аналитикой компьютерных угроз. Анонсы новых статей в Телеграме.

Добавить комментарий