Конкурс “Большой ку$h” на PHDays — райтап

Буквально пару дней назад завершился PHDays, познакомился со многими интересными людьми, в целом форум оставил самые позитивные впечатления, за что огромный респект организаторам, компании Positive Technologies. Уже появилось довольно много отчетов (shr, d0znpp, toxa, asintsov), напишу лишь о том, что больше всего запомнилось лично для меня – о конкурсе Snatch, он же “Большой ку$h”.

За день до конкурса всем участникам выдали по флешке с PHP-исходниками системы дистанционного банковского обслуживания, нужно было найти в них уязвимости и на следующий день, используя баги, слить как можно больше денег со счетов в этой системе. Причем, обналичка украденных полученных средств производилась на реальном банкомате с реальными картами. В итоге, удалось занять лишь третье место, первое досталось Gifts’у, а второе – Глебу Чербову из Digital Security.

Никаких SQL-инъекций, LFI/RFI и прочих традиционных для PHP уязвимостей в коде не было – присутствовали баги, которые, по словам организаторов, встречаются в ходе пентеста реальных ДБО. Система была подготовлена очень грамотно, разработчики потрудились на славу. Всего присутствовало три уязвимости, самую жирную успел использовать Gifts благодаря своему многопоточному скрипту на Python, который мне впоследствии удалось посмотреть, за что спасибо cyber-punk’у. Вторую уязвимость нашли все, так как была самой простой, и, соответственно, давала меньше всего денег. Третий баг позволял получать доступ к аккаунтам с помощью подбора сессии. Как ни странно парни, занявшие первое и второе место, как впоследствии выяснилось, ее не использовали. Буквально за час до конкурса я нашел этот баг, но использовать его мне удалось, до сих пор очень обидно.

1. Уязвимость через helpdesk

helpdesk/pswdcheck.php
helpdesk/index.php
[php]
$user = $auth->checkSession();
if(!$user) {
/* … */
}
[/php]

class/HelpdeskAuth.php
[php]
public function checkSession() {

if(isset($_SERVER["HTTP_BANKOFFICEUSER"])) {
$userId = base64_decode($_SERVER["HTTP_BANKOFFICEUSER"]);
$userInfo = $this->user->getUserInfoById($userId);
$this->user->setupUserInfo($userInfo);
return $this->user;
}[/php]
При отправке HTTP-хэдера BANKOFFICEUSER с любым значением можно было обойти авторизацию и получить доступ к скрипту, который выводит пользователей со слабыми числовыми паролями. Для брута юзера с 5-символьным паролем требовалось 100 тысяч запросов. Была captcha, но она нисколько не мешала, так как был обход:

login.php
[php]if($_POST["code"] != $captcha->decodeCaptchaCode($_POST["_code"])) {[/php]

class/Captcha.php
[php]
public function decodeCaptchaCode($code) {
return @base64_decode(@strrev(@base64_decode($code)));
}
[/php]
Здесь все просто, для обхода нужно было отправлять в POST, например, такие параметры: code=”12345″ и _code=”PVVETnpJVE0=”.

Получив доступ к аккаунту, для перевода денег на свой счет было необходимо использовать еще одну уязвимость. На одних аккаунтах транзакции могли проводиться без защиты, а на других с помощью одноразовых паролей. Эти одноразовые пароли генерились следующим алгоритмом:
[php]
protected function generateOTP() {
$OTPs = array();
$s = 44553 + $this->userInfo["id"];
for($n = 10; $n < 24; $n++) {
$OTP = "";
$j = rand(20,39);
$j = substr($j, 0, 1);
$OTP = $n*$s*$j;
$OTP = substr($OTP, 0, 5);
$OTPs[] = $OTP;
}
return $OTPs;
}[/php]
Понятно, что сбрутить тут очень просто – всего 19 вариантов всего 2 варианта (thx BECHED). Был еще один способ защиты транзакций, но сгенерированный OTP было невозможно подобрать при переходе на третий шаг авторизации OTP не проверялся (thx Gifts).

2. Уязвимость в восстановлении пароля

Нужно было лишь отправить запрос на сброс пароля и брутить код, который генерился следующим нехитрым образом:
[php]$key = md5($login.rand(1, 250));[/php]
Собственно, все использовали именно этот баг, хорошо, что в своем брутере я начал с конца диапазона аккаунтов, а не с начала, иначе вообще ничего не досталось бы.

3. Слабые сессии

class/Auth.php
[php]
private function getSpecialHash($password) {
$hash = sprintf("%u", crc32($password));
if(strlen($hash) > 4) {
$hash = substr($hash, 0, 4);
}
if(strlen($hash) < 4) {
while(strlen($hash) < 4) {
$hash .= "1";
}
}
return $hash;
}[/php]

У некоторых пользователей, для которых в БД поле type соответствовало значению “contractor”, можно было сбрутить сессию, так как рандомный хэш состоял лишь из 4 символов, т.е. требовалось лишь 10 тысяч запросов. Почему я не догадался попробовать уязвимость на аккаунтах, на которых Дима Евтеев демонстрировал для публики возможности ДБО, для меня остается загадкой.

Помимо конкурса на PHDays понравилась настоящая хек-атмосфера, интересные доклады и халявный Гиннес в баре 🙂 Остается поблагодарить Positive Technologies за организацию мероприятия, было очень круто.


Posted

in

by

Comments

16 responses to “Конкурс “Большой ку$h” на PHDays — райтап”

  1. cyber-punk Avatar

    Опередил меня =( Я тоже хотел написать врайтап, с рахбором исходников 🙂

  2. Gifts Avatar

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

    Как это ты писал на ПХП, тоже интересно. Без воркеров это тот еще финт ушами

    З.Ы. и вообще я обижен то ли на организаторов, то ли на Ребза – мой ник неправильно написали =)

  3. Raz0r Avatar

    Точно, обновил) Я написал по отдельному скрипту для каждой уязвимости, использовал RollingCurl (http://code.google.com/p/rolling-curl/).

  4. Gifts Avatar

    [quote]Понятно, что сбрутить тут очень просто – всего 19 вариантов. Был еще один способ защиты транзакций, но сгенерированный OTP было невозможно подобрать.[/quote]

    Вот похоже почему я больше всего сорвал денег, там же три отп:

    1) Без проверки, переходим на третий шаг – профит
    2) Генерируемый список ключей – брутим комбинации – профит
    3) В базе обозначен SmartCard вроде как – достаточно не переходить на 3 шаг, а сразу идти на 4 – там нету проверки подтвержденности транзакции (столбец otp_check)

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

  5. Raz0r Avatar

    Теперь понятно)

  6. IAD Avatar

    хы, чувствую здорово развлеклись =)
    Завидую

  7. cyber-punk Avatar

    Gifts, мой ник тоже написали не правильно 🙁

  8. chipik Avatar
    chipik

    “Слабые сессии”
    багу нашли, но почему-то решили её не использовать.

    Вот с OPT для SmartCard косячнули слегка, уязвимость нашли, а вот то, что на 3 шаг ходить не стоит не проверили 🙁

    А от атакующих никто не защищался?

  9. Raz0r Avatar

    Гифтс сделал, причем очень основательно) Я считаю, что обычные аккаунты не было смысла защищать, так как после слива денег они были бесполезны. А защита своего аккаунта – просто не заходить в него, чтобы не назначалась сессия.

  10. BECHED Avatar

    Задание было на грамотную реализацию и толику везения =)
    Я сделал отвратительнейшую реализацию, на которую мне самому стыдно смотреть.
    Поэтому ничего и не снял =)
    Кстати, у меня была настолько убогая реализация, что брут сессии в баге с контрактными акками обрывался на 502 ошибке серва, которая регулярно скакала из-за ддос-эффекта.

  11. Rebz Avatar

    Gifts, Cyber – ники писал не я, поэтому хз кто их такими вписывал, я давал нормальные 🙂
    Разор, за подробный райтап отдельное спасибо, было интересно читать.

  12. BECHED Avatar

    Ещё стоит отметить, что в функции generateOTP() было достаточно проверить всего 2 варианта, поскольку текущий номер одноразового пароля можно было напарсить, а случайна здесь лишь строка $j (2 или 3).

  13. Raz0r Avatar

    Точно, там же substr()

  14. Raz0r Avatar

    Обновил пост

  15. Rebz Avatar

    Парни, если подвести итог, что же в итоге не хватило, чтобы вывести весь куш на кошельки участников? Обвал сети, нехватка времени или что-то ещё?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.