//Кейс

Кейс: как крупный ритейлер выявил доступ к чужим заказам и риски для корпоративной видеосвязи

Пилот AI-хакера Sentra: доступ к историческим заказам без клиентской авторизации и цепочка от записи файлов до входа в видеоконференции под чужим именем.

Команда Sentra24 сентября 20265 мин чтения
Складские стеллажи сверху с освещённым центральным проходом, монохромная фотография.

Через цифровые сервисы ритейлера проходят заказы, оплаты и персональные данные покупателей. Одна ошибка в API может обернуться утечкой, мошенничеством от имени компании или сбоем в работе интернет-магазина.

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

Профиль клиента

  • Торговая сеть: более 30 магазинов, интернет-магазин, мобильное приложение.
  • География: более 20 крупных городов на территории России.
  • Количество сотрудников: более 5 000.
  • Ассортимент: более 80 тыс. товарных позиций.
  • Клиенты: более 30 тысяч покупателей ежедневно.

Масштаб пилота

Количество активов и находок изменено для анонимизации. Технические сценарии и результаты проверок сохранены.

Периметр и границы проверки согласовали заранее. Первичная инвентаризация охватила 311 активов: домены, IP-адреса, веб-приложения, мобильные приложения, сертификаты и порты.

Обзор активов

311Всего активов

Проверка шла методом «чёрного ящика» — с позиции внешнего атакующего. По итогам пилота в реестре было 147 находок, включая 5 критических и 10 высокого уровня.

Уязвимости

147Всего

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

Подтверждённые цепочки атак

Названия маршрутов API, параметров и технических полей в примерах изменены. Последовательность проверок и границы подтверждённых результатов сохранены.

1. Данные покупателей и управление их заказами

AI-хакер Sentra
Цель

Проверить доступ анонимного device-токена к чужим заказам.

Подтверждён
3 из 3 подтверждены
  1. Мобильный APIapi.example
  2. Device-токенDEVICE_CONTEXT
  3. Чужие заказыИсторический контур
  4. Операции с заказомСогласованная проверка
  1. АнализПрямой /example-api/shop/edge-b/device-session возвращает блок-страницу. Проверю нормализацию пути на соседнем маршруте: шлюз и backend могут обрабатывать его по-разному. После достижения API отдельно проверю авторизацию.

    Прямой /example-api/shop/edge-b/device-session возвращает блок-страницу. Проверю нормализацию пути на соседнем маршруте: шлюз и backend могут обрабатывать его по-разному. После достижения API отдельно проверю авторизацию.

  2. Повтор HTTP-запросаАльтернативный маршрут достигает API Завершено
    dast_replayОбезличенный фрагмент
    Вход
    GET /example-api/shop/edge-b/device-session?client_marker=<тестовый>
    Контроль:
    GET /example-api/shop/edge-a/..%2fedge-b/device-session?client_marker=<тот же>
    Результат
    Прямой путь → блок-страница
    Альтернативный → HTTP 200
    {"device_session":{"value":"[скрыт]"}}
  3. Обращение к памятиDevice-контекст и клиентская сессия — разные уровни доступа Контекст найден
    Поисковый запрос
    Мобильный API: device-session, DEVICE_CONTEXT, archived-purchase и active-purchase
    Источник · Контракт мобильного API · токен устройства и заказы

    Токен устройства выдаётся до входа покупателя. В контракте есть два маршрута информации о заказе: archived-purchase и active-purchase. Наличие device-токена не устанавливает владельца заказа; эту связь нужно проверять отдельно на каждом маршруте.

  4. Выполнение командыВ payload токена субъект DEVICE_CONTEXT Завершено
    computer_executeОбезличенный фрагмент
    Вход
    Локальный разбор payload выданного токена
    Токен и его подпись не публикуются
    Результат
    sub: "DEVICE_CONTEXT"
    Клиентский вход при выдаче не выполнялся
  5. АнализТокен получен без входа, субъект — DEVICE_CONTEXT. Это контекст устройства. Проверю archived-purchase: такой токен не должен получать заказ другого покупателя.

    Токен получен без входа, субъект — DEVICE_CONTEXT. Это контекст устройства. Проверю archived-purchase: такой токен не должен получать заказ другого покупателя.

  6. Повтор HTTP-запросаarchived-purchase возвращает чужой заказ Завершено
    dast_replayОбезличенный фрагмент
    Вход
    GET /example-api/shop/edge-a/..%2fedge-b/archived-purchase
    client_marker=<свой тестовый>
    purchase_ref=<исторический заказ>
    Authorization: Bearer [скрыт]
    Результат
    HTTP 200
    Имя, телефон, email, адрес доставки: [скрыты]
    Состав покупки, сумма, статус оплаты
  7. Повтор HTTP-запросаКонтрольные номера возвращают карточки других покупателей Завершено
    dast_replayОбезличенный фрагмент
    Вход
    Тот же анонимный device-контекст
    Изменяется только purchase_ref в историческом диапазоне
    Результат
    Получены другие исторические карточки
    Идентификаторы последовательные
    Данные покупателей и номера заказов: [скрыты]
  8. АнализМеняется purchase_ref — меняются покупатель и состав заказа, хотя device-контекст остаётся тем же. Это связывает раскрытие с отсутствием проверки владельца. Дальше отделю историческое хранилище от текущей системы.

    Меняется purchase_ref — меняются покупатель и состав заказа, хотя device-контекст остаётся тем же. Это связывает раскрытие с отсутствием проверки владельца. Дальше отделю историческое хранилище от текущей системы.

  9. АнализВ ответе полная карточка с контактами и оплатой. Проверю границу хранилища: старые записи и текущие заказы могут идти через разные API.

    В ответе полная карточка с контактами и оплатой. Проверю границу хранилища: старые записи и текущие заказы могут идти через разные API.

  10. Повтор HTTP-запросаНовая система требует клиентскую авторизацию Завершено
    dast_replayОбезличенный фрагмент
    Вход
    Сопоставление archived-purchase и active-purchase
    Тот же анонимный device-контекст
    Результат
    archived-purchase → исторические записи
    active-purchase → error: customer_login_required · требуется авторизация клиента
  11. РешениеПроверять изменение в согласованной области

    Заказчик разрешил отмену и изменение оплаты на завершённых заказах прошлых лет. Воздействие на текущие заказы новой системы не подтверждено.

  12. АнализВ контракте мобильного API есть void-purchase и payment-option. Проверю бизнес-результат на согласованном историческом заказе: HTTP 200 сам по себе недостаточен, нужно смотреть код и сообщение операции.

    В контракте мобильного API есть void-purchase и payment-option. Проверю бизнес-результат на согласованном историческом заказе: HTTP 200 сам по себе недостаточен, нужно смотреть код и сообщение операции.

  13. Повтор HTTP-запросаСервис подтвердил отмену заказа Завершено
    dast_replayОбезличенный фрагмент
    Вход
    POST /example-api/shop/edge-a/..%2fedge-b/void-purchase
    purchase_ref=<согласованный исторический заказ>
    Authorization: Bearer [скрыт]
    Результат
    HTTP 200
    {"operation_state":"cancelled","purchase_ref":"[скрыто]"}
  14. Повтор HTTP-запросаСпособ оплаты изменён Завершено
    dast_replayОбезличенный фрагмент
    Вход
    POST /example-api/shop/edge-a/..%2fedge-b/payment-option
    purchase_ref=<согласованный исторический заказ>
    payment_mode=<проверяемый способ>
    Результат
    HTTP 200
    operation_state: payment_updated
    payment_result.checkout_url: [скрыто]
  15. Исследование страницыПлатёжная страница доступна Завершено
    dast_observe_browserОбезличенный фрагмент
    Вход
    Открытие полученной платёжной ссылки
    Без выполнения оплаты
    Результат
    HTTP 200
    Действующая платёжная страница
  16. АнализЧтение и операции подтвердились в историческом контуре. В новую систему токен не прошёл. Разделю результаты в отчёте: этот сценарий не подтверждает управление текущими заказами.

    Чтение и операции подтвердились в историческом контуре. В новую систему токен не прошёл. Разделю результаты в отчёте: этот сценарий не подтверждает управление текущими заказами.

  17. НаходкаАнонимный доступ к историческим заказам

    Обход маршрута соединяется с отсутствием проверки владельца. Подтверждены раскрытие карточек и согласованные операции с историческими заказами.

Цепочка атаки
Подтверждён

Анонимный доступ к историческим заказам

Раскрытие данных покупателей и операции с чужими заказами

Бизнес-риск
80/100
Вероятность реализации
95%

Маршрут атаки

Исходный доступ
Анонимное устройство без клиентской сессии. Операции согласованы на завершённых заказах прошлых лет.
01Получение анонимного токена через альтернативный путьМобильный API Device-токенПодтверждён
Предпосылка
Шлюз и backend различаются в обработке маршрута.
Результат
Альтернативный путь достигает API выдачи маркера устройства; выдан токен устройства без входа.
Альтернативный маршрут достигает API
Обезличенный фрагмент материалов исследования
Запрос / действие
GET /example-api/shop/edge-b/device-session?client_marker=<тестовый>
Контроль:
GET /example-api/shop/edge-a/..%2fedge-b/device-session?client_marker=<тот же>
Наблюдение
Прямой путь → блок-страница
Альтернативный → HTTP 200
{"device_session":{"value":"[скрыт]"}}
Открыть в ходе работы
02Чтение чужого исторического заказаDevice-токен Чужие заказыПодтверждён
Предпосылка
Анонимный device-контекст используется при вызове archived-purchase.
Результат
Получена карточка с контактами, адресом и оплатой. active-purchase возвращает требование авторизации.
archived-purchase возвращает чужой заказ
Обезличенный фрагмент материалов исследования
Запрос / действие
GET /example-api/shop/edge-a/..%2fedge-b/archived-purchase
client_marker=<свой тестовый>
purchase_ref=<исторический заказ>
Authorization: Bearer [скрыт]
Наблюдение
HTTP 200
Имя, телефон, email, адрес доставки: [скрыты]
Состав покупки, сумма, статус оплаты
Открыть в ходе работы
Контрольные номера возвращают карточки других покупателей
Обезличенный фрагмент материалов исследования
Запрос / действие
Тот же анонимный device-контекст
Изменяется только purchase_ref в историческом диапазоне
Наблюдение
Получены другие исторические карточки
Идентификаторы последовательные
Данные покупателей и номера заказов: [скрыты]
Открыть в ходе работы
Новая система требует клиентскую авторизацию
Обезличенный фрагмент материалов исследования
Запрос / действие
Сопоставление archived-purchase и active-purchase
Тот же анонимный device-контекст
Наблюдение
archived-purchase → исторические записи
active-purchase → error: customer_login_required · требуется авторизация клиента
Открыть в ходе работы
03Отмена и изменение способа оплатыЧужие заказы Операции с заказомПодтверждён
Предпосылка
Заказчик согласовал воздействие на завершённые исторические заказы.
Результат
Сервис подтвердил отмену и изменение оплаты; получена действующая платёжная страница без выполнения оплаты.
Сервис подтвердил отмену заказа
Обезличенный фрагмент материалов исследования
Запрос / действие
POST /example-api/shop/edge-a/..%2fedge-b/void-purchase
purchase_ref=<согласованный исторический заказ>
Authorization: Bearer [скрыт]
Наблюдение
HTTP 200
{"operation_state":"cancelled","purchase_ref":"[скрыто]"}
Открыть в ходе работы
Способ оплаты изменён
Обезличенный фрагмент материалов исследования
Запрос / действие
POST /example-api/shop/edge-a/..%2fedge-b/payment-option
purchase_ref=<согласованный исторический заказ>
payment_mode=<проверяемый способ>
Наблюдение
HTTP 200
operation_state: payment_updated
payment_result.checkout_url: [скрыто]
Открыть в ходе работы
Платёжная страница доступна
Обезличенный фрагмент материалов исследования
Запрос / действие
Открытие полученной платёжной ссылки
Без выполнения оплаты
Наблюдение
HTTP 200
Действующая платёжная страница
Открыть в ходе работы

Раскрытие данных покупателей и операции с чужими заказами

Подтверждены исторические заказы и согласованные операции с ними. Текущая система требует клиентскую авторизацию.

Условие реализации

Получена чужая карточка заказа, подтверждены согласованные отмена и изменение оплаты. Текущая система active-purchase требует авторизации.

Меры защиты

Проверять владельца заказа

Проверять клиентскую авторизацию и принадлежность заказа при чтении и каждой операции.

Согласовать нормализацию маршрутов

Применять одинаковую обработку пути и правила доступа на шлюзе и в приложении.

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

Проверочные запросы вернули карточки чужих заказов: имя покупателя, адрес доставки, телефон, электронную почту, состав покупки, сумму и статус оплаты. Последовательная нумерация создавала возможность массового сбора этих данных.

С согласия заказчика на завершённых заказах прошлых лет проверили отмену и изменение способа оплаты. Сервис подтвердил обе операции и вернул действующую платёжную ссылку. Саму оплату не выполняли.

Такой доступ создавал риск утечки персональных данных и мошеннических обращений от имени магазина с деталями настоящего заказа. Цепочка затрагивала историческое хранилище. Новая система требовала клиентскую авторизацию; доступ к текущим заказам и операции с ними не подтвердились.

2. Вход в корпоративную видеосвязь под чужим именем

AI-хакер Sentra
Цель

Проверить влияние записи файлов в сервисе видеоконференций.

Подтверждён
4 из 4 подтверждены
  1. profile-storeБез сессии
  2. Запись файлаРабочая система
  3. КомандыКонтрольная копия
  4. Ключ подписиКонтрольная копия
  5. Вход по токенуКонтрольная копия
  1. АнализУ /example-api/meeting/profile-store нет проверки сессии. Поле пользователя участвует в пути записи. Проверю выход за каталог и формат полученного файла — произвольная запись ещё не доказывает исполнение.

    У /example-api/meeting/profile-store нет проверки сессии. Поле пользователя участвует в пути записи. Проверю выход за каталог и формат полученного файла — произвольная запись ещё не доказывает исполнение.

  2. Повтор HTTP-запросаОбработчик принимает запрос без сессии Завершено
    dast_replayОбезличенный фрагмент
    Вход
    POST /example-api/meeting/profile-store
    Контрольный маркер, без авторизации
    Результат
    HTTP 200
    Ответ: ok
  3. Повтор HTTP-запросаОракул различает файл и отсутствующий путь Завершено
    dast_replayОбезличенный фрагмент
    Вход
    Контроль пути вне каталога данных
    Сопоставление отсутствующего пути и файла-маркера
    Результат
    Отсутствующий путь → Errno 2: No such file
    Файл + <контрольный дочерний сегмент> → Errno 20: Not a directory
  4. Обращение к памятиФормат записи определяет возможный триггер Контекст найден
    Поисковый запрос
    profile-store: сериализация файла, Python .pth/sitecustomize, условия исполнения
    Источник · Заметки по обработчику · формат записи и отвергнутые ветки

    Обработчик сериализует содержимое, поэтому запись по исполняемому пути не равна исполнению. Для Python .pth важен исполняемый import в начале строки; отдельный строковый литерал в sitecustomize не выполняет вложенный текст.

  5. АнализENOTDIR показывает файл по целевому пути. Но обработчик сериализует содержимое: неподходящий формат останется строкой. Полную эскалацию продолжу в контрольной копии. В live-результате пока подтверждена запись.

    ENOTDIR показывает файл по целевому пути. Но обработчик сериализует содержимое: неподходящий формат останется строкой. Полную эскалацию продолжу в контрольной копии. В live-результате пока подтверждена запись.

  6. РешениеПеренести дальнейшую цепочку в контрольную копию

    В копии проверяются формат записи, триггер исполнения, права контейнера и принятие токена. Рабочая система и копия фиксируются отдельно.

  7. Выполнение командыФормат записи воспроизведён локально Завершено
    computer_executeОбезличенный фрагмент
    Вход
    Контрольная копия обработчика
    Сопоставление входного значения и полученного файла
    Результат
    Сериализованный формат воспроизведён
    Кавычки влияют на интерпретацию содержимого
  8. Выполнение командыPython-ветка не даёт автоматического исполнения Завершено
    computer_executeОбезличенный фрагмент
    Вход
    Контрольная копия: сопоставление формата с .pth и sitecustomize
    Без проверки этой ветки на рабочей системе
    Результат
    .pth: нужный исполняемый import не получается
    sitecustomize: самостоятельный строковый литерал
    Автоматическое исполнение этой веткой не подтверждается
  9. АнализPython-ветку отбрасываю: путь подходит, но формат записи не создаёт исполняемый код. Для оставшейся цепочки нужен отдельный триггер. Его проверю в копии и зафиксирую, при каком действии появляется результат.

    Python-ветку отбрасываю: путь подходит, но формат записи не создаёт исполняемый код. Для оставшейся цепочки нужен отдельный триггер. Его проверю в копии и зафиксирую, при каком действии появляется результат.

  10. Выполнение командыТриггер в копии приводит к выполнению команды Завершено
    computer_executeОбезличенный фрагмент
    Вход
    Контрольная среда:
    запись → согласованный триггер → проверка контрольного маркера
    Результат
    Контрольный маркер появился после триггера
    Права: администратор контейнера
    Самопроизвольное исполнение на рабочей системе не заявляется
  11. АнализВ копии получено выполнение команд с правами администратора контейнера. Проверю, доступен ли из этого контекста ключ, которым сервис подписывает токены конференций.

    В копии получено выполнение команд с правами администратора контейнера. Проверю, доступен ли из этого контекста ключ, которым сервис подписывает токены конференций.

  12. Выполнение командыКлюч подписи доступен в контрольной среде Завершено
    computer_executeОбезличенный фрагмент
    Вход
    Проверка конфигурации и механизма подписи
    Среда: контрольная копия
    Результат
    Ключ подписи: [скрыт]
    Контекст: администратор контейнера
  13. АнализКорректная подпись ещё не означает вход. Проверю токен с выбранной личностью на компонентах конференций в той же копии. Ключ и токен не публикую.

    Корректная подпись ещё не означает вход. Проверю токен с выбранной личностью на компонентах конференций в той же копии. Ключ и токен не публикую.

  14. Выполнение командыКомпоненты копии приняли поддельный токен Завершено
    computer_executeОбезличенный фрагмент
    Вход
    Контрольная копия:
    создание токена → проверка доступа к конференции
    Результат
    Подпись принята
    Доступ от имени выбранного сотрудника подтверждён
  15. НаходкаЦепочка до входа под чужой личностью

    На рабочей системе подтверждена произвольная запись. Полная цепочка от команд до принятия поддельного токена воспроизведена в контрольной копии.

Цепочка атаки
Подтверждён

Запись файлов → ключ подписи конференций

Вход в конференции под выбранной личностью

Бизнес-риск
80/100
Вероятность реализации
90%

Маршрут атаки

Исходный доступ
Посетитель без сессии. Дальнейшая эскалация исследована в контрольной копии сервиса.
01Запись вне каталога данныхprofile-store Запись файлаПодтверждён
Среда проверки
Рабочая система
Предпосылка
Поле пользователя влияет на путь записи; проверка сессии отсутствует.
Результат
Файл по целевому пути подтверждён дифференциалом Errno 2 / ENOTDIR.
Обработчик принимает запрос без сессии
Обезличенный фрагмент материалов исследования
Запрос / действие
POST /example-api/meeting/profile-store
Контрольный маркер, без авторизации
Наблюдение
HTTP 200
Ответ: ok
Открыть в ходе работы
Оракул различает файл и отсутствующий путь
Обезличенный фрагмент материалов исследования
Запрос / действие
Контроль пути вне каталога данных
Сопоставление отсутствующего пути и файла-маркера
Наблюдение
Отсутствующий путь → Errno 2: No such file
Файл + <контрольный дочерний сегмент> → Errno 20: Not a directory
Открыть в ходе работы
02Выполнение команд из записанного файлаЗапись файла КомандыПодтверждён
Среда проверки
Контрольная копия
Предпосылка
В копии воспроизведены сериализация содержимого и условия исполнения.
Результат
В контрольной среде получены команды с правами администратора контейнера. Рабочая система не эксплуатировалась на этом этапе.
Формат записи воспроизведён локально
Обезличенный фрагмент материалов исследования
Запрос / действие
Контрольная копия обработчика
Сопоставление входного значения и полученного файла
Наблюдение
Сериализованный формат воспроизведён
Кавычки влияют на интерпретацию содержимого
Открыть в ходе работы
Триггер в копии приводит к выполнению команды
Обезличенный фрагмент материалов исследования
Запрос / действие
Контрольная среда:
запись → согласованный триггер → проверка контрольного маркера
Наблюдение
Контрольный маркер появился после триггера
Права: администратор контейнера
Самопроизвольное исполнение на рабочей системе не заявляется
Открыть в ходе работы
03Доступ к ключу подписиКоманды Ключ подписиПодтверждён
Среда проверки
Контрольная копия
Предпосылка
Контекст администратора контейнера доступен в копии.
Результат
В конфигурации контрольной среды доступен ключ подписи токенов конференций.
Ключ подписи доступен в контрольной среде
Обезличенный фрагмент материалов исследования
Запрос / действие
Проверка конфигурации и механизма подписи
Среда: контрольная копия
Наблюдение
Ключ подписи: [скрыт]
Контекст: администратор контейнера
Открыть в ходе работы
04Принятие токена с выбранной личностьюКлюч подписи Вход по токенуПодтверждён
Среда проверки
Контрольная копия
Предпосылка
Получен ключ подписи в контрольной среде.
Результат
Компоненты копии приняли токен. Аналогичное воздействие на рабочей системе не выполнялось.
Компоненты копии приняли поддельный токен
Обезличенный фрагмент материалов исследования
Запрос / действие
Контрольная копия:
создание токена → проверка доступа к конференции
Наблюдение
Подпись принята
Доступ от имени выбранного сотрудника подтверждён
Открыть в ходе работы

Вход в конференции под выбранной личностью

Рабочая система: произвольная запись. Контрольная копия: команды, ключ подписи и принятие токена.

Условие реализации

На рабочей системе подтверждена запись файла. Команды, доступ к ключу и принятие токена подтверждены только в контрольной копии.

Меры защиты

Ограничить путь и формат записи

Добавить авторизацию и проверять канонический путь записи внутри разрешённого каталога.

Изолировать ключ подписи

Ограничить права контейнера и доступ к ключу; заменить ключ при подтверждённом раскрытии.

В сервисе видеоконференций обнаружили обработчик без проверки авторизации. Через него можно было создавать и перезаписывать файлы за пределами каталога пользовательских данных. Произвольную запись файлов подтвердили на рабочей системе.

Дальнейшие шаги воспроизвели в контрольной копии среды: запись файла и отдельный триггер приводили к выполнению команд с правами администратора контейнера. Из этого контекста был доступен ключ подписи токенов конференций.

С полученным ключом создали токен от имени выбранного сотрудника. Компоненты видеосвязи в контрольной копии приняли его и предоставили доступ к конференции. Полная цепочка была подтверждена в копии; на рабочей системе проверку ограничили записью файлов.

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

Чем закончился пилот

Ритейлер получил технический отчёт с оценкой критичности уязвимостей, доказательствами, шагами воспроизведения и разбором цепочек атак. Рекомендации разделили на первоочередные и дополнительные. Sentra автоматически определила приоритеты устранения с учётом подтверждённых сценариев эксплуатации и риска для бизнеса.

Исправления начались ещё во время пилота. Повторная проверка подтвердила закрытие уязвимости в конфигураторе. Непрерывный контроль также обнаружил регрессию: вернулась ранее устранённая проблема, позволявшая определить наличие клиента по номеру телефона.

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

Пилот

Проверьте работу AI-хакера на своей инфраструктуре — бесплатно

Запросить пилот
Запросить пилот contact@sentra-tech.ru