Посмотрели на свою админку глазами реверс-инженера: что инструмент нашёл и что пропустил

Страница входа в биллинг выглядит просто: логин, пароль, кнопка. Но браузер перед показом этой формы получает гораздо больше, чем видит человек, и получить это может любой, у кого есть адрес панели. Мы решили посмотреть, что именно там лежит, и заодно проверить новый инструмент для реверс-инжиниринга — REA.
Что такое REA и как мы его запускали
Реверс-инжиниринг — это разбор программы, у которой нет исходного кода: понять по готовому файлу, как она устроена. REA собирает для этого разные инструменты под одну команду. Он читает JavaScript сайтов и приложений, а скомпилированные программы разбирает через подключаемые движки: Ghidra, Hopper, Kuna или IDA. Им можно пользоваться из терминала или подключить к ИИ-агенту. Мы брали версию 6.8.0 из npm. Документация проекта описывает более новую ветку, так что часть ограничений из этой статьи там может быть уже снята.
Мы проверяли только свою систему и только пассивно. REA читал код уже открытой вкладки браузера: ни формы, ни кнопки он не трогал и к API сам не обращался. Браузер запускали отдельный, с пустым профилем, чтобы в анализ не попали рабочие сессии.
flowchart LR a1["Отдельный браузер<br/>с пустым профилем"] --> a2["Страница входа"] a2 --> a3["REA читает<br/>код вкладки"] a3 --> a4["Вход делает человек"] a4 --> a5["REA читает<br/>страницу после входа"] a5 --> a6["Сверка с кодом<br/>и выводы"]
Сравнили две страницы: форму входа и профиль пользователя после авторизации. Другие разделы панели в тест не вошли. Анализ занял меньше сорока секунд на страницу.
Ноль маршрутов в сводке — ожидаемый результат. Страницы панели собирает сервер, а поиск маршрутов в REA рассчитан на одностраничные приложения.
Что видно до входа
Форме входа нужны два поля, проверка и пара стилей. А браузер получает 119 скриптов: 90 файлов и 29 блоков прямо в странице. Среди них окна сделок, выбор тарифов, телефония, почта. Страница входа построена на том же общем шаблоне, что и вся панель, поэтому загружает её целиком.
В этих скриптах REA нашёл семь внутренних адресов. Два относятся ко входу по отпечатку или аппаратному ключу, и они форме нужны. Остальные пять связаны с почтой, уведомлениями, телефонией и настройками интерфейса. Само по себе это не уязвимость: адрес ещё не даёт доступа, если сервер проверяет права на каждый запрос. Но публичной странице незачем показывать эти пять адресов, а браузеру незачем разбирать около 1,6 МБ кода (до сжатия) при каждом открытии формы. Лёгкий отдельный шаблон решил бы обе задачи. Для сравнения, страница входа в личный кабинет абонента сделана именно так: 7 скриптов и 30 КБ кода против 119 скриптов и 1,6 МБ у панели.
Важная оговорка: права доступа мы в этом тесте не проверяли и ни один из найденных адресов не вызывали. Это был не аудит безопасности, а знакомство с инструментом.
Самое полезное: что инструмент пропустил
После входа скриптов стало 126, а найденных адресов — 13. Выглядит убедительно, поэтому мы сверили результат с самим кодом: взяли три скрипта, которые появляются только после авторизации. В них четыре обращения к серверу через fetch, а REA нашёл одно.
Причина оказалась простой. Вот так инструмент адрес видит (адреса в примерах упрощены):
fetch('/api/share/', { method: 'POST' })
А вот так уже нет, хотя для человека разницы никакой:
var URL = '/api/balance/';
fetch(URL, { credentials: 'same-origin' });
В одном из старых файлов нашлось ещё шесть вызовов через jQuery ($.ajax, $.get, $.getJSON), и ни один адрес оттуда в список не попал. Почему, мы не выясняли: либо инструмент не понимает jQuery, либо помешал частичный разбор этого файла, о котором ниже.
Отсюда главный вывод этого теста. Отчёт такого инструмента показывает то, что он нашёл, но не доказывает, что больше ничего нет. Список из 13 адресов выглядит законченным, а на проверенном участке инструмент увидел один адрес из четырёх.
Три файла — маленькая выборка, поэтому мы повторили разбор на всех 128 собственных скриптах панели. В графе запросов REA оказалось 90 обращений к серверу, и только в пяти адрес виден прямо. Обычный поиск по тексту тех же файлов находит 95 разных адресов. Сравнение не совсем честное: граф REA упёрся в собственный лимит в 100 000 узлов. Но сам инструмент предупреждает об этом в отчёте: то, чего он не видит, нельзя считать отсутствующим.
Для настоящей инвентаризации API надёжнее взять список маршрутов из самого приложения, а находки инструмента использовать как дополнение. В биллинге таких маршрутов больше полутора тысяч.
Находка в одну строку
Одна польза всё же обнаружилась сразу. REA пометил один из наших старых скриптов как «разобранный частично». Мы проверили: файл корректный, браузер и Node.js принимают его без ошибок. Инструмент оказался строже браузера, а споткнулся о строку вроде этой:
$.map(interfaces_list, function (interface, v) { /* ... */ });
interface — зарезервированное слово в строгом режиме JavaScript и в ES-модулях. Сегодня код работает, потому что файл подключён по-старому. Но стоит перевести его на модули или включить строгий режим, и скрипт перестанет загружаться. Формально пометка оказалась ложной тревогой, но указала на настоящее хрупкое место. Исправляется переименованием параметра. Такие места хорошо чинить заранее, а не в день большого обновления.
А если исходников нет совсем
Панель написана нами, поэтому её код и так у нас есть. Интереснее другое: REA умеет разбирать и готовые программы. Мы взяли системную утилиту hostname.exe, у которой нет ни исходников, ни имён функций, и попросили восстановить логику.
Результат совпал с реальным поведением программы: при /? или -? выводится справка, при неизвестном аргументе — ошибка, без аргументов — имя компьютера. А на одноимённой утилите для Linux два разных движка, Ghidra и Hopper, независимо указали на одну и ту же главную функцию.
Оператору связи это может пригодиться, например, чтобы понять, что делает служебная утилита оборудования без документации. Разбирать чужие программы стоит только если это разрешают лицензия и закон. Свои — пожалуйста.
Какой движок где работает
Здесь нас ждал самый практичный сюрприз: возможности инструмента сильно зависят от операционной системы.
| Движок | Windows | Linux | Что разбирает | Анализ небольшого файла |
|---|---|---|---|---|
| Ghidra | да, только PE | да | PE, ELF, Mach-O | 10–30 с |
| Kuna | нет | да | ELF, Mach-O | около 2 с |
| Hopper | нет | да, демо-режим | ELF (больше не проверяли) | около 4 с |
| IDA | не проверяли | не проверяли | — | — |
PE — это программы для Windows, ELF — для Linux, Mach-O — для macOS. Для Linux-программ на Windows нужен контейнер или отдельная машина с Linux: мы проверяли их в одноразовом контейнере. Запуск на macOS мы не проверяли.
У инструмента есть и другие слабые места. Два из пяти реальных файлов JavaScript мы не дождались: один за 80 секунд, другой за 280. Дело не в размере: файл на 647 КБ прошёл за 15 секунд, а на 425 КБ не закончился и за 80. Причину мы не выяснили. При этом ведёт себя REA аккуратно: по истечении времени отдаёт понятную ошибку и частичные данные, зависших процессов не остаётся.
При подключении к ИИ-агенту REA по умолчанию отдаёт описание 229 инструментов объёмом 3,4 МБ. Настройку лучше сразу менять: с отключёнными схемами ответов описание сжимается до 295 КБ. Сам разбор той же утилиты через агента занял около минуты и стоил 30–50 центов, результат оказался верным. Но в одном из ответов агент добавил деталь, которой в коде нет, так что его выводы тоже надо проверять.
Что мы вынесли
- Страница входа отдаёт больше, чем кажется. Полезно хотя бы раз посмотреть на неё со стороны.
- Отчёт сканера — это нижняя граница, а не полный список. Цифры стоит выборочно сверять вручную.
- Инструмент удобен для разовых разборов, особенно чужих готовых программ. Постоянно держать его подключённым к агенту незачем.
- Запускать такие инструменты лучше отдельно от рабочей среды: чистый браузер, отдельная папка, своя система как цель.
Как это работает в СмИТ Биллинге
Панель — серверное приложение: страницы собирает сервер на общем шаблоне, поэтому страница входа и получила те же скрипты, что и рабочие разделы. Адрес в коде страницы сам по себе ничего не открывает. Но проверяет ли сервер права на каждом адресе, по скриптам в браузере узнать нельзя: для этого нужны отдельный разбор серверного кода и проверка запросов. REA такой работы не делает, и его отчёт нельзя считать заключением о защищённости.
Посмотреть на своих данных
Покажем платформу на живом стенде и разберём ваш случай. Или спросите ассистента прямо сейчас — он отвечает по документации и настройкам.


