3. Подбор типов данных (NULL)
Подбор типов данных (NULL): Уточнение структуры
Знать количество колонок недостаточно — нужно, чтобы типы данных в UNION совпадали. В строгом мире SQL нельзя объединить числовой ID и текстовый пароль в одной колонке. Для решения этой задачи хакеры используют NULL — универсальное значение, которое совместимо с любым типом.
Посмотрим, как пошаговое замещение NULL реальными данными помогает найти «текстовые окна» для вывода секретной информации.
1. Механика: "Магия NULL"
Представьте запрос в Go-коде:
SELECT id, name, price FROM products WHERE category = '%s' (через fmt.Sprintf).
Хакер уже узнал, что здесь 3 колонки. Но он не знает, где там строки, а где числа. Он начинает подставлять:
category = 'Electronics' UNION SELECT 'a', NULL, NULL--(Первая колонка — строка?) → Success (или Ошибка в Postgres)category = 'Electronics' UNION SELECT NULL, 'a', NULL--(Вторая колонка — строка?) → Success (Появился текст на странице!)category = 'Electronics' UNION SELECT NULL, NULL, 'a'--(Третья колонка — строка?) → Error (Там был численный прайс!)
2. Результат разведки: "Текст во второй колонке!"
Как только запрос с 'a' во второй позиции сработал, и на сайте вместо названия товара появилось слово 'a', хакер понимает: вторую колонку можно использовать для вывода паролей или секретных данных.
3. Таблица работы: Подбор типов
| Попытка | SQL-запрос (через Sprintf) | Итог (Результат) |
|---|---|---|
| 1 | ... UNION SELECT 'a', NULL, NULL-- |
🔴 Ошибка (Там был ID: INT) |
| 2 | ... UNION SELECT NULL, 'a', NULL-- |
🟢 Успех (Там было Имя: TEXT) |
| 3 | ... UNION SELECT NULL, NULL, 'a'-- |
🔴 Ошибка (Там был Прайс: NUM) |
4. Как это выглядит в Go (database/sql)
Если ваш Go-код уязвим, хакерский запрос вернет ошибку в db.Query или rows.Scan. Но хакер видит 500 ошибку в браузере — и это для него тоже ответ. Если страница загрузилась со словом 'a' — значит он нашел "текстовую дыру".
5. Особенность Go: строгая типизация через Scan
В отличие от PHP/Python, где результаты SELECT часто читаются через mixed-тип, Go-драйвер database/sql строго типизирован: каждое значение колонки попадает в Go-переменную через rows.Scan(&p.ID, &p.Name, &p.Description, &p.Price, &p.Image). Если хоть один тип в UNION-части не совпадёт с типом исходной структуры — драйвер вернёт ошибку вида:
sql: Scan error on column index 0, name "id":
converting driver.Value type string ("a") to a int: invalid syntax
Текст этой ошибки часто отображается прямо в HTML-ответе уязвимого приложения — и становится прямым подсказчиком структуры. Вместо подбора NULL-маски атакующий отправляет одинаковый строковый payload во все колонки и читает позиции, где драйвер ругается на несовместимость:
' UNION SELECT 'str','str','str','str','str' --
Каждое сообщение converting driver.Value type string to int указывает на колонку INT в исходной структуре. По итогам нескольких попыток собирается рабочий шаблон — например, INT, STRING, STRING, INT, STRING для каталога — и только потом подставляются реальные данные.
Вывод: для Go-приложений с Scan в типизированную структуру NULL-маска работает хуже, чем сравнение строкового payload с сообщениями об ошибках — это специфика Go, отсутствующая в динамически типизированных языках.
NULL — универсальная "затычка" в SQL. Она подходит к любому типу данных. Хакеру достаточно найти хотя бы одну текстовую колонку, чтобы вытащить данные всей вашей базы.
Теперь, когда структура полностью ясна, мы готовы перейти к самому интересному — извлечению реальной полезной нагрузки.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.