Дешевые авиабилеты… Сеть мошеннических сайтов, ворующих деньги с карт. Второе расследование. При чём тут Промсвязьбанк?

Пользователь форума Geektimes.ru под ником Алексей около месяца назад опубликовал на Geektimes статью «Дешевые авиабилеты… Или сеть мошеннических сайтов, ворующих деньги с карт. Мое расследование.» Публикация получила большой отклик и неожиданное продолжение…

Напомню для тех, кто первую часть не читал. В публикации на основе реальных случаев были описаны схемы, с помощью которых мошенники воруют деньги с карт покупателей авиабилетов, которые имели неосторожность попасть на поддельный сайт по продаже билетов. Количество таких мошеннических сайтов по продаже авиабилетов в рунете исчисляется десятками и сотнями (с учетом закрытых). На таких сайтах пользователю сначала показывается реальная информация об авиарейсах, предлагается оформить заказ и оплатить его банковской картой. Всё выглядит красиво, пока покупатели авиабилетов не обнаруживают, что остались и без денег, и без билетов.

Во всех обнаруженных случаях для кражи денег такие сайты используют сервисы банков для перевода денег с карты на карту (P2P). В первой части был подробно разобран механизм того, как страница Банка Тинькова для оплаты с карты на карту маскируется и встраивается на мошеннические сайты, так, чтобы «покупатель» ничего не заметил. Также упоминался Промсвязьбанк, — именно через него были украдены деньги с карты потерпевшего в истории, которая была описана. И если с банком ТКС вопросов не осталось, то в случае с Промсвязьбанком было непонятно, как именно выводятся деньги. Основной скрипт, служащий для воровства денег, выполнялся на стороне сервера и без исходных кодов можно было только стоить предположения, что именно он делает.

И вот один из пользователей Geektimes связался со мной и прислал тот самый скрипт payp2p.php, который использовался в последнее время на большой части мошеннических сайтов по продаже авиабилетов. Скрипт этот использует сервис Промсвязьбанка для перевода с карты на карту. И на мой взгляд, Промсвязьбанк, предоставляя свой сервис, который было легко обмануть, способствовал росту количества интернет-мошенников.

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

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

Так выглядела страница оплаты на мошеннических сайтах
При анализе HTML кода этой страницы оплаты я не обнаружил, никаких частей страниц каких-либо банков, не используются встраиваемые окна iframe, вообще не используются скрипты, а сама страница очень простая и не похожа на страницу Промсвязьбанка. Данные введенные в форму проверяются не скриптами, а встроенными в браузеры механизмами, — с помощью атрибутов «pattern» и «required» для полей ввода input и для раскрывающихся списков select. Т.е. даже страница, сохраненная в браузере на локальный диск, потом остается «работоспособной» и может использоваться для тестирования того, как перехватываются данные карты. Подобная сохраненная ранее страница и была использована в рамках этой публикации для того, чтобы понять как работает скрипт.

По сути это страница представляет собой только форму для ввода номера карты. При подтверждении формы обработка передается программе payp2p.php.
 

<form class="b-card-feature-list clearfix" id="formPay" action="payp2p.php" method="post">

Программа payp2p.php может делать что угодно. Код ее нам ранее был недоступен, поскольку он выполняется на стороне сервера. Но как я уже писал, теперь у нас появился код, и мы узнаем всё.

Теперь посмотрим, как выглядит страница оплаты с карты на карту на сайте Промсвязьбанка.

https://www.psbank.ru/Personal/eCommerce/Card2Card

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

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

<iframe name="card2card" src="https://3ds.payment.ru/P2P/card_form.html" height="100%" width="100%" frameborder="no" seamless scrolling="no">
</iframe>

Этот кусок означает, что реальная страница оплаты расположена на другом домене, а то, что мы видим на сайте Промсвязьбанка отображается в «окне» с помощью технологии iframe.
 

Интересно, а кому принадлежит домен 3ds.payment.ru?

Домен 3ds.payment.ru тоже принадлежит Промсвязьбанку. Этот домен мы запомним, он нам еще встретится в описании и не раз.

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

https://3ds.payment.ru/P2P/card_form.html

Это реальная страница, которая используется для переводов с карты на карту. Как видим, эта страница без полей. Это сделано специально, чтобы ее было удобнее выстраивать в другие сайты.

В HTML коде этой страницы нам интересна вот эта часть:

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

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

Скрипт простой и для его понимания не требуется каких-то глубинных знаний языка программирования PHP. Для удобства разбора я разбил его на части. Слева указываются номера строк, на которые можно ссылаться. Скрипт приводится полностью без изменений в том виде, в котором был получен. После каждого куска кода будет представлена расшифровка и пример значений переменных во время исполнения программы (т.е. что-то похожее на отладку). В некоторых местах возможно избыточное комментирование, — это сделано для того, чтобы читатели, не связанные с программированием, тоже могли понять смысл программного кода.

Для тестирования нам понадобится форма, в которую нужно будет ввести данные карты, с которой предполагается оплата. Воспользуемся сохраненной ранее формой. Как выглядела форма на мошенническом сайте показано в картинке в начале статьи. Про форму будет еще дополнительно написано ниже. Для тестирования введем номер карты 1111.2222.3333.4444.

Начнем.

Строка 3 — никакие команды не выполняет.
Строка 4 — Подгружается отдельный файл dbconfig.php в котором хранятся параметры для подключения к базе данных MySQL. Скриншот кода dbconfig.php и его разбор есть ниже.
Строка 6 — подключаемся к серверу MySQL, в базе которого потом будем хранить данные об украденных картах и о проведенных денежных переводах. В этой строке одновременно происходит подключение к серверу MySQL и выход из программы, если подключение по какой-то причине не удалось.
Строка 11 — выбираем кодировку для работы с базой MуSQL.
Строка 13 — К серверу MySQL мы подключились ранее, теперь выбираем базу данных, с которой будем работать.

Скрипт payp2p.php начинает свою работу после того, как обманутый пользователь на странице похожей на обычную страницу онлайн-оплаты заполняет форму. По нажатию на форме кнопки «Оплатить», скрипт payp2p.php получает данные введенные в форме. Данные из формы в скрипт передаются методом POST.

Строка 16 — в переменную $num сохраняется номер кредитной карты, введенный в форме на предыдущей странице.
Строка 17 — в переменную $date сохраняется Месяц / Год срока действия карты.
Строка 18 — в переменную $cvv сохраняется CVV код карты.
Строка 19 — в переменную $code сохраняется некий сформированный ранее при оформлении «заказа на авиабилеты» код. Этот код используется для того, чтобы пользователь мог просмотреть свой заказ по специальной ссылке. Этот же код используется для идентификации заказа (на странице оплаты, чтобы автоматически выводить сумму для оплаты; при сохранении в «книгу продаж» которую ведут мошенники; также этот код передается в платежную форму, вероятно, как идентификатор перевода (об этом ниже).
Строки 21-22 Формируется строка — SQL запрос, который затем выполняется. SQL запрос добавляет в таблицу 'card' значения идентификатора заказа, суммы, срока действия карты, CVV кода карты, и точное текущее время. Пример записи в БД есть ниже.
 

Пример отладочной информации

Временно переключим свое внимание временно на файл dbconfig.php.

Здесь задаются параметры подключения к БД. Из того, что может быть интересно:
 

DBHOST — имя хоста, на котором запущен MySQL сервера (в данном примере база MySQL находится на том же сервере, на котором хранятся исполняемые файлы, но теоретически может быть на стороннем сервере)
DBNAME — Имя Базы Данных
DBUSER — Имя пользователя для подключения к Базе Данных MySQL
DBPASS — Пароль для подключения к Базе Данных MySQL
SECURE_AUTH_KEY — секретный ключ для подключения к чему-то без использования паролей. Для чего именно использовался этот ключ, из тех файлов, что были в наличии, непонятно. Код ключа на скриншоте изменен.

Строка 28 — подключается сторонний файл aviacfg.php. Это конфигурационный файл, в котором хранятся номера карт получателей и другие настройки.
Строка 29 — Из номеров карт, которые в конфигурационном файле разделяются символом переноса строки, создается массив.
Строка 30-31 — Переменной $crd случайным образом присваивается номер одной из карт.

Посмотрим, что у нас в файле aviacfg.php

Здесь мы видим, что переменная $aviacfg — это массив, который содержит значения discount (скидка), и cards (номера карт, на которые предполагается вывод средств). В этом примере только один номер карты, но их может быть любое количество. Само название файла (aviacfg.php) и переменной ($aviacfg) указывает, для какой области был заточен этот скрипт. Значение discount (скидка) определяет на какой процент цены на мошенническом сайте будут указываться дешевле, чем они на самом деле продаются на «честном» сайте по продаже авиабилетов. Владелец мошеннического сайта может быстро сделать отображаемую цену билетов дешевле. Чем ниже будет отображаемая цена, тем больше вероятность, что кто-то из потенциальных покупателей рискнет купить билеты на незнакомом сайте. Про скидку будет еще позже комментарий, как именно она реализована в коде.

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

Пример отладочной информации

Строка 40 — переменной $p112 присваивается значение с номером карты, который был введен ранее в форме.
Строки 41-51 — Номер карты разбивается на части по четыре цифры.
Строки 53-57 — Проверяется длина номера карты. Если в номере карты число знаков отличается от 16 или 18, то происходит выход. Пять секунд отображается сообщение, затем происходит переадресация на другую страницу. В данном примере возврат будет на страницу с заказом на мошенническом сайте.
В строке 56 «Iaaa?iua aaiiua ea?ou» при конвертации кодировки ISO8859-1 =>Windows-1251 соответствует тексту: «Неверные данные карты».
Строки 58-61 — переменным $p4, $p5, $p6, $p11 присваиваются значения, введенные ранее в форме (срок действия карты, код CVV, сумма оплаты).
Строка 63 — В переменной $info сохраняются все данные карты и сумма перевода. При формировании используются переносы строк "\n" и разделители "###...". Эта переменная нигде не в дальнейшем не используется. При доработке скрипта, её можно использовать для сохранения записей в обычный текстовый файл или для вывода на экран при отладке.
 

Пример отладочной информации

Строки 66-75 — Это фактически дублирование блока строк 27-36. Еще раз выбирается случайным образом карта получателя из конфигурационного файла aviacfg.php, и все это сохраняется в таблицу базы данных card_balance. Таким образом в таблице card_balance при каждой попытке перевода будет создаваться по две записи. Если в aviacfg.php забита только одна карта получателя, при случайной выборке, естественно, всегда будет выбираться одна и та же карта. В этом случае в таблице card_balance записи будут просто дублироваться. Но в случае, если в aviacfg.php забиты несколько номеров карт, при случайной выборке результаты будут разные и в таблице card_balance будет одна запись, первая, неправильная, а вторая правильная.

Это ошибка, и покупатели скрипта (о них будет отдельный комментарий) могут обратиться к разработчику с просьбой компенсировать моральный ущерб, связанный с тем, что реальных переводов минимум в два раза меньше, чем записей в логе.
 

Пример отладочной информации

 

Пример записей в базе данных MySQL

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

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

Вторая часть скрипта, относится к переводу денег через сайт Промсвязьбанка 3ds.payment.ru.

В строке 78 в комментарии указывается, что, предполагается, что страница подтверждения успешной оплаты имеет адрес типа "/sus.php?cd=BX3FKT". На такой адрес в случае успеха должен быть возвращен пользователь.

Строка 80-91 Для того, чтобы провести перевод нужно сначала зайти на служебную страницу.

https://3ds.payment.ru/cgi-bin/get_trans_cond_p2p.

На этой странице выдается примерно вот такая строка:
 

{"ORDER_NUM":"20161027070425023400","TIMESTAMP":"20161027070425"}

«ORDER_NUM» — это ~«Номер заказа», «TIMESTAMP» — это метка текущего времени. Если страницу обновить, то всегда выдаются новые данные.

Для того, чтобы прочитать какую-то веб-страницу или отправить данные на веб-страницу используется команда curl. Curl (cURL) позволяет программно подключаться к веб-серверам по различным протоколам, в том числе и по http и https. В нашем случае curl это программный веб-браузер, который может сохранять веб-страницы в переменные. Сохраненная в переменной страница представляет собой очень длинную строку с исходным HTML кодом этой страницы. С такими строковыми переменной можно работать точно так же, как и с любыми строками — можно искать текст, заменять текст итп. Curl в описываемых скриптах будет использоваться несколько раз.

Строка 80 — В переменной $login_url сохраняется URL адрес.
Строка 81 — В переменной $agent сохраняется URL адрес.
Строка 82 — Инициализирует сеанс cURL.
Строка 83-90 — Устанавливаются параметры для сеанса сURL (адрес страницы, сохраненный ранее в $login_url; идентификатор браузера, сохраненный ранее в $agent; страница, с которой происходит переход или по-другому ссылающаяся страница REFERER; настройки COOKIE итп)
Строка 91 — В результате выполнения команды curl_exec программно будет получена веб-страница, которая будет сохранена в переменную $page.
Строки 93-95 В сохраненной веб-странице $page находится ~«номер заказа» ORDER_NUM, который сохраняется в переменной $ord.
Строки 96-98 В сохраненной веб-странице $page находится метка времени TIMESTAMP, которая сохраняется в переменной $tim.
 

Пример отладочной информации

Теперь «программным браузером» нужно зайти на страницу https://3ds.payment.ru/P2P_ACTION/card_form.html. Эта та самая страница оплаты, скриншот которой был показан выше. Это страница с формой, часть служебных полей которой скрыта. Часть HTML кода со скрытыми полями ввода была показана выше. Некоторые значения этих скрытых полей нужно запомнить, чтобы в дальнейшем их использовать при отправке формы.

Строка 99 — В переменную $url сохраняем адрес страницы.
Строка 100 — Устанавливаются параметры для сеанса сURL (в данном случае только адрес страницы. Остальные настройки остаются прежние).
Строки 101-102 Удаляются ранее использовавшиеся переменные $page и $part.
Строка 103 — В результате выполнения команды curl_exec программно будет получена веб-страница, которая будет сохранена в переменную $page.
Строки 104-106 В сохраненной веб-странице $page находится значение поля TERMINAL, которое сохраняется в переменной $term.
Строки 107-109 В сохраненной веб-странице $page находится значение поля TRTYPE, которое сохраняется в переменной $type.
Строки 110-112 В сохраненной веб-странице $page находится значение поля MERCHANT, которое сохраняется в переменной $merch.
Строки 113-115 В сохраненной веб-странице $page находится значение поля EMAIL, которое сохраняется в переменной $ml.

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

Описание некоторых полей. Полное описание всех полей легко найти в гугле.
 

TERMINAL — Уникальный номер виртуального терминала торговой точки
MERCH_NAME — Название Торговой точки
MERCHANT — Номер торговой точки, присвоенный банком
TRTYPE — Тип запрашиваемой операции (Оплата – 1, Отмена – 22, Предавторизация – 0, Завершение расчетов — 21)
EMAIL — E-mail адрес для отправки оповещений

 

Пример отладочной информации

EMAIL здесь, это эпичный случай. Кому интересно, дополнительные материалы про этот EMAIL в конце статьи в приложении под спойлером.

Здесь мы видим большой блок. То, что он выглядит большим объясняется ограниченной шириной колонки в публикации и удобным представлением кода автором скрипта. Все тоже самое можно было бы разместить в 10 строчках кода, но удобство чтения и правки кода при этом пострадали бы.

Строка 120 — В переменную $url сохраняем адрес страницы.
Строка 121-123 — Устанавливаются параметры для сеанса сURL.
Строка 124 — из номера карты получателя в строковой переменной $crd создаётся массив $ncrd, который будет содержать части номера карты, разбитые по четвёркам.
Строка 125 — в переменную-массив $headers сохраняются HTTP-заголовки.
Строка 126 — Устанавливаются параметры для сеанса сURL (HTTP-заголовки из переменной $headers.
Строки 135-164 — Создается массив $postL, каждое значение которого будет соответствовать полю формы на странице оплаты (номер карты отправителя, разбитый по четвёркам; срок действия карты отправителя; CVC карты отправителя; номер карты получателя, разбитый по четвёркам; срок действия карты получателя; CVC карты получателя; сумма оплаты; «номер заказа»; описание для страницы подтверждения; номер терминала; название торговой точки; email для уведомлений; метка времени; неразбитый на части номер карты отправителя; неразбитый на части номер карты получателя; данные о софте и железе «на компьютере отправителя», призванные создать видимость реального пользователя, а не скрипта).
Строки 135 — Устанавливаются параметры для сеанса сURL (данные, передаваемые в HTTP POST-запросе. При этом массив $postL преобразуется в строку, которая представляет собой url-закодированную строку, наподобие 'p1=val1&p2=val2&...'.

Более наглядно передаваемые данные показаны на скриншоте с отладочной информацией ниже.
 

Пример отладочной информации

Строка 166 — В результате выполнения команды curl_exec программно методом POST будут отправлены подготовленные данные в форму веб-страницы. Для веб-страницы такая отправка будет выглядеть точно так же, как, если бы обычный пользователь заполнил и подтвердил форму в обычном браузере. Страница с результатом отправки данных в форму будут сохранена в переменную $page.
Строка 167 — Завершается сеанс cURL.
Строка 168 — В полученной странице, которая хранится в переменной $page, и как мы помним, представляет из себя длинную строку, ищется подстрока «Error».
Строки 169-173 — Если подстрока «Error» найдена, то 5 секунд отображается сообщение об ошибке «Карта не подходит» и затем производится выход из скрипта с переадресацией отображаемой в браузере страницы на «страницу с заказом». Если пользователь проявит упорство, то он может еще раз попробовать пройти процедуру оплаты.

Отображаемая страница в случае любой ошибки.

Причины ошибок, которые выдает банк, могут быть разные (ошибка в номере карты, недостаточно средств, ошибка авторизации и много других). Но для скрипта payp2p.php разницы нет. Раз оплата не прошла, значит пользователя переадресовывают на страницу, с которой можно повторить попытку оплаты. Страница, на которую производится возврат при ошибке, может быть легко изменена в зависимости от поставленной задачи.
 

Пример HTML кода возвращаемой банком страницы, в случае ошибки

 

Пример отладочной информации в случае, если банк при оплате сообщает об ошибке

Строка 174 — Если ранее выхода из скрипта из-за ошибки при оплате не произошло, это означает, что все идет, как задумано. В ранее сохраненной в переменной $page странице производится замена всех подстрок с адресом https://3ds.payment.ru/cgi-bin/cgi_link на строку с адресом типа mydomain.ru/sus.php?cd=… — это адрес страницы на мошенническом сайте, на которую пользователь должен попасть в случае успешной оплаты. (На такой странице пользователя можно будет поблагодарить и сообщить ему, что электронные билеты высланы на почту). После замены подстроки результат сохраняется в переменной $pp.

Строка 175 — Переменная $pp выводится на экран в браузере. Поскольку переменная $pp — это строка с полным HTML кодом страницы, пользователь увидит какую-то страницу. От исходной страницы, которую отдал банк, отображаемая страница внешне не будет отличаться, — отличие будет только внутри HTML кода в том месте, где была заменена ссылка.

Так что же это за страница, которую банк отдает в случае ввода корректного номера карты, и в которой скрипт подставляет ссылку на страницу успешной оплаты на мошенническом сайте? И ведь, вероятно, еще должна быть проверка 3D Secure от банков-отправителей, которая не позволит провести оплату? Код закончился на самом интересном месте и возникают сомнения, что без дополнительных хитрых скриптов, форм итп это может работать.

Мы дошли до заключительных строк скрипта. Кроме разбора сухих цифр и букв хотелось бы получить какой-то результат. Давайте это и попробуем сделать. Заодно и узнаем ответ на предыдущий вопрос.

В файл aviacfg.php вбиваю свой номер банковской карты. На нее буде пробовать принять перевод, если, конечно, получится. Открываю ранее сохраненную на диске страницу с формой. Форма эта была просто сохранена в браузере при посещении одного из мошеннических сайтов, который на момент написания первой части публикации, еще работал. Форма сохранилась уже с суммой 2915руб, а для тестирования это слишком много. Давайте это изменим. В любой форме есть видимые и скрытые поля. Скрытые поля (input, select) ничем не отличаются от обычных, за исключением того, что их не видно. Такие поля используются для того, чтобы хранить служебную информацию, которую пользователю видеть не нужно. Скрываются поля ввода двумя способами.
 

  • Через стили CSS (свойство display:none). Это свойство может относится, как к самому элементу (input), так и к контейнеру, (например DIV) в котором располагается элемент input.
  • Второй способ скрытия поля ввода — указать его тип, как type=«hidden». У обычного видимого поля тип type=«text».

В нашем случае поля формы скрыты с помощью type=«hidden».

Нажимаем в браузере F12 (режим веб-разработки). Находим нужное место в HTML коде и меняем текст type=«hidden» на type=«text» для двух или нескольких элементов input. Теперь мы видим поля, в которых хранится сумма и служебный код (code). Уменьшаем сумму с 2915руб до 20руб. Теперь в форму вводим данные своей второй банковской карты. С этой карты деньги должны списаться в случае, если получится провести перевод.

Подтверждаем форму, нажимая на кнопку «Оплатить». После нажатия кнопки запускается скрипта payp2p.php, который получает введенные в форму данные.

К своему удивлению после ввода реального номера карты и нажатия на тестовой форме кнопки «Оплатить», я увидел на экране страницу Сбербанка (банка из которого осуществляется перевод), с просьбой ввести код подтверждения 3D Secure.

Также на свой телефон я получил SMS от Сбербанка с кодом.

До начала тестирования с действующей банковской картой я предполагал, что для подтверждения кода 3D Secure его нужно будет каким-то образом «выманить» у пользователя, а затем программным путем скрыто передать в настоящую форму подтверждения 3D Secure. Однако, всё оказалось значительно проще. После того, как на сайт Промсвязьбанка отправляются данные для перевода с карты на карту, в браузере отображается форма банка-эмитента карты, с которой осуществляется перевод. В моем случае это Сбербанк. Эту форму даже подделывать не нужно. Форма подтверждения отображается на HTTPS сайте Сбербанка. Жертвы мошенников сами прямо в эту привычную для них форму вводят код подтверждения. После этого, если перевод пройдет, то деньги списываются. Хотя теоретически опротестовать такой перевод можно, далеко не факт, что деньги получится вернуть. На вероятность возврата денег влияют много факторов, в том числе, как быстро «потерпевший» обратится с заявлением в свой банк.

HTML код страницы, которую отдает Сбербанк для подтверждения 3D Secure под спойлером. Код получен при тестировании путем записи переменной $page в текстовый файл. Строка 166 скрипта payp2p.php.
 

HTML код страницы 3D Secure до замены строки

HTML код страницы после того, как в нем заменяется часть текста, под спойлером. Код получен при тестировании путем записи переменной $pp в текстовый файл. Строка 174 скрипта payp2p.php.
 

HTML код страницы 3D Secure после замены строки

Если коротко, то в HTML коде страницы 3D Secure (в этом примере от Сбербанка) строка:
 

<input name="TermUrl" type="hidden" value="https://3ds.payment.ru/cgi-bin/cgi_link">

Программным путем меняется на:
 

<input name="TermUrl" type="hidden" value="http://p2p.localhost/sus.php?cd=BX3FKT">

Заменяемая строка представляет собой адрес страницы, на которую банк-эмитент карты отправителя после проверки кода 3D Secure должен вернуть пользователя. До того, как скрипт заменил строку, в качестве адреса возврата был указан сайт Промсвязьбанка. После того, как скрипт заменил строку, в качестве адреса возврата уже указывается какая-то страница на мошенническом сайте.

Я до конца не понимаю, в какой именно момент производится подмена адреса возврата, но это работает. В тот момент, когда в браузере отображается https страница Сбербанка с просьбой ввести код 3D Secure, если в браузере посмотреть исходный HTML код страницы, там нет адреса возврата ни на какой сайт. HTML код этой страницы имеет длину более 400строк и полностью отличается от представленного выше HTML кода страницы ответа Сбербанка, который был захвачен путем записи переменных $page (строка 166) и $pp (строка 174) на диск.

Если вводить неправильный код 3D Secure, Сбербанк на своей странице выдает сообщение о том, что код неверный, и высылает еще одно SMS. Как только вводится правильный код, происходит переадресация на сайт оплаты или на подменный сайт. Т.е., вероятно, сама переадресация на сайт оплаты подразумевает, что со стороны Сбербанка все необходимые процедуры выполнены. Сбербанк здесь выступает в качестве примера для тестирования. Перевод может быть осуществлен и через другой банк.

Со стороны «покупателя билетов» выглядит это так. Покупатель на заранее подготовленной форме оплаты вводит номер своей карты. После этого почти сразу отображается страница подтверждения кода 3D Secure и приходит SMS с кодом подтверждения. Страница 3D Secure в браузере отображается на сайте банка эмитента карты покупателя по протоколу HTTPS. Страница с формой ввода номера карты может выглядеть подозрительно, но подтверждение 3D Secure на сайте своего банка не вызывает никаких сомнений или подозрений.

Кстати, обратите внимание на подпись «ticket pay» в строке «Описание» на странице 3D Secure от Сбербанка. Эта подпись задается в скрипте payp2p.php. В будущих примерах мы ее попробуем изменить.

Вернемся к тестированию.

Код из SMS я ввел на странице Сбербанка и после нажатия кнопки «Отправить», получил предупреждение о том, что данные будут отправлены по незащищенному соединению.

После того, как я подтвердил, что согласен с отправкой данных по незащищенному соединению произошла переадресация на страницу /sus.php?cd=…

Это страница возврата. Адрес возврата у нас задается в скрипте. В этом случае страница не найдена. Но причина понятна, — страница возврата заранее не была приготовлена.

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

Я решил, что причина неудачи в первой попытке заключалось в том, что локальный сайт (localhost), работал по незащищенному соединению http, а сайт Сбербанка по защищенному протоколу http. Http и https друг с другом не очень дружат. Это, кстати, объясняет, почему мошеннические сайты, описанные в первой части публикации, использовали защищенное соединение https, хоть и с самым простым сертификатом.

Для проверки этого предположения пришлось настроить на локальном сайте протокол https. Для этого был создан локальный домен p2p.localhost и самоподписанный сертификат. В результате новый адрес с тестовым скриптом стал выглядеть так:

https://p2p.localhost/payp2p.php

Дополнительно в скрипте был изменен адрес страницы, на которую должен осуществятся возврат после ввода кода 3D Secure. Сама страница для возврата тоже была предварительно приготовлена.

Пробуем еще раз провести платеж уже с локальным сайтом, который работает по протоколу https.

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

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

Всё. Теперь соединение осуществляется по https и при переходе с сайта Сбербанка предупреждения пропадают.

После ввода кода 3D Secure возврат на специально приготовленную страницу осуществляется корректно.

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

У меня была только часть файлов, которые используются на одном из мошеннических сайтов по продаже авиабилетов. Среди файлов, которые мне прислали, нашелся файл payment.php. Это аналогичный разбираемому выше скрипт. Судя по коду он, вероятно, был создан не для обмана посетителей на «боевом сайте», а для тестирования программистом-разработчиком возможности перевода с карты на карту через сервис 3ds.payment.ru. Маловероятно, но теоретически в ранних версиях мошеннических сайтах он мог использоваться не только для тестирования.

Я попробовал провести оплату с помощью альтернативного скрипта payment.php и платеж прошел с первого раза. Единственное, что подтверждение об успешной оплате отображалось на сайте 3ds.payment.ru. Я решил, что раз этот скрипт работает, то можно будет найти причину, по которой первый в описании скрипт (payp2p.php) не работает.


 

Полный код скрипта payment.php под спойлером

 

Описание отличий скрипта payment.php от payp2p.php

 

Заметка на полях… Возможно совпадение, но если обратить внимание на версию Firefox, которую «альтернативный» скрипт payment.php выдает в качестве идентификатора браузера («Firefox/3.0.3»), можно предположить, что он был написан как минимум несколько лет назад и, вероятно, сервис перевода с карты на карту Промсвязьбанка использовался подобными скриптами годами. Напомню, версия 3.5 Firefox была выпущена в 2009 году, версия 4 Firefox была выпущена в марте 2011г, разбираемый в начале статьи скрипт payp2p.php идентифицируется, как «Firefox/38.0», а текущая версия в ноябре 2016 года — Firefox 49.

Далее были попытки заставить неработающий по какой-то причине скрипт payp2p.php починить, взяв за основу рабочий скрипт. Были перепробованы разные варианты. Все куски кода, которые как-то могли влиять на работу по очереди переносились из рабочего скрипта в нерабочий. Среди прочего была попытка дополнительного промежуточного подключения к https://3ds.payment.ru/cgi-bin/is_3DS; изменение, включение и отключение опций cURL и др. Ничего не помогало, — каменный цветок не выходил.

Позднее на время тестирования переадресацию на заключительном этапе в payp2p.php было решено отключить. После этого появилась возможность прочитать сообщение об ошибке от Промсвязьбанка. Скриншот ошибки ниже. В браузере после неудачной попытки провести платеж отображается другая страница, но если нажать «Back» один или несколько раз, то можно увидеть эту страницу.

Перевод:

Извините, по техническим причинам Ваш запрос не может быть обработан.

Сообщение об ошибке: Неправильная/Дублирующая авторизационная ссылка (связь/сноска)
Пожалуйста, попробуйте еще раз или посетите нас позже, или используйте другие средства/способы оплаты

На сайте Промсвзязьбанка есть некоторые ограничения по количеству платежей с одной карты в день и др. Хотя лимиты количества реальных платежей я не превысил, возможно, на каком-то этапе платежи не проходили, из-за большого количество моих попыток. (Для захвата значений переменных при отладке я много раз начинал процесс оплаты, но не заканчивал его) Точно причину этого сообщения я не знаю. При каждой попытке оплаты ORDER_NUM и TIMESTAMP используются новые. Они не должны были влиять на появление такой ошибки. Хотя с карты, которую я использовал для оплаты, один успешный платеж прошел через альтернативный скрипт payment.php, возможно карта или отправителя или получателя попали в стоплист.

Скрипт payp2p.php был уже мало похож на свое первоначальное состояние. Я уже сам начал путаться, что я в нем заменил, а что нет. Поэтому я вернул его в исходный вид, за исключением того, что на последних строках подмена переадресации на страницу успешной оплаты была отключена. Номера карты отправителя и получателя для последующих попыток были использованы новые.

Наконец, с помощью payp2p.php получилось провести успешный платеж.

Обратите внимание на подпись в строке «Описание».

После ввода кода подтверждения 3D Secure возврат осуществляется на страницу Промсвязьбака:

Полученные SMS. Слева от банка отправителя. Справа от банка получателя.

Сбербанк, почему-то указал в SMS время по Гринвичу. Раньше я такого не замечал в сообщениях от этого банка.

При отключенной подмене страницы возврата повторить успешную оплату с помощью скрипта payp2.php получилось многократно.

Я пробовал платить с других карт. Каждый банк выдает свою форму 3D Secure. Но сути это не меняет.

Обратите внимание, что не все банки в свою форму подтверждения включают «дополнительное описание». В нашем пример «ticket pay».

Под страницу каждого банка подстраиваться не обязательно. Хоть формы разные, механизм работы подмены для них подразумевается одинаковый. Любая форма после оплаты содержит ссылку с адресом страницы, на которую нужно вернуться. На «левый сайт» сами банки, предоставляющие формы проверки 3D Secure, скорее всего не вернут. Наверняка, есть какие-то правила и банки с формы проверки 3DS как минимум должны возвращать на тот же домен, с которого пришёл запрос на оплату. (В нашем случае на 3ds.payment.ru). Банк, проверяющий код 3D Secure, в случае правильного ввода «пароля», в html коде страницы указывает адрес на который нужно вернуться, но проконтролировать был ли возврат именно на эту страницу уже не может.

В результате всех экспериментов удалось заставить скрипт payp2p.php платить через сервис перевода с карты на карту Промсвязьбанка 3ds.payment.ru. При этом пришлось отключить подмену адреса возврата на последних строках скрипта. При включении подмены адреса страницы возврата, как было в оригинале скрипта, в настоящее время реально деньги не проходят. Показывается страница проверки 3D Secure; присылается SMS с «паролем»; форма проверки не пропускает на следующий шаг при вводе неправильного пароля; после ввода правильного «пароля» производится переадресация на подложную страницу, но деньги не проходят.

Подлог адреса страницы возврата при успешной оплате — это очень важная часть для мошеннических сайтов. Если «покупатель авиабилетов» не подозревает, что его обманули, то он может оплатить не одну, а несколько покупок билетов и после этого долго (дни и недели) не предпринимать никаких активных действий по отмене платежа и тп. Если покупатель после «оплаты авиабилетов» получит подтверждение о переводе с карты на карту, то он скорее всего уже не будет проводить следующие оплаты, намного быстрее обратится в свой банк и, возможно, в полицию. Это означает, что денежные потоки на мошеннических сайтах снижаются, вероятность отмены прошедших платежей увеличивается, правоохранительные органы и сотрудников хостинга начинают действовать раньше, а вероятность не успеть вывести в безопасное место украденные средства увеличивается.

В том, что этот скрипт использовался на боевом мошенническом сайте, у меня нет сомнений. У меня есть основания полагать, что он работал в том виде, в котором мне его предоставили. В настоящее время он работает ограничено (без переадресации).

Примерно через три недели после выхода первой части публикации, в которой упоминалось использование мошенниками сервиса перевода с карты на карту Промсвязьбанка, этот банк внес некоторые изменения в работу своего сервиса, которые я считаю важными. Если раньше при оплате через сайт Промсвязьбанка плательщикам приходили малопонятные SMS с текстом «P2P PSBANK», то теперь стали приходить SMS с текстом «CARD2CARD PSBANK.RU». Даже такого, на первый взгляд, незначительно изменения расшифровки назначения платежа достаточно, чтобы часть потенциальных жертв мошенников отменила оплату на этапе подтверждения. Я думаю, что это не совпадение, а изменения были внесены именно в результате публикации статьи на GeekTimes.

Вероятно, что после публикации первой части статьи, наряду с изменением текста подтверждения в SMS, в алгоритмы работы сервиса перевода с карты на карту Промсвязьбанка могли быть внесены и дополнительные корректировки. Я не могу утверждать на 100%, но мое мнение, раньше сервис Промсвязьбанка 3ds.payment.ru с большой вероятностью не проверял возврат пользователей на свой сайт после успешного ввода кода 3D Secure на сайтах банков-эмитентов карт плательщиков. Поэтому платежи проходили даже в том случае, когда мошеннические скрипты меняли страницу возврата.

Банку, который много раз упоминается в этой публикации, повезло с бесплатной рекламой. Я думаю, что в действительности есть еще достаточное количество подобных банков. Просто этому больше повезло в том, что его выбрали сначала для использования на мошеннических сайтах, а потом и для разбора в этой статье. Как говорится, нет здоровых пациентов, — есть плохо обследованные.

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

Эта статья ставит много вопросов, но не дает всех ответов. Я уверен, что среди читателей найдется достаточное количество продвинутых пользователей, которые смогут более точно прокомментировать клиническую картину и поставить диагноз. Со своей стороны, я постарался максимально полно представить свидетельские показания…

Часть публикации с разбором скрипта оплаты закончена. Далее бонусы для тех, кто смог дочитать до этого места.

Откуда берутся дешевые цены на авиабилеты на мошеннических сайтах?

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

Пример информации по наличию мест и ценам на мошенническом сайте

Теперь у нас появилась возможность заглянуть за сцену и посмотреть, как это реализуется в программном коде.

Вот место в коде мошеннического сайта, в котором мы видим, откуда берутся картинки и цены по авиарейсам на мошеннических сайтах.

Как и предполагалось в этой серии мошеннических сайтов информация о наличии свободных мест берется на честном сайте www.aviacassa.ru. Поскольку количество авиакомпаний и рейсов большое, все картинки и иконки в подобной выдаче заранее скачать очень трудно, ссылки на такие картинки оставляются прямо на оригинальный сайт.

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

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

Парсер цен - более полная часть кода

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

Старый парсер использовал другой сайт для получения данных:

Совет для авиакассы (www.aviacassa.ru) — нужно закрыть возможность ссылок на файлы домена с внешнего реферера (ссылающегося сайта). Такую возможность можно закрыть всем без исключения, а можно сделать исключения только для проверенных партнеров. Веб-сервер NGINX, который использует aviacassa, легко позволяет это сделать. Такая же рекомендация ко всем подобным сайтам, которые могут быть использованы, как «доноры информации».

Если мошеннические сайты не смогут напрямую ссылаться на картинки на сайтах типа авиакассы, то это усложнит им жизнь. Количество логотипов и картинок различных авиакомпаний заранее не известно. Даже если картинки пытаться загрузить предварительно, можно что-то пропустить, и мошеннический сайт станет выглядеть некрасиво. Такие сайты вынуждены будут скачивать все картинки к себе локально на сервер при каждом запросе или хотя бы проверять, была ли такая картинка скачана ранее в «кэш» или нет. Это увеличивает нагрузку на сервер мошенников и делает отображение страницы более медленным. Кроме того, закрытие возможности ссылаться напрямую на картинки в один момент сделает все текущие мошеннические сайты, использующие информацию авиакассы нерабочими.

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

Также авиакасса может включить для подобных картинок отдельный лог, в котором будут сохраняться записи о всех внешних реферерах (ссылающихся сайтах). И за несколько дней в этом логе получится список всех активных мошеннических сайтов. Очень удобно — вместо того, чтобы пытаться по отдельности найти каждый сайт, можно попросить их самостоятельно записаться в список (лог-файл).
 

А еще если в авиакассе есть веселые админы, то можно пошутить...

Кто-то может сказать, что публикация таких статей служит учебным пособием для мошенников, и задать вопрос, почему я здесь это выложил? Отвечаю. Если есть какой-то способ воровства денег, основанный на использовании уязвимого или недостаточно защищенного программного обеспечения, про который знают хотя бы несколько человек и их цель на этом заработать, то попытка скрыть такую информацию и сделать вид, что никаких проблем нет, приводит только к еще худшим последствиям. Мошенники пользуются подобными способами еще активнее, банки при этом довольны, потому что им комиссию за услуги исправно оплачивают, а крадут деньги у них. Зачем банкам что-то менять, если и так все хорошо? Периодически только какие-то пользователи Интернета оказываются обманутыми и теряют деньги на мошеннических сайтах. Но кого это волнует?

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

Скрипт payp2.php и еще некоторое количество файлов, использовавшихся на недавней серии мошеннических сайтов по продаже авиабилетов, мне прислал пользователь frozenstorm. Где он его взял, я не знаю, — все вопросы по этому поводу направляйте к нему напрямую.

Но сразу могу сказать, что, как выяснилось позднее, найти полный комплект исходников мошеннических сайтов по продаже авиабилетов совсем несложно. Ищется по запросу «фейк авиабилеты». Оба главных поисковика выдают ссылки на первой странице. Полный комплект исходников стоил раньше всего 25-30т рублей. После того, как эта тема перестала работать, нерабочие исходники, которые, по словам продавца «легко допилить», стали стоить 10тр. Недавно, судя по сообщениям на форумах, в продаже якобы выставлена версия 2.0 опять по цене 25тр.

Ниже под спойлером пример свободной продажи исходников мошеннического сайта по продаже авиабилетов на одном из форумов.
 

Скриншот форума. (Аккуратно, очень длинные картинки)

На форуме, который приведен на скриншоте, открыто продаются и покупаются коды подобных мошеннических сайтов, данные кредитных карт, паспортные данные, персональная информация из государственных баз данных, предлагается сделать поддельные паспорта, водительские удостоверения итп. Это лишь короткий список для примера. Т.е. за редким исключением, там сплошной криминал. При этом администрация форума выступает гарантом между покупателями и продавцами. Форумов таких, как этот, несколько. Все они свободно работают годами. Все они прекрасно индексируются поисковиками (Яндексом, Гуглом итп). Адрес конкретного форума не привожу. Их очень легко найти.

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

Для того, чтобы нанести сокрушительный удар по мошенническим сайтам, продающие фейк авиабилеты, нужно не так и много. Если каждый сделает понемногу, то это сильно усложнит жизнь мошенникам и может поставить вопрос о неэффективности ведения такого бизнеса. Нужно немного внимания от поисковиков — не допускать попадания таких сайтов в рекламные объявления. Без рекламы пробиться таким сайтам в топ выдачи нереально. Также поисковики должны исключать из выдачи сайты, где фактически ведется покупка и продажа криминальных схем. Нужно немного внимания от банков — следить за своими сервисами, связанными с оплатой, так чтобы их не могли легко использовать мошенники. Нужно немного внимания от хостеров. Нужно немного внимания от платежных систем — для начала не допускать проведения платежей без проверки 3D Secure (как показано в первой части публикации, это до сих пор возможно). Нужно немного внимания от правоохранительных органов. Вместо того, чтобы расследовать каждый случай кражи денег, эффективнее действовать на упреждение — разобраться с гнездом, где мошенники общаются (проанализировать, например, те самые теневые форумы). И конечно нужно немного внимания от самих потенциальных покупателей авиабилетов.

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

Размешение Ваших турновостей на Pitert.Ru    Турновости, канал @pitertru в Telegram

Другие новости по теме «Происшествия»

Декабрь 19, 2024 - 04:09

11 декабря 2024 года решением главы администрации МО «Ивангородское городское поселение» И.П.Паршина введен запрет подъезда всех регулярных международных автобусов к пешеходному пункту пропуска МАПП Ивангород.

 

Декабрь 18, 2024 - 10:10

Уважаемые росграждане, Посольство России в Шри-Ланке убедительно просит Вас не нарушать местное законодательство, особенно по природоохранным вопросам.

 

Декабрь 18, 2024 - 09:53

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

 

Декабрь 18, 2024 - 06:40

На протяжении веков Джидда служила воротами к Красному морю Саудовской Аравии и его живописному побережью протяжённостью 1800 километров.