Взлом сайта на Django

Django взлом

Сегодня, с помощью слож­ной машины Developer с пло­щад­ки Hack The Box, я покажу как взломать сай­т на Django. Кро­ме того, вы узнаете как вытащить пароль с фай­ла XLS и при­менить фишин­говую ата­ку Tab Nabbing.

Еще по теме: Взлом сайта на PHP эксплуатируя уязвимость XXE

Взлом сайта на Django

Для начала до­бав­им IP-адрес машины в /etc/hosts:

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

Самый популярный сканер — это Nmap. Следующий скрипт улучшит резуль­таты сканирования:

Он дей­ству­ет в два эта­па. На пер­вом про­изво­дит­ся обыч­ное быс­трое ска­ниро­вание, на вто­ром — более тща­тель­ное ска­ниро­вание, с исполь­зовани­ем име­ющих­ся скрип­тов (опция -A).

Ре­зуль­тат работы скрип­та
Работ скрипта Nmap

Скрипт находит два откры­тых пор­та:

  • 80 — отве­чает за веб
  • 22 — на нем работа­ет SSH

Справка: брут учетых записей

Нет смысле изучать службы, пос­коль­ку у нас пока нет учет­ных дан­ных, которые всег­да тре­буют авто­риза­цию (нап­ример, SSH). Единс­твен­ное, что можно сделать — это переби­рать пароли брут­ом, но у машин с Hack The Box поч­ти всег­да есть дру­гое сценарий прохождения. В  реальности таких вари­антов может не быть, к тому же есть шан­сы подоб­рать пароль или добыть его с помощью соци­аль­ной инже­нерии.

На­чина­ем, разумеется, с веба!

Глав­ная стра­ница сай­та Django Developer Hack The Box
Глав­ная стра­ница сай­та Django Developer Hack The Box

Нас встре­чает сайт какой‑то пло­щад­ки CTF (Capture The Flag). Видим воз­можность регис­тра­ции и авто­риза­ции, но, что интересно, нет ни одно­го фай­ла на PHP. Может, это фрей­мворк на Python? Проверим догад­ку, прос­канировав скры­тые дирек­тории в кор­невом катало­ге сай­та.

Справка: сканирование веба c ffuf

Пер­вое дей­ствие при тес­тирова­нии безопас­ности веб‑при­ложе­ния — это ска­ниро­вание методом перебо­ра катало­гов. Для это­й цели вы можете исполь­зовать прог­раммы вро­де DIRB и dirsearch.

Мне нравится лег­кий и очень быс­трый ffuf. Параметры запуска:

  • -w — сло­варь (лично я предпочитаю сло­вари из SecLists);
  • -fc — исклю­чить из резуль­тата отве­ты с кодом 403;
  • -u — URL;
  • -t — количес­тво потоков.

Ко­ман­да выходит сле­дующая:

Ска­ниро­вания катало­гов
Ска­ниро­вания катало­гов

В выводе будет очень мно­го катало­гов с кодом 301 — редирект. При переходе по ним, то нас встречает админка фрей­мвор­ка Django.

Авто­риза­ция Django
Авто­риза­ция Django

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

Глав­ная панель поль­зовате­ля
Админка

На вебсай­те лежит по два‑три тас­ка из раз­ных катего­рий, но меня заинтересовала стра­ница с нас­трой­ками про­филя поль­зовате­ля.

Ска­нирование тек­сто­вых полей не дает никакого резуль­тата. Поп­робу­ем сдать любой из тас­ков. Я решил прос­мотреть задание на форен­зику phished_credentials. По усло­виям задания, где‑то в фай­ле находится пароль.

Точка входа

После открытия файла, видим скры­тый стол­бец E. Раз­дви­нуть стол­бцы не получается, так как докумен­т защищен паролем от изменения.

Со­дер­жимое phished_credentials.xls
Со­дер­жимое phished_credentials.xls

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

Со­дер­жимое архи­ва
Со­дер­жимое архи­ва

В данном фай­ле находим и уда­ляем эту стро­ку (поле sheetProtection):

По­ле sheetProtection
По­ле sheetProtection

Сохраняем файл и открываем документ. Теперь защиты нет. Раз­дви­гаем стол­бец E и находим флаг для пло­щад­ки.

Флаг для задания
Флаг для задания

Ос­талось ввести его в фор­му на сай­те.

От­прав­ка фла­га
От­прав­ка фла­га

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

Стра­ница чел­лен­джа
Стра­ница чел­лен­джа

При­чем не через заг­рузку фай­ла, а с помощью ука­зания URL стра­ницы.

Фор­ма заг­рузки решения
Фор­ма заг­рузки решения

Открываем локаль­ный веб‑сер­вер Python 3 (коман­да python3 -m http.server 80) и отпра­вяем ссыл­ку:

В логах веб‑сер­вера находим обра­щение к ука­зан­ной стра­нице. Это мес­то для тес­та!

Ло­ги веб‑сер­вера
Ло­ги веб‑сер­вера

Ко все­му про­чему решение отоб­ража­ется на стра­нице про­филя.

Про­филь текуще­го поль­зовате­ля
Про­филь текуще­го поль­зовате­ля

Вот толь­ко если попытать­ся прос­мотреть его, оно откро­ется в новой вклад­ке. В исходном коде стра­ницы находим атри­бут target="_blank" в теге <а>.

Ис­ходный код стра­ницы
Ис­ходный код стра­ницы

Ког­да аргу­мент href тега <а> с атри­бутом target="_blank" нам под­кон­тро­лен и целевой поль­зователь может перей­ти по ссыл­ке, есть шанс ука­зать там фишин­говый сайт.

Как толь­ко поль­зователь наж­мет ссыл­ку, с помощью объ­екта window.opener мы перенап­равля­ем его на наш вре­донос­ный ресурс, который будет содер­жать клон легитим­ной стра­ницы авто­риза­ции. Это дол­жно зас­тавить поль­зовате­ля вбить свои учет­ные дан­ные. Эта тех­ника фишин­га называ­ется Tab Nabbing.

Соз­дадим в катало­ге веб‑сер­вера файл writeup.html со сле­дующим содер­жимым.

Этот код дол­жен открыть стра­ницу login.html на нашем сер­вере. Теперь кло­ниру­ем стра­ницу авто­риза­ции на сай­те. Для это­го я исполь­зую рас­ширение SingleFile для бра­узе­ра Firefox, поз­воля­ющее сох­ранить всю стра­ницу в еди­ном HTML-фай­ле.

Сох­раним файл как login.html и нем­ного изме­ним его код. Ука­зыва­ем атри­буты action="auth.php" и method="get".

Исходный код фишинговой страницы
Исходный код фишинговой страницы

Те­перь сно­ва отпра­вим решение задания и в логах веб‑сер­вера уви­дим его зап­рос, затем перенап­равле­ние на login.html и отправ­ку учет­ных дан­ных на auth.php.

Ло­ги веб‑сер­вера
Ло­ги веб‑сер­вера

Эти учет­ные дан­ные поз­воля­ют авто­ризо­вать­ся в админке Django.

Па­нель адми­нис­три­рова­ния Django
Па­нель адми­нис­три­рова­ния Django

Точка опоры

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

Спи­сок поль­зовате­лей
Спи­сок поль­зовате­лей
Спи­сок сай­тов
Спи­сок сай­тов

Так как мы получи­ли новое домен­ное имя, сра­зу добавим его в /etc/hosts. Теперь наша запись будет выг­лядеть так:

А на самом сай­те Sentry нас встре­тит фор­ма авто­риза­ции.

Фор­ма авто­риза­ции Sentry
Фор­ма авто­риза­ции Sentry

У нас есть пароль адми­нис­тра­тора одно­го сер­виса, высока веро­ятность, что этот пароль подой­дет и тут. Воп­рос лишь в име­ни поль­зовате­ля. Логин admin ока­зал­ся невер­ным; если впи­сать пол­ную поч­ту admin@developer.htb или admin@developer.ctf, тоже ничего не получа­ем. Но у адми­нис­тра­тора ука­зано имя James. Про­буем поч­ту james@developer.htb и получа­ем дос­туп к сай­ту.

Глав­ная стра­ница сай­та
Глав­ная стра­ница сай­та

Вни­зу видим номер вер­сии Sentry — 8.0.0. Это не самая новая, поэто­му сто­ит поис­кать экс­пло­иты. Так Google при­водит нас на Exploit-DB, а точ­нее — к экс­пло­иту для вер­сии 8.2.0.

По­иск экс­пло­итов
По­иск экс­пло­итов

Экс­пло­ит отра­баты­вает, но ничего не дает.

За­пуск экс­пло­ита
За­пуск экс­пло­ита

По­это­му про­буем вруч­ную.

Sentry исполь­зует модуль pickle, нуж­ный для сери­али­зации и десери­али­зации дан­ных Python. Это может помочь добить­ся выпол­нения кода, но сна­чала нам нужен сек­ретный ключ Django.

Его мож­но получить, соз­дав и уда­лив про­ект: Create Project → Add Project → Save Project → Project Setting → Remove Project.

Create New Project
Create New Project
Configure your application
Configure your application
Project settings
Project settings
Remove project
Remove project

И мы получим нуж­ные кон­фигура­ции. Про­лис­таем до пун­кта SENTRY_OPTIONS и сох­раним сек­ретный ключ (параметр system.secret-key).

Па­рамет­ры SENTRY_OPTIONS
Па­рамет­ры SENTRY_OPTIONS

Имея сек­ретный ключ, мы можем исполь­зовать сле­дующий PoC для соз­дания и сери­али­зации объ­екта, который выпол­нит нуж­ный нам код. Все, что нуж­но в нем изме­нить, — это зна­чения SECRET_KEY и cookie. В качес­тве наг­рузки исполь­зуем реверс‑шелл:

Соз­дание новых cookie
Соз­дание новых cookie

Ак­тивиру­ем на сво­ем локаль­ном хос­те лис­тенер.

Справка: реверс-шелл

Об­ратный шелл — это под­клю­чение, которое акти­виру­ет ата­куемая машина, а мы при­нима­ем и таким обра­зом под­клю­чаем­ся к ней, что­бы выпол­нять коман­ды от лица поль­зовате­ля, который запус­тил шелл. Для при­ема соеди­нения необ­ходимо соз­дать на локаль­ной машине listener, то есть «слу­шатель».

В таких слу­чаях при­годит­ся rlwrap — readline-обо­лоч­ка, которая в чис­ле про­чего поз­воля­ет поль­зовать­ся исто­рией команд. Она обыч­но дос­тупна в репози­тории дис­три­бути­ва.

В качес­тве самого лис­тенера при этом мож­но исполь­зовать широко извес­тный netcat.

Ко­ман­да будет сле­дующей:

Встав­ляем новые cookie, обновля­ем стра­ницу и в окне лис­тенера получа­ем бэк­коннект.

По­луче­ние бэк­конек­та
По­луче­ние бэк­конек­та

Продвижение

Пер­вым делом получа­ем удоб­ную TTY-обо­лоч­ку с помощью Python:

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

Спи­сок фай­лов сай­та developer_ctf
Спи­сок фай­лов сай­та developer_ctf
Со­дер­жимое фай­ла settings.py
Со­дер­жимое фай­ла settings.py

Те­перь под­клю­чим­ся к базе c помощью psql — ути­литы коман­дной стро­ки для работы с PostgreSQL.

Пос­ле под­клю­чения взгля­нем на спи­сок таб­лиц, для это­го исполь­зует­ся коман­да \dt.

Спи­сок таб­лиц
Спи­сок таб­лиц

Нас инте­ресу­ет таб­лица auth_user, из которой получим логины и пароли.

Учет­ные дан­ные поль­зовате­лей сай­та Developer CTF
Учет­ные дан­ные поль­зовате­лей сай­та Developer CTF

Но с эти­ми учет­ными дан­ными ниг­де залоги­нить­ся не получи­лось. Тог­да изу­чим Sentry. Нас­трой­ки для под­клю­чения к базе дан­ных хра­нят­ся в фай­ле:

Со­дер­жимое фай­ла sentry.conf.py
Со­дер­жимое фай­ла sentry.conf.py

Опять под­клю­чаем­ся к базе и прос­матри­ваем сущес­тву­ющие таб­лицы.

Спи­сок таб­лиц
Спи­сок таб­лиц

Вновь получа­ем учет­ные дан­ные из таб­лицы auth_user.

Учет­ные дан­ные плат­формы Sentry
Учет­ные дан­ные плат­формы Sentry

Сох­раня­ем хеши в файл и отправ­ляем на перебор с помощью hashcat.

Ре­зуль­тат перебо­ра хешей
Ре­зуль­тат перебо­ра хешей

Спус­тя нес­коль­ко минут мы получа­ем один пароль, с которым уда­ется авто­ризо­вать­ся по SSH.

Флаг поль­зовате­ля
Флаг поль­зовате­ля

Повышение привилегий

Пер­вым делом про­веря­ем наибо­лее веро­ятные мес­та повыше­ния при­виле­гий. Это могут быть нас­трой­ки sudoers, при­ложе­ния с битом SUID, прос­лушива­емые на локаль­ном хос­те пор­ты. Нам везет с sudoers.

Справка: sudoers

Файл /etc/sudoers в Linux содер­жит спис­ки команд, которые раз­ные груп­пы поль­зовате­лей могут выпол­нять от име­ни адми­нис­тра­тора сис­темы. Мож­но прос­мотреть его как нап­рямую, так и при помощи коман­ды sudo -l.

Нас­трой­ки судо­ера
Нас­трой­ки судо­ера

В нас­трой­ках sudoers про­писан при­виле­гиро­ван­ный запуск поль­зователь­ско­го при­ложе­ния /root/.auth/authenticator. Узна­ем тип фай­ла с помощью ути­литы file.

Прос­мотр типа фай­ла
Прос­мотр типа фай­ла

Это исполня­емый файл, который при запус­ке поп­росит пароль. Ска­чива­ем файл на локаль­ный хост:

За­киды­ваем его для ана­лиза в любой удоб­ный дизас­сем­блер. На этот раз я решил поп­робовать Ghidra.

Еще по теме: Использование фреймворка Ghidra

При поис­ке фун­кции main я понял, что прог­рамма написа­на на язы­ке Rust, а это усложня­ет ана­лиз.

По­иск фун­кции main
По­иск фун­кции main

От­кры­ваем в деком­пилято­ре най­ден­ную фун­кцию authentication::main и в ней находим точ­ку, где зап­рашива­ется пароль.

Псев­докод зап­роса пароля поль­зовате­ля
Псев­докод зап­роса пароля поль­зовате­ля

Чуть ниже находим исполь­зование шиф­рования ( crypto::aes::ctr), а имен­но алго­ритм AES, режим CTR.

Блок шиф­рования стро­ки
Блок шиф­рования стро­ки

И еще ниже видим сооб­щение об успешной аутен­тифика­ции.

Блок кода пос­ле про­вер­ки пароля
Блок кода пос­ле про­вер­ки пароля

Та­ким обра­зом, вве­ден­ная нами стро­ка будет срав­нивать­ся с про­обра­зом сох­ранен­ных в прог­рамме зашиф­рован­ных дан­ных. Поп­робу­ем най­ти все парамет­ры, необ­ходимые для шиф­рования (стро­ка, ключ, век­тор ини­циали­зации), и рас­шифро­вать пароль.

Из докумен­тации узна­ем аргу­мен­ты фун­кции crypto::aes::ctr.

Опи­сание фун­кции crypto::aes::ctr
Опи­сание фун­кции crypto::aes::ctr

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

Блок шиф­рования дан­ных
Блок шиф­рования дан­ных

А нуж­ная нам стро­ка сох­ранена в перемен­ной __ptr. Исполь­зуя все дан­ные и суперинс­тру­мент CyberChef, мы можем рас­шифро­вать дан­ные и пароль.

Рас­шифров­ка дан­ных из прог­раммы
Рас­шифров­ка дан­ных из прог­раммы

Ис­поль­зуем этот пароль в при­ложе­нии. Про­вер­ка прой­дена, нас про­сят ука­зать ключ SSH (генери­руем коман­дой ssh-keygen).

Экс­плу­ата­ция при­ложе­ния authenticator
Экс­плу­ата­ция при­ложе­ния authenticator

Те­перь мы можем авто­ризо­вать­ся с при­ват­ным клю­чом и заб­рать флаг рута.

Флаг рута
Флаг рута

Заключение

Мы зах­ватили машину и име­ем над ней пол­ный кон­троль!

Еще по теме:

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

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

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