2. Фингерпринтинг СУБД
Фингерпринтинг СУБД: Определение типа базы данных
Прежде чем наносить удар, профессиональный атакующий всегда определяет тип цели. Как и языки программирования, базы данных имеют свои уникальные черты: специфичные функции, разный синтаксис конкатенации и характерные сообщения об ошибках. Этот процесс сбора информации называется фингерпринтингом.
Для Go-разработчика этот шаг неочевиден — вы импортируете _ "github.com/lib/pq" или _ "github.com/mattn/go-sqlite3" один раз в cmd/main.go и потом просто пишете db.QueryRow(...). Тип СУБД для вас деталь инфраструктуры, не часть бизнес-логики. Атакующий же без знания типа СУБД не может правильно подобрать payload: WAITFOR DELAY '0:0:5' работает только в MSSQL, SLEEP(5) — только в MySQL, pg_sleep(5) — только в PostgreSQL. Ошибиться нельзя: неправильный синтаксис вызовет ошибку без задержки, и time-based blind не сработает.
Разберемся, какие улики помогают хакеру с точностью до версии определить вашу СУБД: PostgreSQL, MySQL или SQLite. Аналогия — врач перед операцией: ему нужно знать группу крови, аллергии, рост и вес пациента; без этого даже простая инъекция может убить. Атакующий тратит первые минуты на «диагностику» и только потом подбирает «лекарство».
1. Прямой способ: Функция version()
Самый простой и надежный метод. Хакер пробует вызвать версию БД — через UNION SELECT или error-based. Если уязвимый эндпоинт возвращает данные на фронт, хакер делает ' UNION SELECT version(), NULL, NULL-- и сразу получает строку вроде PostgreSQL 15.3 on x86_64-pc-linux-gnu. Точность вплоть до patch-версии: дальше атакующий смотрит в CVE-базу — нет ли в этой версии известных RCE.
| СУБД | Функция получения версии |
|---|---|
| PostgreSQL | version() |
| MySQL | @@version или version() |
| SQLite | sqlite_version() |
| MS SQL Server | @@version |
2. Косвенный способ: Ошибки (Error-based)
Если вывод данных напрямую недоступен, хакер посылает запросы, которые вызывают ошибки. Одна и та же ошибка выглядит по-разному в зависимости от движка. Это типичная проблема Go-приложений на ранней стадии: разработчик пишет if err != nil { http.Error(w, err.Error(), 500); return } — и текст ошибки от драйвера улетает прямиком в HTTP-ответ. На staging это удобно для отладки; на production это раскрытие архитектуры базы.
- MySQL:
Table 'users' doesn't exist - PostgreSQL:
relation "users" does not exist - SQLite:
no such table: users
По тексту этих сообщений в логах или на странице приложения хакер сразу поймет архитектуру системы.
3. Физические различия (Конкатенация строк)
Символы объединения строк — отличный маркер типа СУБД. Хакер может проверить это через поисковую форму:
... WHERE name = 'a' || 'b'(Результатab?) → Это PostgreSQL/SQLite... WHERE name = CONCAT('a', 'b')(Результатab?) → Это MySQL/PostgreSQL... WHERE name = 'a' + 'b'(Результатab?) → Это MS SQL Server
4. Почему это критично для хакера
Зная тип СУБД, хакер выбирает правильный "словарь" атак:
- Для PostgreSQL будет использоваться
pg_sleep(). - Для MySQL — функция чтения файлов
LOAD_FILE(). - Для SQLite — запрос к таблице
sqlite_master.
Это экономит время и позволяет избежать лишнего шума в логах — атакующий действует максимально прицельно. Вместо тысячи разноязычных payload-ов отправляются только релевантные двести-триста — снижается шанс срабатывания WAF и алертов SIEM.
Защита для Go-разработчика на этом уровне: всегда возвращать generic-ошибки клиенту (http.Error(w, "Internal server error", 500)), а оригинальный err.Error() логировать через slog/zap во внутреннюю систему. Никогда не пробрасывать строку pq.Error в HTTP-ответ — это бесплатный fingerprint для атакующего.
Идентификация цели — это залог успеха любой операции. Зная тип базы, хакер выбирает идеальный вектор эксплуатации, не тратя силы на бесполезные запросы. Это первый шаг любой профессиональной атаки — без него ни UNION SELECT, ни time-based blind не сработают на нужной СУБД.
После того как движок определен, можно приступать к масштабной выгрузке структуры всех таблиц и колонок вашей системы. И снова: единственная фундаментальная защита — параметризация (db.QueryRow(q, args...) вместо fmt.Sprintf). При корректной параметризации фингерпринтинг через инъекцию вообще невозможен — атакующий не сможет даже понять, какая СУБД крутится за бэкендом.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.