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



Сейчас хочется поговорить о том, откуда эта информация берется, на примере конкретного случая с известным российским банком. Чтобы никого не обидеть (а банки очень обидчивы и любят публично поистерить силами своих пиар-отделов, все отрицая в стиле «вы все врете» и «на нас осуществляют информационную атаку»), назову данный банк условно «Эпсилон».


Мне на анализ попало два весьма интересных PHP-приложения, случайно оказавшихся в открытом доступе на одном из серверов в Нидерландах. Но обо всем по порядку…


На почту моего Telegram-канала «Утечки информации» пришло письмо от исследователя безопасности Alex Gor (в твиттере — 0xyzq). Письмо содержало скриншот (см. выше) и архив с тем, что собственно и представляет интерес.


В процессе «охоты» на открытые директории (например, «80.http.get.title:"index of /"») с использованием поисковика Censys.io исследователем был найден некий сервер с адресом 95.179.156.7, на котором весьма удачно, в свободном доступе, расположились некие файлы (.php, .html, .txt и даже один .zip). По данным поисковика Shodan, открытый 80-й порт на этом сервере впервые «засветился» 23.12.2019, а по данным другого поисковика – BinaryEdge, последний раз открытую директорию там «видели» 09.02.2020.



Тут примечательно имя архива – букву «A» в имени читатели могу попробовать расшифровать сами, буква «P» — от слова «Parse», а вот «v22» явно указывает на версию парсера – 22. Это может говорить о том, что были и другие младшие версии (и скорее всего будут и старшие).


Внутри архива два файла:


  • parse.php – дата последней модификации 31.12.2019, размер 11 757 байт
  • next.php – дата последней модификации 24.12.2019, размер 6 678 байт

Чтобы драматически не увеличивать размер статьи, скажу сразу, что оба PHP-приложения обращаются к официальному REST API банка и, «притворяясь» официальным мобильным приложением, пытаются получить от сервера банка некие данные (см. ниже), перебирая входные параметры. REST API банка получают на входе HTTP-запрос, и в ответ выдают данные в формате JSON. Налицо весьма стандартное решение, специалисты «в теме» без труда догадаются, кто и с какими целями его использует.


1. Приложение parse.php принимает на вход (через HTML-форму) три параметра: «prefix», «from», «to».




Затем оно в цикле формирует из них входной параметр $reference для функции REST API (путем инкремента в заданном диапазоне), засылает запросы на сервер банка под видом iOS-приложения и проверяет есть ли в ответе сервера нужное поле, и, если есть, то записывает ответ с json-данными сервера в файл с именем «result_префикс диапазона.txt» (см. ниже).


Параметр $reference представляет собой конкатенацию некоего id (type), далее следует дата (в формате ddmmyy), и затем номер операции, дополненный до 7 знаков. Например:


H03 111119 0000001


Здесь H03 – id, а 111119 – дата (11.11.2019). Эти две части не меняются от запроса к запросу. 0000001 – это номер операции в виде инкрементирующегося счетчика. Его очень удобно перебирать от 0000000 до 9999999, и это именно то, что делают парсеры.


Ниже приведен кусок функции request() из parse.php, которая для очередного $reference отсылает запрос серверу банка, и сохраняет ответ в файл (обработка ответа и сохранение в файл для краткости не показана):



Можно заметить, что код снабжен комментариями. Кроме того, парсер поддерживает работу через прокси.


2. Приложение next.php ничем принципиально не отличается и делает примерно тоже, что и первый парсер, но через вызов другой функции REST API: принимает на вход (через HTML-форму) многострочный параметр «AAAAAA».




Затем данный парсер формирует из каждой строки входной параметр $reference для REST API, засылает для каждой строки запрос на сервер банка и, в случае успешного завершения вызова функции, записывает ответ сервера в файл с именем «result_next_строка из AAAAAA.txt» (см. ниже).


Если проанализировать результат работы (см. ниже) этого парсера, то можно заметить, что $reference представляет собой конкатенацию некоего префикса p, далее следует дата (в формате ddmmyy). Например:


p151119


Здесь p – префикс, а 151119 – дата (15.11.2019).



Теперь самое интересное – собственно, что за данные получают эти PHP-приложения от сервера банка и что они записывают в текстовые файлы.


Как я уже отмечал выше, владельцы «нидерландского» сервера оставили в открытом доступе не только исходные коды PHP-приложений, но и текстовые файлы (результаты работы парсеров), заботливо разложив их по директориям «parse» и «next» в поддиректориях «files».



Результат работы первого парсера (parse.php) содержит номер счета отправителя, номер банковской карты получателя и срок ее действия, валюту и тип счета.



Всего 30 файлов, суммарно во всех 133 728 строк (выше показана одна строка).


Результат работы второго парсера (next.php) содержит ФИО, пол, номер мобильного телефона, адрес электронной почты, место работы (название и ИНН), а также потенциально возможно присутствие и других данных (паспорт, данные по кредитам и зарплате, кодовое слово, наличие загранпаспорта и ДМС и т.п.).



Всего 21 файл, суммарно во всех 113 442 строки (выше показана одна строка).


Являются ли все строки валидными и сколько среди них уникальных данных, я не проверял.


По датам последней модификации файлов можно сказать, что оба парсера работали с 29.12.2019 по 04.01.2020, без перерыва на новогодние праздники.


Поскольку все эти сотни тысяч строк, содержащие персональные и банковские данные клиентов лежали в открытом доступе, мы можем говорить о факте «двойной утечки». Получается весьма «забавная» картина – сначала злоумышленники похитили данные у банка, затем сами допустили утечку и этих данных и инструментов для их получения.


Разумеется, я незамедлительно уведомил банк и ЦБ в лице ФинЦЕРТ. Банк, как ни странно, особого интереса к файлам не проявил и архив не запросил. ФинЦЕРТ – наоборот, запросил и получил все файлы, что описаны выше.


Еще стоит отметить, что вызовы REST API, используемые описанными выше парсерами, вот так впрямую не работают — сервер банка возвращает 404-ю ошибку. Тут возможно несколько вариантов: либо банк, обнаружив подозрительную активность в начале года убрал вызовы этих функций, либо исходники парсеров не содержат важной части – кода авторизации “Authorization: Bearer“ в HTTP-заголовке (переменные авторизации в коде инициализируются пустой строкой). Этот код авторизации может, например, доставаться злоумышленником в ходе анализа реального трафика общения мобильного приложения банка с сервером. Либо есть какие-то тонкости в составлении HTTP-запросов к серверу в плане наличия определенных заголовков в запросе, которые мы по понятным причинам не можем детально воспроизвести в полевых условиях без доступа к мобильному приложению. Поэтому пришлось ограничиться анализом исходных кодов PHP-приложений и результатов их работы.


О том, как данные, добытые в том числе и подобным образом, потом используют злоумышленники, уже многократно освещалось и рассказывалось в СМИ. И я удивлюсь, если среди читателей этой статьи не найдется тех, кому не звонили из «службы безопасности» банка.


Новости про утечки информации и инсайдеров всегда можно найти на Telegram-канале «Утечки информации».