Загрузка...

20 лет проблем приема платежей

Тема в разделе Веб уязвимости создана пользователем дабстеп 18 авг 2022. (поднята 25 сен 2022) 1369 просмотров

  1. дабстеп
    дабстеп Автор темы 18 авг 2022 Заблокирован(а) 124 31 авг 2017
    Электронные системы расчетов существуют в интернете уже давно, а баги на них встречаются двадцатилетней давности.

    Мы находили критические уязвимости позволяющие угнать деньги и накрутить баланс.

    Сегодня мы разберем типовые реализации приема платежей и связанные с ними проблемы безопасности.

    Обзор платежных систем и типовых реализаций API

    Мало кто знает, но первой (анонимной!) платежной системой был DigiCash, который появился аж в 1989 году, за ним, в 1996 году, последовала уже более известная (преимущественно среди ******ов) система E-gold.

    Но вернемся в настоящее и перечислим основные современные крупные платежные системы/сервисы электронных платежей, которые позволяют принимать платежи на собственном веб-сайте:

    • PayPal
    • WebMoney
    • ЮMoney (бывшие Яндекс.Деньги)
    • ****
    • Alipay
    • и т.д.
    [IMG]

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

    Несмотря на кажущуюся простоту, процесс приема платежей, с точки зрения создания безопасной программной реализации, представляет собой комплексный процесс, который до сих пор приводит к проблемам как у крупных торговых площадок, так и у новых электронных систем расчетов, которые периодически выходят на рынок с "новым и удобным" API и прочими способами интеграции. Как же выглядит типичный процесс приема платежа? Для начала давайте рассмотрим текущую реализацию, которую описывает PayPal, так называемый PayPal Express Checkout.


    [IMG]

    Данную реализацию можно считать относительно безопасной и вот почему:
    • Параметры платежа не передаются явным образом, вместо этого используется Token
    • Сервер платежной системы не отправляет результаты на некий URL самостоятельно, вместо этого ваш веб-сайт должен самостоятельно их запросить и обработать ответ
    • В целом схема взаимодействия реализована так, что у потенциального разработчика существует минимум возможностей "выстрелить себе в ногу"
    А теперь посмотрим на схему, которую нам предлагает WebMoney:
    [IMG]

    Схема ни хрена не понятная. Также схема не отражает ряд нюансов, вроде подписи запроса. Или информацию о том, что URL, который принимает на себя технические параметры платежа от платежной системы и URL, куда пользователь будет перенаправлен для просмотра деталей об оплате, стоит делать разными. Архитектура, которую использует WebMoney, часто всплывает в той или иной форме и в других платежных системах, которые были созданы в СНГ.

    Типовые проблемы
    Излишнее усложнение схемы приема платежей ведет к финансовым потерям. Например, 10 лет назад Kaimi публиковал заметку о проблеме интеграции с WebMoney системы Global Collect Services, что приводило к возможности подтверждать платежи без оплаты в Steam, Battle.net и некоторых других.


    В чем же состояла проблема? Ранее я упоминал URL на стороне продавца, которые должны принимать информацию о платеже. Согласно документации, у WebMoney существуют три сущности:

    • Success URL - URL (на веб-сайте продавца), на который будет переведен интернет-браузер покупателя в случае успешного выполнения платежа в сервисе Web Merchant Interface. URL имеет префикс "http://" или "https://".
    • Fail URL - URL (на веб-сайте продавца), на который будет переведен интернет-браузер покупателя в том случае, если платеж в сервисе Web Merchant Interface не был выполнен по каким-то причинам. URL имеет префикс "http://" или "https://".
    • Result URL - URL (на веб-сайте продавца), на который сервис Web Merchant Interface посылает HTTP POST или SMTP-оповещение о совершении платежа с его детальными реквизитами. URL должен начинаться с префикса "http://", "https://" или "mailto:".

    Что делают некоторые разработчики, которые читают эту документацию:

    1. Обрабатывают информацию по одному URL, что приводит к возможности узнать адрес обработчика (также обработчик, в том числе Result URL, может отображаться в платежной форме на сайте WebMoney, но такое происходит не всегда и, вероятно, зависит от настроек).
    2. Некорректно реализуют проверку подписи для запроса, который приходит на Result URL. Это позволяет клиенту подменить данные о платеже.
    3. Проверяют подпись, но не проверяют сумму, которая пришла на Result URL. Это позволяет получить товар за 100$, заплатив, например, 0.01$.
    4. Проверяют подпись, сумму, но не нотацию передаваемых сумм. Помните я упоминал о передаче параметров платежа через браузер клиента? Так вот, WebMoney абсолютно нормально воспринимает сумму платежа со значением 1e1 или 0xFF, а сравнение подобных чисел, еще и на старых версиях PHP, еще и с учетом нюансов сравнения в языке PHP, приводило к самым неожиданным последствиям.
    5. Не совсем проблема платежной системы, НО, как насчет race condition и одинаковых внутренних идентификаторов платежей на ресурсе продавца? Привет, мультипликация баланса.
    6. ...
    Подпись запросов
    [IMG]

    Как это работало:
    1. При оплате через WebMoney, пользователя, в соответствии со спецификацией платежной системы, перенаправляло на сайт WebMoney, где он мог видеть сумму платежа, номер счета и прочие параметры.
    2. После нажатии кнопки “Далее” и аутентификации в системе становилась доступна информация об URL, который отвечал за обработку результата платежа (Result URL).
    3. Пользователь мог сформировать запрос к целевому URL, который, в соответствии со спецификацией WebMoney (ну почти), информировал платежную систему о том, что платеж успешно проведен.
    4. Profit!
    [IMG]

    Система приема платежей Global Collect успешно споткнулась о несколько проблем, которые упоминались выше:

    • Известный единый обработчик результатов платежа
    • Отсутствие проверки подписи (да и отсутствие подписи в запросе как таковой)
    • Использование данных, передаваемых через браузер пользователя, в качестве (хотя, согласно спецификации WebMoney, это можно было делать через коллбэк, приходящий от серверов WebMoney)
    Все это привело к возможности совершать фиктивные транзакции и покупать все, что использовало процессинг Global Collect, без ограничений. Проблему устранили только через ~2 недели массовой эксплуатации.

    Другой вариант похожей проблемы, но чуть сложнее, был не так давно в Smart2Pay.


    Еще одна проблема, связанная с подписью запросов - Length Extension Attack.

    [IMG]
    Или атака удлинением сообщения. Согласно Wikipedia - это тип атаки на хеш-функцию, заключающейся в добавлении новой информации в конец исходного сообщения. При этом новое значение хэша может быть вычислено, даже если содержимое исходного сообщения остаётся неизвестным. Чуть подробнее можно изучить здесь. Проблема встречалась всего пару раз, когда разработчики решили реализовать свою “классную” подпись запросов в стиле VK (которые в общем-то тоже не сами придумали алгоритм), но получилось как обычно.


    Ниже небольшая иллюстрация на тему как допустимо генерировать подпись в таком вот стиле и как “выстрелить себе в ногу”.
    [IMG]
    Для эксплуатации же можно воспользоваться одним из следующих инструментов:

    https://github.com/bwall/HashPump
    https://github.com/iagox86/hash_extender

    Раскрытие “Result URL”
    На сайте, где было доступно пополнение с помощью WooPay (через SMS), отображался полный URL с параметрами (включая подпись), по которому платежная система уведомляет сайт, если платеж успешно зачислен.
    Логика достаточно проста, нужно вызвать исключительную ситуацию, чтобы тестируемое веб-приложение вывело ошибку.

    Если выбрать оплату через SMS и ввести случайный недействительный номер, то получаем:

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

    Атрибуты платежа
    Перейдем к проблеме проверки атрибутов платежа.

    Один из вариантов интеграции с ЮMoney (ex Яндекс.Деньги), это форма для перевода или ее старая реализация. Опознать ее можно по наличию запросов

    https://yoomoney.ru/eshop.xml


    или

    https://yoomoney.ru/quickpay/confirm.xml

    Кстати тестируя на лолзе, пришёл к выводу, что таким образом можно "закрывать" заявки на пополнение, по сути ничего серьезного, но всё же)
    Прямо при отправке запроса необходимо подменить число, которое запрашивает тестируемое веб-приложение:

    [IMG]
    Высокая вероятность, что платеж пройдет. А дальше сайт либо проверяет сумму, либо нет. Так как в комментарии к платежу передается идентификатор пользователя и/или идентификатор платежа, этого достаточно, чтобы оформить подписку на какой-то сервис (например, на rbc.ru).
    [IMG]
    Небольшой пример:
    [IMG]
    На скриншоте происходит оплата подписки на бота голосового ассистента в Telegram, но сумма платежа не проверяется, что дает приобрести продукт за произвольную цену. Подменяем сумму 1990 на 19, получаем нужную подписку. Этот тип проблем часто встречается (например, много сервисов-ботов в Telegram, о которых многие слышали и где эта проблема до сих пор присутствует), в том числе на зарубежных ресурсах (пример из старых - покупка лицензии Minecraft), в 2022 году, хотя казалось бы…

    Еще один релевантный пример, но связанный не с суммой платежа, а с валютой, присутствовал у ****. В кошельке была опция пополнения путем отправки SMS на короткий номер, причем валюта передавалась через браузер клиента на нескольких этапах (выбор валюты и суммы, отправка SMS), где сервер доверял данным клиента. В итоге на счет зачислялось 100$, а оплата на 100р.


    А что там в 2022?


    Смотрим в чат армянского банка https://t.me/Inecobank_forum/6333

    [IMG]
    [IMG]
    Значит проблема до сих пор актуальна.
    Нотации и сравнение типов
    [IMG]

    Занимательная проблема присутствовала на широко известном в узких кругах сервисе Антикапча (сервис по разгадыванию капчи за деньги с API интерфейсом). Личный кабинет пользователя позволял совершать ряд операций, в т.ч. выводить неиспользованный баланс на WebMoney. WebMoney нормально воспринимает сумму платежа в различных нотациях (например, со значением 1e1 или 0xFF), а сравнение подобных чисел, еще и на старых версиях PHP, еще и с учетом нюансов сравнения в языке PHP, еще и с порцией “качественного кода” приводило к самым неожиданным последствиям.

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

    Пример возможной логики перевода денег:


    [IMG]
    Если на вход подать 1e9, имея на балансе 20 долларов, механизм проверки удостоверится, что 19>20, вырезав все кроме цифр, а процессинг обработает 1e9 как 1000000000.


    Другая ошибка - это особенности приведения типов.

    [IMG]
    NodeJS - пример языка с динамической типизацией. Когда прибавляешь к числу строку, то произойдет конкатенация 1+"1" = "11" Но стоит из строки вычесть число, то уже строка приводится к числу "11"-1 = 10


    Самый популярный формат обмена данными - JSON:


    {"amount":100}


    Справедливо, что JSON будет корректным: параметр amount с числом 100. Но и этот вариант будет корректным JSON’ом:


    {"amount": "100"}



    Только содержимое параметра amount будет строкой, но из-за особенностей обработки подобного запроса, возможно кто-то приплюсует к числу 1337 значение этого параметра, и получится 1337100, а не то, что задумывалось изначально)


    Ошибки бизнес-логики
    [IMG]

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


    Другой пример:

    Вызываем механизм пополнения баланса (на балансе $1000, пополняем на $100).
    1. Веб-приложение запоминает текущий баланс.
    2. В это время тратим (отправляем на второй аккаунт) деньги.
    3. После выполнения транзакции баланс окажется $1100.
    Отдельного упоминания заслуживает работа корзины на ресурсах, где используется несколько валют. Уязвимость которая была в магазине Xbox несколько лет назад (причем после исправления появлялась еще пару раз):
    Кладёшь в корзину товар за минимальную цену в рублях.
    1. Ищешь в магазине дорогие игры, цены на которые указаны в долларах.
    2. Добавляешь их в корзину.
    3. Магазин считает сумму позиций, но перерасчёт от доллара к рублю происходит в соотношении один к одному.
    [IMG]

    Голоса в vk.com генерировались с помощью SMS со счета с около-нулевым балансом. Отправляешь SMS, оператор связи не может забрать деньги (овердрафт отсутствует), а голоса пополняются.


    Другой вектор через SMS - это перевод со своего счета на чужой в платежной системе ****. Это делалось через отправку сообщения на специальный короткий номер:
    [IMG]


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

    [IMG]

    Дальнейшие шаги — использовать сервисы по подмене номера, чтобы отправить туда SMS от аккаунта, на котором много денег. Способ так и не проверен, хотя в теории выглядит крайне забавно). Очевидцы говорят, что подобным образом можно было привязать карту через SMS, а дальше сливать деньги с карты.
    А теперь изучим операцию возврата средств (refund). Если рассмотреть каноничный процесс возврата, то станет очевидно, что на каждом этапе можно пропустить или некорректно реализовать все проверки, что приведет к финансовым потерям.

    [IMG]

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

    Ошибки округления, переполнения и числа с отрицательным знаком

    Частая категория проблем - ошибки округления чисел. Распространенные проблемы с округлением могут выглядят следующим образом:


    [IMG]

    1. Пользователь переводит 0,29 RUB в доллары США.
    2. При стоимости одного доллара в 60 RUB, сумма в 0,29 RUB соответствует 0,00483333333333333333333333333333 USD.
    3. Данная сумма будет округлена до двух знаков после запятой, т. е. до 0,01 USD (один цент).
    4. Затем пользователь переводит 0,01 USD обратно в рубли и получает 0,60 RUB.
    5. Таким образом пользователь «выигрывает» 0,31 RUB.
    Проблему до сих пор можно встретить в крупных финансовых организациях (различных банках и биржах).

    [IMG]
    Если присмотреться, то можно увидеть уязвимость, хоть она и не актуальна на текущий момент.

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


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


    [IMG]
    Еще один пример – это восприятие больших сумм при передаче между системами. В HTTP-запросе передаваемое число будет строкой, но вот обработка большого числа может отличаться, т.е. отправляется запрос на пополнение на больше чем INT_MAX+2, на локальной системе число обрабатывается корректно, а в платежной системе получаем счет на оплату размером в 1$.


    Стоит учитывать, что тестируемая система может использовать не 32-разрядную переменную для хранения значения, а 64-разрядную.


    Чтобы лучше понять, можно потыкать циферки в вконтакте. Раньше в vk.com все числа были 32-разрядные. Чтобы получить id1 с помощью переполнения, необходимо было посчитать 2^32+1.


    Страница Дурова открывалась под https://vk.com/id4294967297


    Но сейчас уже все переведено на int64, поэтому, чтобы получить единицу, необходимо посчитать 2^64+1


    Это одни и те же страницы: https://vk.com/id1 == https://vk.com/id18446744073709551617


    А теперь представь, что в веб-приложении операцию с id:100 может выполнить только администратор? А если это операция с 2^32+100?
    З.Ы. Иногда можно не рассчитать с циферками, и уйти глубоко в минус, так и не достигнув плюса)


    [IMG]
    Состояние гонки

    Перейдем к такой проблеме, как состояние гонки (англ. race condition). Согласное Wikipedia – это ошибка проектирования многопоточной системы или приложения, при которой работа системы или приложения зависит от того, в каком порядке выполняются части кода. Своё название ошибка получила от похожей ошибки проектирования электронных схем.


    Условно каноничный пример:


    [IMG]




    1. Выполняем операцию на перевод средств в рамках баланса.
    2. Совершаем ту же операцию N раз, где баланс должен закончиться при N-1 или больше, но отправляя запросы с минимальной задержкой (тут на помощь приходит HTTP-пайплайнинг, особенности с HTTP2 (все в рамках одной TCP-сессии) и т.п.).
    3. Наблюдаем минус на балансе.


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


    [IMG]

    Алгоритм эксплуатации был следующий:


    • Создаем тейк-профит на 0,1 BTC, когда стоимость биткойна будет равна $100,000
    • Биржа изымает (блокирует) в аккаунте 0,1 BTC на будующий тейк-профит
    • Удаляем тейк-профит отправляя 438695936458926734 запросов
    • Биржа «возвращает» нам 0,1 x N BTC, где N, количество одновременно выполненных операций
    Эта категория проблем не специфична для финансовых операций. Сюда же относятся проблемы типа TOCTOU, когда, например, приложение проверяет подпись на файле, далее некоторое окно и далее работа с содержимым файлом (а содержимое возможно подменить в рамках окна).

    Резюме

    Реализация безопасного приема платежей - это комплексная задача, которой должны заниматься опытные разработчики. Получившийся продукт необходимо всесторонне тестировать, иначе мы еще не один десяток лет будем наблюдать детские проблемы безопасности из начала нулевых, особенно при появлении новых классных способов платежей (привет, криптовалюты) и сопутствующих платежных систем. И это мы еще не упоминали атаки на генераторы псевдослучайных чисел, Padding Oracle, и множество других веселых штук, которые заслуживают отдельной статьи.


    оригинал - https://xss.is/threads/69067/ ( не реклама )
     
    18 авг 2022 Изменено
  2. RELIA
    RELIA 18 авг 2022 Хорни каждый день ♡ 172 22 май 2018
    круто, но мне лень читать
     
  3. Мизулина
    Мизулина 18 авг 2022 :peace: ne pishite v tg spasibo | lzt.market/user/2283430 20 382 25 май 2019
    накрутите на сбер пож
     
    1. дабстеп Автор темы
      Мизулина, Не знаю про сбер, но на соседнем борде депозит крутили:wut:, борд по инфобезу
  4. hanguan
    hanguan 18 авг 2022 Заблокирован(а) 166 2 дек 2021
    где пруфы? больше половина статьи с инета, некоторые скрины сделал сам, коротко можно было расписать без воды и левой темы
     
    1. дабстеп Автор темы
      hanguan, Спасибо за рецензию, мне её не хватало от вас
    2. дабстеп Автор темы
      hanguan, ну, а если серьезно то я оставил линк на оригинал в конце статьи, можно было и без жалобы) Не думал, что вас заденет благодарность за рецензию
    3. дабстеп Автор темы
      hanguan, И о каких "пруфах" вы говорите? Это статья в разделе веб уязвимости, а не тема с продажей скинов для стендоффа)
  5. Qisneep
    Qisneep 18 авг 2022 6528 30 дек 2021
    мод сбербанк много денег
     
    1. xeds
      Qisneep, Лакипатчер уже не справляется
  6. nodopeclvb
    nodopeclvb 21 авг 2022 :shiza: 14 352 11 авг 2019
    сильно
     
    1. Ddos2281337
      nodopeclvb, Ctrl + c и Ctrl + v это не сильно
  7. NextLvl
    NextLvl 21 авг 2022 49 21 авг 2022
    Зач так много текста
     
    1. дабстеп Автор темы
  8. микропенис
    микропенис 22 авг 2022 Заблокирован(а) 1223 11 авг 2022
    накрутите на тинькофф пжжжжж
     
    1. микропенис
      микропенис, ну если честно то ползено много нового узнал
Загрузка...
Top