Шаг за шагом. Автоматизируем многоходовые атаки в Burp Suite

Шаг за шагом. Автоматизируем многоходовые атаки в Burp Suite

@Leakinfo

При ата­ке на веб‑при­ложе­ние иног­да нуж­но мно­гок­ратно выпол­нить цепоч­ку каких‑то дей­ствий. Самый яркий при­мер — перебор паролей или вто­рого фак­тора аутен­тифика­ции либо мно­гок­ратное исполь­зование ресур­сов. Для это­го есть раз­ные инс­тру­мен­ты. Какой из них выб­рать, если, нап­ример, нам пот­ребу­ется тысячу раз под­ряд выпол­нить пять зап­росов через HTTP, под­держи­вая одну и ту же сес­сию? Я выберу Burp Suite, и вот почему.

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

Ес­ли тебе труд­но реали­зовать подоб­ные задачи при помощи язы­ков прог­рамми­рова­ния или ты счи­таешь, что на это уйдет мно­го вре­мени, мож­но вос­поль­зовать­ся Burp Suite. Этот инс­тру­мент пре­дос­тавля­ет сра­зу нес­коль­ко спо­собов авто­мати­зации:

  • мак­росы;
  • пла­гин Stepper от сто­рон­них раз­работ­чиков;
  • пла­гин Turbo Intruder от соз­дателей Burp Suite.

Мы погово­рим о том, что дают эти под­ходы, об их воз­можнос­тях и огра­ниче­ниях.

Рас­смат­ривать работу этих трех под­ходов мы будем на при­мере задачи, которую при­ходит­ся решать очень час­то: перебор четырех­знач­ных одно­разо­вых паролей, которые исполь­зуют­ся... Да поч­ти вез­де. Кста­ти, на bug bounty за экс­плу­ата­цию та­ких уяз­вимос­тей мож­но получить не­малое воз­награж­дение.

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

ОПИСАНИЕ ЗАДАЧИ

Вот как сфор­мулиро­вана тес­товая задача на сай­те PortSwigger Academy:

Двух­фактор­ная аутен­тифика­ция в этой лабора­тории уяз­вима перед брут­форсом. Ты уже получил имя поль­зовате­ля и пароль, но не име­ешь дос­тупа к верифи­каци­онно­му коду поль­зовате­ля 2FA. Что­бы решить эту проб­лему, перебо­ром най­ди код 2FA и получи дос­туп к стра­нице акка­унта Кар­лоса.
Учет­ные дан­ные жер­твы: carlos:montoya.

Осо­бен­ность этой задачи сос­тоит в том, что здесь недос­таточ­но прос­то переб­рать код одно­разо­вого пароля (One Time Password — далее OTP) с сущес­тву­ющей сес­сией, потому что пос­ле двух неп­равиль­ных попыток при­ложе­ние перес­тает счи­тать сес­сию валид­ной. Для решения задания нам пред­сто­ит выпол­нять пре­даутен­тифика­цию при помощи учет­ных дан­ных, а пос­ле это­го попытать­ся пред­ска­зать OTP-код.

Подробнее о задании

Нам дана стра­ница аутен­тифика­ции, которая выг­лядит сле­дующим обра­зом.

Стра­ница аутен­тифика­ции

При вво­де учет­ных дан­ных при­ложе­ние отправ­ляет сле­дующий зап­рос на сер­вер:

POST /login HTTP/1.1

Host: ace61ff51f4557d880dbab96004f009d.web-security-academy.net

Cookie: session=rcnBF1vzBD00ZSjcoswRzttRrEPIQNj2

Content-Type: application/x-www-form-urlencoded

Content-Length: 70

csrf=AxCZcrNQ1Y7x8xTI9odKun0alLM34a9a&username=carlos&password=montoya

Ес­ли мы вве­дем учет­ные дан­ные кор­рек­тно, на экра­не появ­ляет­ся сле­дующая стра­ница вво­да OTP-кода.

Стра­ница вво­да OTP

Пос­ле вво­да слу­чай­ного OTP-кода при­ложе­ние отпра­вит сле­дующий зап­рос:

POST /login2 HTTP/1.1

Host: ace61ff51f4557d880dbab96004f009d.web-security-academy.net

Cookie: session=2gt4P1gFqzyxZJIonAlFv9czYetD5pm0

Content-Type: application/x-www-form-urlencoded

Content-Length: 51

csrf=W9Nei8NhTXl5usVKeynuZ3kbjRHaVjW7&mfa-code=1234

Ес­ли мы смо­жем уга­дать OTP-код, мы решим задание. Шанс уга­дать, по сути, не так уж и мал: 1 к 10 000. С уче­том того что количес­тво попыток у нас не огра­ниче­но, пусть и тре­бует допол­нитель­ных дей­ствий, резуль­тат гаран­тирован на 100%.

Что важ­но знать, преж­де чем мы прис­тупим к решению этой задачи?

  1. При­ложе­ние исполь­зует сес­сион­ный иден­тифика­тор, который мы получа­ем при вхо­де на сайт. Он изме­няет­ся пос­ле пер­вого эта­па аутен­тифика­ции при помощи кор­рек­тных учет­ных дан­ных.
  2. Пос­ле аутен­тифика­ции у нас есть толь­ко две попыт­ки вво­да OTP-кода. Пос­ле двух неудач­ных попыток наша сес­сия инва­лиди­рует­ся и при­ходит­ся начинать весь про­цесс с начала.
  3. При­ложе­ние исполь­зует CSRF-токены, которые меня­ются при каж­дом зап­росе. Их необ­ходимо под­хва­тывать и под­менять для каж­дого нашего POST-зап­роса.

Ос­талось авто­мати­зиро­вать про­цесс получе­ния сес­сии, вво­да пер­вичных учет­ных дан­ных, под­хва­та CSRF-токенов и попыток пред­ска­зания OTP-кода. Прис­тупим!

СПОСОБЫ РЕШЕНИЯ

Способ 1. Использование макросов

Мак­росы в Burp Suite — это механизм для авто­мати­зации пре­доп­ределен­ных пос­ледова­тель­нос­тей дей­ствий. Ты можешь исполь­зовать мак­росы внут­ри пра­вил обра­бот­ки сеан­сов для решения раз­личных задач. Научить­ся ими поль­зовать­ся нес­ложно, осо­бен­но на при­мере нашей задачи.

  1. С запущен­ным Burp Suite вхо­дим в сис­тему как Кар­лос (учет­ные дан­ные ука­заны в задаче) и собира­ем пакеты HTTP-аутен­тифика­ции вплоть до про­вер­ки 2FA. Они при­годят­ся нам для нас­трой­ки мак­роса.
  2. Пос­коль­ку сес­сия пос­тоян­но изме­нят­ся и инва­лиди­рует­ся при неус­пешных попыт­ках вво­да кода, нам понадо­бит­ся каким‑то обра­зом ее под­держи­вать. Для это­го мы будем исполь­зовать воз­можнос­ти обра­бот­ки сеан­сов Burp. Перей­дем к их нас­трой­ке.
  3. В меню Burp перей­ди в Project Options → Sessions. На панели Session Handling Rules наж­ми кноп­ку Add. Откро­ется диалог Session handling rule editor. Здесь мы будем добав­лять пра­вила под­держа­ния сес­сии и ее возоб­новле­ния.
  4. В окне диало­га во вклад­ке Scope в раз­деле URL Scope выберем зна­чение Include All URLs, что­бы не утруждать себя тон­кой нас­трой­кой. Сес­сия будет под­держи­вать­ся для любых URL.
  5. Вер­немся на вклад­ку Details и нач­нем соз­давать мак­рос. В раз­деле Rule Actions наж­мем кноп­ку Add и в открыв­шемся окош­ке выберем Run a macro. Здесь и нач­нется про­цесс соз­дания мак­роса, который будет пов­торять­ся при отправ­ке каж­дого нашего зап­роса.
  6. В открыв­шемся окне нас­трой­ки мак­роса выберем зап­росы для авто­мати­зации (это будут зап­росы пер­вично­го вхо­да, получе­ния иден­тифика­тора сес­сии и токена CSRF для отправ­ки пер­вой фор­мы). Для это­го в раз­деле Select macro нажима­ем кноп­ку Add. Здесь мы выбира­ем пакет вхо­да на стра­ницу /login (GET-зап­рос), пакет отправ­ки учет­ных дан­ных с POST-зап­росом к стра­нице /login и пакет вхо­да на стра­ницу /login2, где Burp под­хва­тит токен CSRF для вво­да OTP-кода.
  7. В этой же вклад­ке в ниж­нем пра­вом углу мож­но про­тес­тировать соз­данный нами мак­рос, нажав кноп­ку Test macro. Если мы наж­мем эту кноп­ку, то уви­дим, что Burp выпол­нит три зап­роса под­ряд, под­хва­тит выдан­ные ему Cookie-дан­ные и получит токен CSRF, который надо было исполь­зовать для отправ­ки фор­мы. Уже сей­час нам оста­ется толь­ко авто­мати­зиро­вать ввод OTP-кода, и дело сде­лано.
  8. На­жима­ем ОK и зак­рыва­ем диало­говые окна. Теперь при отправ­ке каж­дого зап­роса Burp будет выпол­нять дан­ный мак­рос для получе­ния новой сес­сии, а потом под­став­лять зна­чение сес­сии и зна­чение токена CSRF в исхо­дящий зап­рос для их обновле­ния.
  9. Те­перь возь­мем зап­рос с отправ­кой OTP-кода (POST-зап­рос к стра­нице /login2) и отпра­вим его в Intruder для авто­мати­зации.
  10. Во вклад­ке Intruder оставля­ем для наг­рузки толь­ко поле mfa-code (вот так: mfa-code=§1234§) и перехо­дим во вклад­ку Payloads. Здесь выбира­ем для Payload Type зна­чение Numbers и ука­зыва­ем циф­ры, которые мы хотим генери­ровать: From: 0, To: 9999, Step: 1, Min integer digits: 4.
  11. Пе­рехо­дим во вклад­ку Options и нас­тра­иваем Number of threads в зна­чение 1 (это нуж­но потому, что Burp не уме­ет одновре­мен­но под­держи­вать иден­тифика­торы сес­сии для двух и более потоков, толь­ко для одно­го).
  12. Пос­ле это­го запус­каем Intruder и вклю­чаем режим «жду­на».

На уга­дыва­ние кода Intruder понадо­билось поряд­ка десяти минут (мой код был 0643). Это супер­долго! Даже не десятая часть всех попыток. Почему нель­зя быс­трее? Потому что Session Handling не может под­держи­вать сес­сию у двух потоков одновре­мен­но.

Под­ведем итог того, что нам дают мак­росы и что они уме­ют.

Воз­можнос­ти:

  • удоб­но под­держи­вать сеанс сес­сии, пос­тоян­но зах­ватывая иден­тифика­тор сес­сии самос­тоятель­но, даже если он обновля­ется;
  • под­хва­тыва­ются не толь­ко зна­чения сес­сии, но и все зна­чения, которые исполь­зуют­ся для выпол­нения нового зап­роса: перемен­ные, токены CSRF и про­чее.

Проб­лемы:

  • ра­бота толь­ко в одном потоке;
  • ес­ли нуж­ны «перек­рес­тные ата­ки», исполь­зующие сес­сию двух поль­зовате­лей одновре­мен­но, то реали­зовать это невоз­можно, так как под­держи­вает­ся толь­ко одна сес­сия.
  • дос­таточ­но неоче­вид­ная нас­трой­ка, очень лег­ко запутать­ся в мно­гочис­ленных меню.

Способ 2. Использование плагина Stepper

Пла­гин Stepper — это бес­плат­ный пла­гин, дос­тупный в модуле Burp Suite Extender, который помога­ет авто­мати­зиро­вать пос­ледова­тель­нос­ти дей­ствий. Най­ти его мож­но на GitHub.

Раз­работ­чики рас­ска­зыва­ют о Stepper сле­дующее:

Stepper раз­работан как естес­твен­ное раз­витие инс­тру­мен­та Repeater из Burp Suite и пре­дос­тавля­ет воз­можность соз­давать пос­ледова­тель­нос­ти шагов и опре­делять регуляр­ные выраже­ния для извле­чения зна­чений из отве­тов, которые затем могут быть исполь­зованы в пос­леду­ющих шагах.

Ус­тановим его и вос­поль­зуем­ся им для решения нашей задачи.

WARNING

Очень важ­но! Если ты дела­ешь это пос­ле пре­дыду­щего экспе­римен­та, отклю­чи соз­данные ранее пра­вила обра­бот­ки сес­сий и уда­ли мак­росы!

Мо­дуль Stepper поз­воля­ет выб­рать ряд зап­росов и объ­явить в каж­дом из них перемен­ные, которые зап­рос получа­ет от пре­дыду­щего шага. Затем он под­став­ляет их, а так­же перемен­ные, получен­ные из тела отве­та при помощи регуляр­ных выраже­ний, и переда­ет сле­дующе­му зап­росу. Такая прос­тая и понят­ная связ­ка.

  1. Во вклад­ке Proxy выбира­ем три зап­роса, которые нам нуж­ны для получе­ния сес­сии, пер­вичной аутен­тифика­ции и извле­чения CSRF-токена. Вот они: GET /loginPOST /loginGET /login2. Выделив дан­ные зап­росы, щел­каем на них пра­вой кноп­кой мыши и в под­разде­ле Extensions нажима­ем кноп­ку Add 3 items to Stepper → New Sequence. Нам пред­ложат выб­рать для этой пос­ледова­тель­нос­ти наз­вание. Я назову ее evil.
  2. Важ­но: сле­ди, что­бы пакеты были перене­сены в пра­виль­ном поряд­ке! Для это­го нуж­но, что­бы пер­вые пакеты были выше пос­ледних при сор­тиров­ке во вклад­ке Proxy (это реша­ется сор­тиров­кой по номерам пакетов от мень­ших к боль­шим).
  3. Пе­рехо­дим в модуль Stepper, который появил­ся во вклад­ках с осталь­ными модуля­ми.
  4. Здесь мы уви­дим нашу пос­ледова­тель­ность и три пакета, про­нуме­рован­ные от 1 до 3. Каж­дый из пакетов мы можем пов­торно отпра­вить, нажав на кноп­ку Execute Step, что­бы получить при­мер тела отве­та, и про­тес­тировать каж­дый шаг.
  5. Вы­пол­ним пер­вый шаг, нажав кноп­ку Execute Step. Соз­дадим пер­вую перемен­ную для хра­нения и переда­чи иден­тифика­тора сес­сии, нажав на кноп­ку Add Variable в ниж­нем пра­вом углу модуля. Назовем перемен­ную session и добавим ей усло­вие поис­ка в поле Condition: session=([\d\w]+). Таким обра­зом у нас появит­ся пер­вая перемен­ная сес­сии, которую мы будем проб­расывать по осталь­ным зап­росам и исполь­зовать пов­торно.
  6. Так­же добавим вто­рую перемен­ную токена CSRF, которую проб­росим на сле­дующий зап­рос отправ­ки учет­ных дан­ных. Наж­мем кноп­ку Add Variable, назовем перемен­ную csrf и добавим усло­вие нахож­дения ее в теле отве­та в поле Condition со сле­дующим зна­чени­ем: name="csrf" value="([\w\d]+)".
  7. Вот что получи­лось у меня пос­ле выпол­нения этих шагов.
Пер­вичная нас­трой­ка Stepper
  1. Те­перь мож­но перей­ти к сле­дующе­му зап­росу отправ­ки учет­ных дан­ных и исполь­зовать в нем перемен­ные session и csrf. Для это­го перехо­дим к сле­дующе­му шагу (Step 2) и вмес­то сущес­тву­ющих там зна­чений сес­сии и CSRF-токена под­ста­вим обра­щение к перемен­ным в сле­дующем виде: $VAR:session$ и $VAR:csrf$. Получит­ся что‑то вро­де это­го:
  2. POST /login HTTP/1.1
  3. Host: ac3f1f861fe209fb80374867009900fe.web-security-academy.net
  4. Cookie: session=$VAR:session$
  5. Content-Type: application/x-www-form-urlencoded
  6. Content-Length: 70
  7. csrf=$VAR:csrf$&username=carlos&password=montoya
  8. Вы­пол­ним этот вто­рой шаг нажати­ем на кноп­ку Execute Step и получим ответ, где нас попыта­ются перенап­равить на стра­ницу /login2 и выдадут нам новый иден­тифика­тор сес­сии, который нам сно­ва нуж­но зах­ватить при помощи регуляр­ных выраже­ний и передать на сле­дующий шаг № 3. Соз­даем такую же перемен­ную session как и в пун­кте 4, и перехо­дим к шагу № 3.
  9. На шаге № 3 не забыва­ем сно­ва изме­нить зна­чение сес­сии на перемен­ную $VAR:session$ и выпол­няем зап­рос, так как нам прос­то нуж­но получить токен CSRF для пос­ледне­го шага. Пос­ле выпол­нения зап­роса сно­ва добав­ляем пар­синг токена CSRF в виде перемен­ной csrf, как мы это делали в пун­кте 5 ранее.
  10. Те­перь мы можем поп­робовать выпол­нить всю пос­ледова­тель­ность и про­верить ее работос­пособ­ность. Наж­мем на кноп­ку Execute Sequence в самом низу окна модуля. Видим, что пос­ледова­тель­ность выпол­нилась кор­рек­тно и на пос­леднем шаге мы получа­ем ответ с пред­ложени­ем ввес­ти OTP-код.
  11. Те­перь наша задача — запус­тить дан­ную пос­ледова­тель­ность 10 тысяч раз. Для это­го перено­сим POST-зап­рос /login2 из вклад­ки Proxy в Intruder.
  12. В панели Intruder нам нуж­но убрать сим­волы под­ста­новок § в полях сес­сии и CSRF-токена и оста­вить под­ста­нов­ку толь­ко в поле mfa-code вот так: mfa-code=§1337§.
  13. Для того что­бы шаги нашей пос­ледова­тель­нос­ти из модуля Stepper выпол­нялись для каж­дого зап­роса из Intruder, добавим в заголов­ки зап­роса сле­дующее: X-Stepper-Execute-Before: [Название твоей последовательности].
  14. Так­же под­ста­вим име­на наших перемен­ных $VAR:session$ и $VAR:csrf$ в пакет Intruder, толь­ко испра­вим их на $VAR:[Название твоей последовательности]:session$ и $VAR:[Здесь тоже]:csrf$. В Intruder у меня получил­ся сле­дующий пакет зап­роса:
  15. POST /login2 HTTP/1.1
  16. Host: ac311f2c1f2abcbd807689da0068009a.web-security-academy.net
  17. Cookie: session=$VAR:evil:session$
  18. Content-Type: application/x-www-form-urlencoded
  19. X-Stepper-Execute-Before: evil
  20. Content-Length: 51
  21. csrf=$VAR:evil:csrf$&mfa-code=§1337§
  22. В дан­ном при­мере имя моей пос­ледова­тель­нос­ти — evil.
  23. Те­перь перед каж­дым зап­росом из Intruder будет выпол­нять­ся пос­ледова­тель­ность ранее под­готов­ленных зап­росов, которые переда­дут в пакет получен­ные зна­чения сес­сии и CSRF-токена.
  24. Пос­ледний шаг, нас­тра­иваем наг­рузку во вклад­ке Payloads, точ­но так же, как мы это делали в пре­дыду­щем раз­деле. Выбира­ем в Payload Type зна­чение Numbers и ука­зыва­ем циф­ры, которые мы хотим генери­ровать: From: 0, To: 9999, Step: 1, Min integer digits: 4.
  25. За­пус­каем нашу ата­ку! Отсле­живать отправ­ленные пакеты мож­но в появив­шей­ся вклад­ке Logger или при помощи модуля Logger++.

В этот раз мне повез­ло боль­ше, мой код был 0261. Что важ­ного мож­но заметить? В отли­чие от пре­дыду­щего вари­анта мы не огра­ниче­ны одним потоком и соз­дали пять потоков, а самые умные мог­ли отклю­чить галоч­ку Set Connection: close в опци­ях наг­рузки и уда­лить этот заголо­вок из пакетов в Stepper и Intruder, что­бы уве­личить ско­рость работы.

Сде­лаем выводы.

Воз­можнос­ти:

  • из‑за того что модуль Stepper под­держи­вает сес­сии, переда­вая зна­чение сес­сии и токена от зап­роса к зап­росу, мы можем исполь­зовать мно­гопо­точ­ное исполне­ние зап­росов и наши перемен­ные не будут кон­флик­товать в потоках;
  • нам ста­новят­ся дос­тупны перек­рес­тные ата­ки, ког­да мы можем запус­кать работу нес­коль­ких пос­ледова­тель­нос­тей парал­лель­но;
  • на­тив­но понят­ная нас­трой­ка перено­са сос­тояний от зап­роса к зап­росу и лег­ко добав­ляемый заголо­вок X-Stepper-Execute-Before:, который запус­кает Stepper для любого модуля.

Проб­лемы:

  • на самом деле Stepper не поз­воля­ет исполь­зовать так мно­го потоков, как хотелось бы. Око­ло трех потоков дей­стви­тель­но успе­вают работать вмес­те, но из‑за осо­бен­ностей кода модуля боль­шее их количес­тво толь­ко тор­мозит выпол­нение;
  • при­ходит­ся вруч­ную нас­тра­ивать перемен­ные для каж­дого зап­роса, что может выг­лядеть изну­ряюще скуч­но.

Дан­ный пла­гин под­ходит ско­рее для исполь­зования его с модулем Repeater, о чем раз­работ­чики пре­дуп­режда­ли нас в при­ветс­твен­ном сооб­щении.

Способ 3. Использование плагина Turbo Intruder

Turbo Intruder — один из самых мощ­ных инс­тру­мен­тов Burp Suite, и его дол­жен осво­ить каж­дый ува­жающий себя поль­зователь Burp. Его так­же мож­но ска­чать с GitHub.

Turbo Intruder пред­став­ляет собой рас­ширение Burp Suite для отправ­ки боль­шого количес­тва зап­росов HTTP и ана­лиза резуль­татов. Оно приз­вано допол­нить Burp Intruder, обра­баты­вая ата­ки, тре­бующие исклю­читель­ной ско­рос­ти, про­дол­житель­нос­ти или слож­ности. Этот модуль отли­чают сле­дующие осо­бен­ности.

  • Быс­тро­та: Turbo Intruder исполь­зует стек HTTP, соз­данный вруч­ную с нуля с уче­том ско­рос­ти. В резуль­тате на мно­гих целях он может серь­езно обог­нать даже мод­ные асин­хрон­ные скрип­ты на Go (на самом деле стек мож­но выб­рать, и боль­шинс­тво из них будут тебе зна­комы).
  • Мас­шта­биру­емость: Turbo Intruder может дос­тичь плос­кого исполь­зования памяти, что поз­воля­ет про­водить надеж­ные мно­год­невные ата­ки. Его так­же мож­но запус­кать в headless-окру­жении через коман­дную стро­ку.
  • Гиб­кость: ата­ки кон­фигури­руют­ся с помощью Python. Это поз­воля­ет выпол­нять слож­ные тре­бова­ния, нап­ример под­писан­ные зап­росы и мно­гос­тупен­чатые пос­ледова­тель­нос­ти атак. Кро­ме того, поль­зователь­ский стек HTTP поз­воля­ет обра­баты­вать неп­равиль­но сфор­мирован­ные зап­росы, которые лома­ют дру­гие биб­лиоте­ки.
  • Удобс­тво: скуч­ные резуль­таты могут быть авто­мати­чес­ки отфиль­тро­ваны с помощью усо­вер­шенс­тво­ван­ного алго­рит­ма дифов, адап­тирован­ного из Backslash Powered Scanner. Это озна­чает, что ты можешь запус­тить ата­ку и получить полез­ные резуль­таты в два кли­ка.

Для исполь­зования Turbo Intruder необ­ходимо зна­ние основ Python. Тем не менее все, что нам нуж­но для начала, — это уста­новить Turbo Intruder из модуля Extender.

Пос­ле уста­нов­ки сра­зу же перей­дем к решению задачи.

  1. Вы­берем самый пер­вый пакет в пос­ледова­тель­нос­ти во вклад­ке Proxy (пакет GET /login) и наж­мем на него пра­вой кноп­кой мыши. А даль­ше выберем пункт Extensions → Send to turbo intruder.
  2. В открыв­шей­ся панели Turbo Intruder появит­ся зап­рос и при­меры скрип­тов, которые мож­но выб­рать для исполь­зования и модифи­кации. В дан­ном слу­чае все, что нам нуж­но для победы, — это написать скрипт, который поз­волит решить задание. Ниже я при­веду свой при­мер кода и объ­ясню логику скрип­та (сде­лай мне скид­ку на качес­тво, вспом­нив о том, что пен­тесте­ры не уме­ют кодить):

import re

import time

# Регулярки для вытаскивания идентификаторов сессии и CSRF-токенов

re_csrf = 'name="csrf" value="([\w\d]+)"'

re_session = 'session=([\d\w]+)'

iterable = 0

def queueRequests(target, wordlists):

global engine

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

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

engine = RequestEngine(endpoint='https://ac051f441e762a3780359cb6002300a2.web-security-academy.net:443',concurrentConnections=5,requestsPerConnection=1)

# Запускаем первые запросы, которые спровоцируют запуск последующих запросов.

# Делаем задержку в одну секунду, чтобы потоки не исполнялись синхронно, а чередовались.

for x in xrange(1,6):

print '1. GET /login Request'

engine.queue(target.req,'')

time.sleep(1)

def handleResponse(req, interesting):

global engine

global iterable

if 'Location: /my-account' in req.response:

# Если мы в ответе получили данный заголовок, значит, мы победили

table.add(req)

print 'You Win!'

return None

if 'Incorrect security code' in req.response:

# Если мы получили в ответе сообщение о неправильно введенном коде, значит, мы использовали одну попытку, и тогда мы запускаем новую итерацию запросов

table.add(req)

print '1. GET /login Request'

engine.queue(target.req,'')

return None

if 'Please enter your 4-digit security code' in req.response:

# Если в ответе мы получаем предложение ввести ОТР, то отправляем запрос с попыткой ввода ОТР

match_csrf = re.search(re_csrf, req.response)

match_session = re.search(re_session, req.getRequest())

req = '''POST /login2 HTTP/1.1\r\nHost: ac051f441e762a3780359cb6002300a2.web-security-academy.net\r\nCookie: session=%s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 51\r\n\r\ncsrf=%s&mfa-code=%s'''

print '4. POST /login2 Request'

engine.queue(req, [match_session.group(1),match_csrf.group(1),str(iterable).zfill(4)])

iterable += 1

print 'Iterable: ' + str(iterable)

return None

if 'Location: /login2' in req.response:

# Если в ответе мы получаем сообщение о переходе на страницу /login2, значит, мы ранее ввели корректные креды и теперь получаем новый идентификатор сессии и переходим на страницу для взятия CSRF для запроса с OTP

match_session = re.search(re_session, req.response)

req = '''GET /login2 HTTP/1.1\r\nHost: ac051f441e762a3780359cb6002300a2.web-security-academy.net\r\nCookie: session=%s\r\n\r\n'''

print '3. GET /login2 Request'

engine.queue(req, match_session.group(1))

return None

if '<form class=login-form method=POST action=/login>' in req.response:

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

match_session = re.search(re_session, req.response)

match_csrf = re.search(re_csrf, req.response)

req = '''POST /login HTTP/1.1\r\nHost: ac051f441e762a3780359cb6002300a2.web-security-academy.net\r\nCookie: session=%s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 70\r\n\r\ncsrf=%s&username=carlos&password=montoya'''

print '2. POST /login Request'

engine.queue(req, [match_session.group(1),match_csrf.group(1)])

return None

Так как в Turbo Intruder нет воз­можнос­ти удоб­но под­держи­вать сес­сию меж­ду зап­росами, при­ходит­ся делать это руками, соз­давая новые зап­росы на осно­ве иден­тифика­торов сес­сии, получен­ных из пре­дыду­щих зап­росов.

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

При помощи дан­ного скрип­та мне уда­лось выпол­нить 400 попыток (~1500 зап­росов) за 30 секунд и решить задание при­мер­но в 20 раз быс­трее, чем в прош­лых при­мерах. Если быть чес­тным, то мож­но было пот­ратить чуть боль­ше вре­мени на калиб­ровку парамет­ров concurrentConnectionsrequestsPerConnection и pipeline и решить задачу еще быс­трее, но мне хва­тило и это­го.

Под­ведем ито­ги для это­го при­мера.

Воз­можнос­ти:

  • Turbo Intruder может выжать из при­ложе­ния мак­сималь­ную ско­рость;
  • пос­коль­ку мы пишем код на Python, мож­но заложить в инс­тру­мент логику поч­ти любой слож­ности;
  • край­не удоб­но филь­тро­вать выпол­ненные зап­росы в таб­лице резуль­татов, а так­же мож­но задавать свои поля к зап­росам для сор­тиров­ки и филь­тра­ции.

Проб­лемы:

  • нуж­но писать код, и это мало отли­чает­ся от написа­ния скрип­тов с нуля, хоть и дает боль­шое пре­иму­щес­тво в исполь­зовании под­готов­ленных абс­трак­ций для мно­гопо­точ­ного и парал­лель­ного выпол­нения зап­росов;
  • нет докумен­тации к инс­тру­мен­ту, кро­ме ряда при­меров, которых тебе дол­жно хва­тить;
  • в наибо­лее быс­трых движ­ках зап­росов для Intruder зап­росы и отве­ты не логиру­ются в модули Logger или Logger++, что не поз­воля­ет удоб­но прос­матри­вать про­исхо­дящее в сети. При­ходит­ся исполь­зовать спо­собы отладки, встро­енные в сам Turbo Intruder и его абс­трак­ции.

ЗАКЛЮЧЕНИЕ

Лич­но мне импо­ниру­ет инс­тру­мент Turbo Intruder, но для нович­ков модуль Stepper или встро­енные мак­росы могут ока­зать­ся про­ще в исполь­зовании. Тем не менее для реаль­ных задач мак­росы и Stepper могут не подой­ти из‑за сво­ей мед­литель­нос­ти.

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






Report Page