Как искать уязвимости сайтов

OWASP Juice Shop

Если вы хороший программист, то наверное у вас появлялась мысль — заняться поиском уязвимостей сайтов (в веб-приложениях) и заработать на программе Bug bounty. Это хорошая идея, но для начала не плохо бы попрактиковаться в поиске уязвимостей на сайтах и сделать это не нарушая закон. В этом поможет поможет площадка Juice Shop, соз­данная спецами OWASP.

Еще по теме: Инструменты для поиска уязвимостей при участии в Bug Bounty

Сегодня я покажу, как установить и использовать OWASP Juice Shop для поиска уязвимостей веб-приложений. Погнали!

Установка и запуск OWASP Juice Shop

Установить Juice Shop можно по разному, я предпочитаю и рекомендую сделать это с помощью Node.js, так как Docker есть не все воз­можные уяз­вимос­ти.

Ни­ког­да не при­меняйте такие вещи в реаль­ных интернет‑магази­нах! Это уго­лов­но наказу­емо прак­тичес­ки во всех стра­нах. Исклю­чени­ем может быть учас­тие магази­на в прог­рамме bug bounty, но там мно­го раз­ных нюан­сов, с которы­ми нуж­но озна­комить­ся до начала поиска уязвимостей на сайте!

Установка Node.js

Juice Shop работает с раз­ными релизами Node.js. На сегодня последняя версия — LTS (Long Term Support) Node.js 14, ее и поставим. Для начала установим Node Version Manager. Он был создан для того чтобы не зах­ламлять свою операционную систему пакета­ми и иметь воз­можность исполь­зовать раз­личные релизы.

На момент написания статьи последняя версия — 0.38. Уста­нов­ка Node Version Manager выпол­няет­ся одной коман­дой в домаш­ней пап­ке.

$curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash

Те­перь необходимо открыть и зак­рыть тер­минал, что­бы при­мени­ть изменения вне­сен­ные скрип­том .

Про­верьте уста­нов­ленную вер­сию nvm и перехо­дите непос­редс­твен­но к уста­нов­ке Node.js.

$nvm -v
$nvm install --lts

Про­верьте вер­сию уста­нов­ленной коман­ды node и запом­ните ее.

$node --version

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

$nvm install <номер версии>
$nvm use <номер версии>

Установка OWASP Juice Shop

В GitHub часто появляются новые релизы, поэтому всег­да качайте самый последний. Но не забудьте, он дол­жен быть сов­мести­мым с вашим Node.js. Если на пре­дыду­щем эта­пе вы уста­новили Node.js 14, то вам будет нужен juice-shop-xx.x.x_node14_linux_x64.tgz. Ска­чайте и рас­пакуй его.

$tar -xzf juice-shop-xx.x.x_node14_linux_x64.tgz

На этом уста­нов­ка завер­шена. Передем в пап­ку с Juice Shop и запус­каему его:

$npm start

Ес­ли установка прошла хорошо, вы уви­дите сооб­щение «info: Server listening on port 3000». Откройте свой бра­узер и зайдите на http://localhost:3000. С права вверху выберите английский язык. Почему английский? Так в будущем не возникнут проб­лемы перево­да всяких тер­минов.

Настройка Burp Suite

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

Еще по теме: Лучшие расширения для Burp Suite

Поиск доски с заданиями

Вы навер­ное при пер­вом запус­ке уже заметили пакет с соком, пред­лага­ющий решить очень прос­тую задачу, а имен­но най­ти дос­ку с задани­ями и резуль­татами, она же Score Board. У этой край­не прос­той задачи есть два вари­анта решения.

  1. Вни­матель­но пос­мотрите на адресную стро­ку вида /#/search, /#/login и так далее и подумайте, а какой бы была стро­ка для дос­тупа к Score Board? Сра­зу ска­жу, этот вари­ант мне не очень нра­вит­ся, пос­коль­ку нуж­но играть в уга­дай­ку, и не всег­да успешно. Поэто­му я пред­почитаю вари­ант номер два.
  2. Да­вайте изу­чим исходный код сай­та и пос­мотрим, нет ли там чего инте­рес­ного. Я наде­юсь, вы уме­ете читать исходный код сай­та в сво­ем любимом бра­узе­ре? В Firefox дос­таточ­но прос­то нажать F12.
Ис­ходный код глав­ной стра­ницы Juice Shop
Ис­ходный код глав­ной стра­ницы Juice Shop

Что сра­зу же бро­сает­ся в гла­за? Огромное количес­тво под­клю­чаемых скрип­тов на JS! Нас будет инте­ресо­вать скрипт main. За что отве­чают дру­гие скрип­ты, вы можете выяс­нить на досуге с помощью любимых анонимных поис­ковиков.

Те­перь перехо­дим во вклад­ку Debugger и смот­рим на исходный код main. Выг­лядит не очень, прав­да? Тут есть два пути: или пытать­ся вос­ста­новить код пос­ле миними­зато­ра JS c помощью одно­го из мно­жес­тва сай­тов‑деоб­фуска­торов или прос­то выб­рать в Firefox (клик­нув по зак­ладке с наз­вани­ем фай­ла) Pretty print source и получить более чита­емый исходный код. Для наших целей пока хва­тит и это­го.

Код вну­шитель­ный. Это пло­хо и хорошо одновре­мен­но. Обыч­но это говорит о том, что очень мно­го логики сай­та вынес­ли в кли­ент­ский JavaScript, а зна­чит, ее мож­но будет лег­ко обой­ти прос­тым дебаг­гером. Най­дем же наконец Score Board. Как эффектив­нее искать в исходни­ках, каж­дый реша­ет сам, но в резуль­тате вы дол­жны доб­рать­ся до кус­ка с уже зна­комы­ми вам мар­шру­тами вро­де /#/search.

Мар­шрут к Score Board
Мар­шрут к Score Board

Вби­вайте в адресную стро­ку:

http://localhost:3000/#/score-board

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

Вы­пол­ненное пер­вое задание
Пер­вое задание выполнено
На прос­торах интерне­та и в YouTube есть пол­ные решения всех задач Juice Shop. Кро­ме того, вы всег­да можете почитать под­робное объ­ясне­ние поч­ти каж­дого задания с решени­ем в кни­ге раз­работ­чиков, но я рекомен­дую смот­реть решение толь­ко в самом край­нем слу­чае. Более того, некото­рые задачи мож­но решить совер­шенно раз­ными метода­ми.

В вер­сии Juice Shop 12.7.0 появи­лась замеча­тель­ная фун­кция — теперь, нажав кноп­ку с тре­уголь­ными скоб­ками, мож­но уви­деть исходный код уяз­вимого модуля и стро­ку, в которой и про­исхо­дит ошиб­ка. Прос­то срав­ните исходный код до миними­зации и тот, что вы уви­дели в бра­узе­ре. Воз­можно, вы най­дете новые инте­рес­ные мар­шру­ты, скры­тые от вас интерфей­сом сай­та.

Кста­ти, на скрин­шоте выше у меня уже выпол­нено два задания. Я прос­то задал­ся воп­росом, а что будет, если поп­робовать открыть мар­шрут /#/complain, не регис­три­руясь на сай­те? Вы же пом­ните, что без вхо­да в учет­ную запись его нет в левом меню? Поп­робуйте открыть его как гость и отпра­вить ано­ним­ную жалобу! Получили новую ачив­ку? Вот так делать не сто­ит и всег­да нуж­но учи­тывать, что любой мар­шрут может быть открыт прос­тым набором нуж­ного адре­са в адресной стро­ке. О том, почему не сто­ит доверять совер­шенно ничему, при­шед­шему вам по сети, я покажу чуть поз­же.

Открытие админки

Преж­де чем бро­сать­ся с головой выпол­нять задания, я рекомен­дую вни­матель­но озна­комить­ся с содер­жимым дос­ки. Все задания на ней раз­делены по уров­ню слож­ности от одной до шес­ти звез­дочек. Деление дос­таточ­но условное. Нап­ример, нуж­но сооб­щить магази­ну об исполь­зовании «сла­бой» крип­тогра­фии. Сама по себе задача реша­ется прос­той отправ­кой в чат наз­вания уяз­вимого алго­рит­ма, вот толь­ко узнать и опре­делить эти алго­рит­мы мож­но, выпол­няя задания более высоко­го уров­ня слож­ности. Поэто­му не ста­рай­тесь выпол­нить все задания одно­го уров­ня слож­ности и лишь потом перехо­дить к дру­гому. Я рекомен­дую руководс­тво­вать­ся катего­риями (кста­ти, вы заметили их уди­витель­ную схо­жесть с OWASP Top 10?). Теги нап­ротив каж­дого задания могут показать вам вер­ное нап­равле­ние поис­ка.

Не­кото­рые задания име­ют под­сказ­ку или тутори­ал. Поп­робуйте вна­чале обой­тись без помощи. Одна­ко некото­рые задания нас­толь­ко туман­ны, что есть смысл почитать более под­робное опи­сание в кни­ге раз­работ­чиков. Вот, к при­меру, ка­тего­рия «Раз­нооб­разное».

Дос­ка с задани­ями Juice Shop
Дос­ка с задани­ями Juice Shop

Те­перь давайте перей­дем к поис­ку админки и попыта­емся в нее попасть. Наде­юсь, вы еще не забыли мес­то, где мы наш­ли адрес Score Board? Там же мож­но обна­ружить и адрес админки! Одна­ко при попыт­ке перей­ти по это­му адре­су нас встре­тит крас­ный бан­нер с ошиб­кой 403… Самое вре­мя запус­тить Burp Suite и пос­мотреть на сетевой обмен.

Се­тевой обмен при дос­тупе к админке
Се­тевой обмен при дос­тупе к админке

Уди­витель­но, но ничего похоже­го на дос­туп к админке тут нет! Пом­ните про огромный раз­мер скрип­та main? Навер­няка вся про­вер­ка дос­тупа обра­баты­вает­ся в нем. Вре­мя порабо­тать с дебаг­гером. Про­ще все­го най­ти нуж­ное мес­то в коде по ошиб­ке дос­тупа — 403.

Ис­ходный код про­вер­ки прав дос­тупа
Ис­ходный код про­вер­ки прав дос­тупа

Ви­дите пер­вую и вто­рую фун­кцию CanActivate()? Если у нас нет токена или нам зап­рещен дос­туп, то мы получа­ем ошиб­ку 403. Что­бы сок­ратить количес­тво скрин­шотов, сра­зу ска­жу — при­дет­ся зарегис­три­ровать­ся. У незаре­гис­три­рован­ных поль­зовате­лей токена дос­тупа нет. Так что самое вре­мя вой­ти под соз­данным ранее поль­зовате­лем или соз­дать нового.

Те­перь давайте поп­робу­ем обма­нуть скрипт. Для это­го уста­новим точ­ку оста­нова (breakpoint) на стро­ке 579 и добавим в Watch перемен­ную t.

Ус­танов­ка точ­ки оста­нова
Ус­танов­ка точ­ки оста­нова

Про­буйте открыть стра­ницу с админкой еще раз. Пом­ните, для того что­бы точ­ка оста­нова сра­бота­ла, у вас обя­затель­но дол­жна быть откры­та отла­доч­ная кон­соль!

Дан­ные токена t
Дан­ные токена t

Те­перь оста­лось самое прос­тое. Скрипт выше про­веря­ет, соот­ветс­тву­ет ли роль зна­чению admin. Если нет, вы увидите ошиб­ку дос­тупа. Поэто­му вам прос­то нуж­но испра­вить зна­чение роли на admin. К сожале­нию, с появ­лени­ем новой кон­соли раз­работ­чика в Firefox воз­можность редак­тирова­ния перемен­ных в окне прос­мотра сло­мали и пока так и не вер­нули… Запом­ните путь к нуж­ному зна­чению t.data.role, перек­лючитесь в окне раз­работ­чика на вклад­ку Console и поменяйте там зна­чение роли на admin.

Из­меня­ем зна­чение роли
Из­меня­ем зна­чение роли

Те­перь вер­нитесь в отладчик и про­дол­жите исполне­ние скрип­та. Поз­драв­ляю, вы получите дос­туп к адми­нис­тра­тив­ной час­ти сай­та! Почему так про­изош­ло? Нель­зя наде­ять­ся на кон­троль дос­тупа на уров­не кли­ент­ско­го кода, пос­коль­ку кли­ент всег­да может этот код изме­нить. Кста­ти, это решение по уров­ню слож­ности тянет звез­дочки на три. Чуть поз­же вы зарегис­три­руете нор­маль­ную админ­скую учет­ку и вос­поль­зуетесь SQLi для дос­тупа к админке. Они нам­ного про­ще, так как не тре­буют изу­чения исходно­го кода.

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

Ес­ли вы не вык­лючили Burp, то можете най­ти эти стро­ки в обме­не и убе­дить­ся, что про­вер­ка прав дос­тупа на сер­верной сто­роне не про­исхо­дит! Отку­да это мож­но понять? Видите куку token? Это так называ­емый тoкен JWT, и его мож­но лег­ко рас­кодиро­вать.

Зап­росы к сер­веру
Зап­росы к сер­веру
JWT-токен
JWT-токен

В этом токене, по сути, содер­жится весь про­филь поль­зовате­ля и явно ука­зана его ори­гиналь­ная роль customer, одна­ко сер­верный бэкенд не про­веря­ет пра­ва при зап­росе всех отзы­вов или про­филей. Это зна­чит, что, перех­ватив такой зап­рос, вы можете лег­ко получать информа­цию о зарегис­три­рован­ных поль­зовате­лях, даже не откры­вая админку. Если вы раз­работ­чик, никог­да так не делайте! Это яркий при­мер Broken Access Control по клас­сифика­ции OWASP. К сожале­нию, и в реаль­ной жиз­ни он встре­чает­ся на каж­дом шагу… Осо­бен­но этим гре­шат мик­росер­висные архи­тек­туры.

Регистрация учетной записи администратора

Са­мое вре­мя зарегис­три­ровать себе пол­ноцен­ную учет­ную запись адми­нис­тра­тора! Для это­го нуж­но разоб­рать­ся, какая же информа­ция отправ­ляет­ся при регис­тра­ции обыч­ной учет­ной записи с сай­та. В этом вам поможет Burp Suite. Запус­кайте его и про­ходите про­цесс регис­тра­ции пол­ностью.

Ре­гис­тра­ция нового поль­зовате­ля
Ре­гис­тра­ция нового поль­зовате­ля

Как видите, отпра­вив информа­цию из фор­мы, в ответ вы получите про­филь поль­зовате­ля с ролью customer. Одна из тра­дици­онных оши­бок раз­работ­чика свя­зана с так называ­емым mass assignment, или мас­совым запол­нени­ем полей. Код регис­тра­ции поль­зовате­ля при­нима­ет спи­сок полей про­филя для обра­бот­ки, а для отсутс­тву­ющих полей наз­нача­ется зна­чение по умол­чанию. Видите пус­тое поле username в отве­те? Поп­робуйте перех­ватить этот зап­рос до отправ­ки и вста­вить в него поле username, как на скрин­шоте ниже.

Из­менен­ный зап­рос на соз­дание поль­зовате­ля
Из­менен­ный зап­рос на соз­дание поль­зовате­ля

А теперь вни­матель­но пос­мотрите на ответ сер­вера! Видите наше изме­нен­ное имя поль­зовате­ля в отве­те? Кро­ме того, оно боль­ше не воз­вра­щает­ся пер­вой стро­кой в дан­ных. Наде­юсь, вы поняли, что нуж­но сде­лать со зна­чени­ем поля role. Про­делайте эту прос­тую опе­рацию, и админ­ская учет­ка у вас в кар­мане, как и оче­ред­ное выпол­ненное задание! Кста­ти, оно офи­циаль­но тоже зас­читыва­ется за три звез­дочки.

От­вет сер­вера на изме­нен­ные дан­ные
От­вет сер­вера на изме­нен­ные дан­ные

Использование SQL-инъекции для входа

Я очень наде­юсь, вы не раз слы­шали об SQL-инъ­екци­ях и при­чинах их воз­никно­вения. Если нет, то самое вре­мя отпра­вить­ся изу­чать теорию. Мне очень нра­вит­ся об­ширный спра­воч­ник по инъ­екци­ям. Откройте окно логина поль­зовате­ля и нач­ните с самого прос­того, вста­вив оди­нар­ную обратную кавыч­ку в поле логина и про­изволь­ный пароль. Судя по ярко‑крас­ной ошиб­ке, мы на пра­виль­ном пути!

SQL-инъ­екция
SQL-инъ­екция

К сожале­нию, совер­шенно непонят­но, что же имен­но про­исхо­дит и как даль­ше раз­вивать эту инъ­екцию. Здесь есть два вари­анта решения: либо вы обла­даете боль­шим опы­том инъ­екций и пла­номер­но под­бира­ете нуж­ные зна­чения, либо, если это не о вас, запус­кайте Burp и смот­рите, что же про­исхо­дит в сети. Пом­ните, это очень уяз­вимое при­ложе­ние, и навер­няка раз­работ­чики допус­тили не одну ошиб­ку…

Ошиб­ка при работе с базой
Ошиб­ка при работе с базой

Кто бы сом­невал­ся, тут даже есть код ори­гиналь­ного SQL-зап­роса. Теперь подоб­рать пра­виль­ную наг­рузку для окна логина не сос­тавит осо­бого тру­да!

Ус­пешный вход от име­ни адми­нис­тра­тора
Ус­пешный вход от име­ни адми­нис­тра­тора

Здесь я дол­жен сде­лать нес­коль­ко важ­ных замеча­ний.

  1. Вы ниг­де не ука­зали поч­ту, но вошли как адми­нис­тра­тор. Это про­изош­ло потому, что в этом вари­анте инъ­екции выбира­ется пер­вая стро­ка в базе, она же чаще все­го будет пер­вым зарегис­три­рован­ным поль­зовате­лем или суперад­минис­тра­тором. Такое поведе­ние есть в боль­шинс­тве CMS.
  2. Ес­ли у вас есть адрес поч­ты инте­ресу­юще­го вас поль­зовате­ля, то вы можеыр нем­ного модифи­циро­вать инъ­екцию и вой­ти сра­зу же от его лица.
  3. Это самый прос­той и яркий при­мер клас­са Injection. Недаром они сто­ят на пер­вом мес­те по клас­сифика­ции ОWASP.
  4. В коде при­ложе­ния еще мно­го мест с инъ­екци­ями, как и задани­ями на нее, но они уже слож­нее по уров­ню исполне­ния и наноси­мому уро­ну. Нап­ример, мож­но получить всю базу дан­ных вмес­те с пароля­ми поль­зовате­лей!

Подбор пароля администратора

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

Ка­кие же ошиб­ки в реали­зации аутен­тифика­ции допус­тили раз­работ­чики это­го при­ложе­ния? А все самые популяр­ные из раз­дела Broken Authentication:

  • от­сутс­тву­ет защита от перебо­ра пароля;
  • поль­зователь может уста­новить сла­бый пароль;
  • поль­зователь может уста­новить прос­той, как раз‑два‑три, пароль…

Вы можете поп­робовать прос­то уга­дать пароль адми­нис­тра­тора, это не так слож­но, как кажет­ся на пер­вый взгляд (или наж­мите кноп­ку Tutorial, и пакет с соком вам поможет). Кро­ме того, я оста­вил вам неболь­шую под­сказ­ку в пре­дыду­щем абза­це. Я же покажу, как мож­но решить эту задачу с помощью перебо­ра и спис­ка популяр­ных паролей rockyou.txt.

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

Зап­рос с неп­равиль­ным паролем
Зап­рос с неп­равиль­ным паролем

Как видите, для логина дос­таточ­но отпра­вить JSON с дву­мя полями, если пароль неп­равиль­ный — вам вер­нется код 401. Тут я поп­робовал нас­тро­ить самый извес­тный под­борщик паролей Hydra, но пос­ле получа­са борь­бы с ним прос­то написал вот такой неболь­шой код на Python.

Де­ло в том, что Hydra очень не любит JSON и некото­рые нюан­сы поведе­ния это­го при­ложе­ния. Если хотите, можете сами поп­робовать решить эти проб­лемы.
import requests
passwords = open('/usr/share/wordlists/rockyou.txt','r')
for password in passwords:
    password = password.rstrip("\n")
    data = {'email':'admin@juice-sh.op','password':password}
    r = requests.post('http://localhost:3000/rest/user/login',json=data)
    if r.status_code == 200:
        print("Password is ",password)
        break
print("That's all... ")

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

Получе­ние Deluxe Membership бесплатно

На­пос­ледок я покажу вам, как мож­но решить более слож­ную задачу, а имен­но получе­ние Deluxe Membership бес­плат­но!

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

Сто­имость Deluxe Membership
Сто­имость Deluxe Membership

Пос­ле это­го на сле­дующем экра­не вы смо­жете опла­тить 0 из кошель­ка, но почему‑то это так прос­то не получит­ся… Если пос­мотреть обмен, то уви­дите пла­теж из кошель­ка и ошиб­ку «недос­таточ­но денег».

Поиск уязвимости на сайтах
Ошиб­ка пла­тежа из кошель­ка

А что, если заменить paymentMode на что‑то более инте­рес­ное, нап­ример free или deluxe?

Установка Juice Shop
Бес­плат­ный Deluxe Membership

Поз­драв­ляю! Вы толь­ко что обма­нули магазин на 49 условных еди­ниц. Более того, если вы вни­матель­но поэк­спе­римен­тиру­етес раз­ными вари­анта­ми опла­ты, то выяс­ните, что менять цену на 0 на пер­вом эта­пе совер­шенно необя­затель­но. Глав­ное — прев­ратить GET-зап­рос /rest/deluxe-membership в POST-зап­рос и добавить в него JSON-дан­ные paymentMode с любым отличным от wallet или card зна­чени­ем.

Выводы

Очень наде­юсь, что эта статья под­тол­кну­ла вас к более глу­боко­му изу­чению рекомен­даций OWASP и типовых оши­бок веб‑при­ложе­ний. В Juice Shop еще мно­го инте­рес­ных задач как для начина­ющих, так и для опыт­ных пен­тесте­ров. Я же про­щаюсь с вами до сле­дующей статьи, в которой вы поп­робу­ете решить задачи с боль­шим количес­твом звез­дочек!

Еще по теме: Обзор лучших сканеров уязвимостей

ВКонтакте
OK
Telegram
WhatsApp
Viber

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *