HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Этичный хакинг или пентестинг > Задания/Квесты/CTF/Конкурсы
   
 
 
Опции темы Поиск в этой теме Опции просмотра

  #29  
Старый 22.04.2019, 13:50
pas9x
Постоянный
Регистрация: 13.10.2012
Сообщений: 423
С нами: 7147766

Репутация: 52
По умолчанию

Извиняюсь, что заставил долго ждать. На выходных было много дел. Времени вообще нет. Поэтому решил сделать упрощённую версию врайтапа. Изначально я её планировал более пафосную, с картиночками и прочими ништяками. В течение недели ещё несколько раз буду редактировать и дополнять этот пост. Скажу сразу: не все из изложенных мной предположений верны (особенно про вежливость), я просто выкладываю какие мысли у меня были в голове по ходу прохождения конкурса.

[ Флаг 0 ]

Для начала нам надо найти точку входа в CTF. Нам известно, что она находится на сервере 94.X5Y.X5Y.96. Значит теоретический максимум для перебора - 100 комбинаций цифр. Но учитывая, что X может иметь значение от 0 до 2 диапазон поиска сужается до 30 айпишников. При этом нам не известно на каком порту работает точка входа и нет-ли в пространстве айпишников левых серверов (которые не относятся к CTF). Пробуем самый простой вариант: пишем пхп-скрипт и через fsockopen ищем сервер с открытым 80 портом. И оказывается, что 80 порт открыт только на сервере http://94.250.250.96/

[ Флаг 1 ]

Обходим сайт, внимательно смотрим в html-код. В коде страницы портфолио видим странный коммент. Пытаемся раскодировать его как base64, но из-под него выходит какой-то бинарный блок данных. По его виду непонятно что это за блок данных. Наугад пробуем сохранить его в файл и открыть с помощью 7zip. Оказывается, что это zip-архив с запароленым файлом 404.txt. Ищем в нэте какой-нибудь брутер zip-архивов. Я воспользовался Ultimate ZIP Cracker. Долго ждать не пришлось, пароль на архив: 123

Но оказалось, что это просто пасхалка с текстом "Bingo! You have found an Easter egg, hurry to contact me and do not forget to send some interesting HTML materials! "

Продолжаем изучать сервер. Сканим все tcp-порты nmap'ом, но оказывается что на сервере нет открытых портов кроме 22 и 80. Значит выбор у нас не велик: копать веб-сервер. Ну или попробовать брутить ssh. Ещё я поискал нмапом другие серверы с айпишником 94.X5Y.X5Y.96 но ничего стоящего не нашлось. Кстати, подключившись любым tcp-клиентом (например nc) на 22 порт во многих случаях ssh-сервер выдаёт нам название и версию операционной системы. В нашем случае ssh-сервер нам выдал: SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u4

Копаем сайт. С помощью ffuf вдоль и поперёк сканим директории/файлы сайта, но из интересного находим только директорию /uploads. Как оказалось, в неё складывают загруженные в форму обратной связи файлы. Ничего кроме картинок и текстовых файлов в неё загрузить невозможно. При попытке загрузить файл с расширением php он там не появляется (это было-бы слишком просто). Однако если добавить php-код в конец нормальной картинки то такой файл загрузится как есть.

На первый взгляд кажется, что тут есть дыра в параметре page. Видно, что тут как-то странно обрабатывается расширение файла. Имею право предположить, что страницы лежат на сервере локально и просто инклудятся. Былоб неплохо подинклудить jpeg-картинку с нашим пхп-кодом. Но опять-же это было-бы слишком просто. Ещё немного поигравшись с параметром page у меня начинает закрадываться подозрение, что это ловука.

Пораскинув мозгами бросаем затею с параметром page и пробуем отправлять всякую хрень в форму обратной связи. Пасхалка нам явно говорит, что надо отправлять в неё какой-то хтмл-код. И тут я подумал: а что если на бекенде какой-то пхп-скрипт проходит по ссылкам в этом хтмл-коде? Надо попробовать накидать в форму хтмл с разными ссылками. Я отправил в форму хтмл с тегами , и глянул лог сайта ссылки на который засабмитил в форму. И действительно: по этим ссылкам зашёл некто с юзер-агентом Moskilla/1.337 (BeOS XS; X-Header-Powered-Browser) Pro/3.5737 с айпишника 94.250.250.96. Header-Powered-Browser нам как-бы намекает, что надо глянуть остальные заголовки клиента. Запускаем tcpdump и сниффирим трафик с 94.250.250.96. Почему tcpdump? Потому что вдруг этот сервер ещё куда-то заходит или что-то делает - я должен об этом знать. Скачиваем дамп трафика на комп и смотрим его в wireshark. Но там всего лишь одиночный http-запрос с заголовком X-Hint: If you try to be more polite, then you will get a surprise

Блин. Вообщето я ожидал увидеть в заголовках флаг а сервер требует просить вежливее. Но что значит вежливее? Тут я вспомнил, что уже несколько раз сабмитил форму. Может невежливостью считается частая отправка формы или ссылки на один и тот-же сайт? Решил подождать несколько часов и засабмитить форму с другим текстом и с другими ссылками. И тут по счастливой случайности я засабмитил в форму текст "Hi" и в заголовках увидел:

Код:
[HTTP_X_REFERER] => http://host2.developer.skill.programmer/messages.php
            [HTTP_X_FLAG] => {skl_wh0_said_s0cial_3ngin33ring?}
            [HTTP_USER_AGENT] => Moskilla/1.337 (BeOS XS; X-Header-Powered-Browser) Pro/3.5737
Охрененчик! Действительно, надо было не так часто самбитить форму, с разных айпишников и с разным текстом. Тут прикол в том, что на радостях я не обратил внимания на заголовок referer и побежал в личку к @crlf отправлять первый флаг Так как в топике что-то говорилось про социальную инженерию, да и флаг нам намекает на неё я подумал: самое время применить соц инженерию. Но в каком виде? И тогда я набравшись наглости начал взламывать соц инженерией самого автора таска. И просто задал ему вопрос: "куда копать дальше?" на что естественно получил ответ "смотри заголовки ответа". Даже как-то стыдно

Но вообще этот флаг я прошёл по чистой случайности. Еслиб я не вбил в форму "hi" то вообще не прошёл-бы конкурс.

[ Флаг 2 ]

Прописываем в хост-файл 94.250.250.96 host2.developer.skill.programmer и заходим на сайт. Подставляя кавычки и прочую дрянь в форму естественно ничего я не добился. Глянул в хтмл и заметил странность: в форме почему-то два инпута с name=login. Т.е. какой-бы логин ты не отпраивл всёравно на бекенд уйдёт и введённый логин и login=Verify. Т.е. форма авторизации тут вообще закосячена. Ок, снова запускаем сканер директорий и находим директорию /misc, содержимое которой бесценно. Среди всего прочего в ней есть файлик README.md с флагом {skl_d1r3ctory_lis7ing_1s_a_bad_id3a.}

В файле in.php какая-то синтаксическая ошибка благодаря которой теперь нам известен путь к директории сайта: /var/www/html/host2.developer/misc/in.php

[ Флаг 3 ]

Смотрим auth.php.old. С этого флага начинается проверка знания php и linux. Если первые 2 флага проверяли твою интуицию то все флаги начиная с третьего - это проверка знания php и проверка на внимательность. Начиная с этого флага нам надо тщательнейшим образом проверять все пхп-исходники, вглядываться в каждую строчку кода и перебирать варианты что с ней может быть не так. Первое на что нужно обратить внимание - это то, что файлы auth_secrets.php и auth_secrets.php.old имеют разный размер. С высокой степенью вероятности это означает то, что ключи поменялись. Я на это не обратил внимания и потратил некоторое время впустую пытаясь подставлять в куки значения сформированные с использованием auth.php.old.

Второе на что нужно обратить внимание - это операция extract($user['auth']), что крайне небезопасно. Используя это мы можем устанавливать какие угодно переменные. В том числе мы можем переопределять суперглобальные пхпшные переменные $_GET, $_POST, $_COOKIE, $_FILES.

Далее в операторе if нам нужно декомпозировать строку in_array($login,['admin','superuser','hackersucks'])&&strlen($user_hash)&&$auth_hash==$user_hash&&4>$ auth_group&&$log=='local'&&$auth_id[/COLOR]$auth_group;
$condition5=$log=='local';
$condition6=$auth_id [
'id'=>1,
'user'=>'admin',
'group'=>1,
'hash'=>'qwe',
'log'=>'local',
'signature'=>'rty',
],
];
$_COOKIE['session'] =base64_encode(json_encode($sessionCookie));
$_COOKIE['signature'] ='test';[/COLOR]
[/PHP]
Но как выполнить 3 и 7 условие? Ведь чтобы их выполнить нам нужно правильное значение $secret, $secretx или $secrety. Если мы возьмём его из auth.php.old то конечно локально у нас все условия будут выполнены. Но на сервере эти значения другие а потому авторизация не пройдёт. Те, кто хорошо знаком с языком в курсе, что в php есть несколько операторов сравнения: https://www.php.net/manual/ru/langua...comparison.php

Оператор === требует чтобы оба операнда были идентичны. Т.е. выражение (1 === '1') вычислится как false.

Но оператор == выполняет конвертацию типов. Поэтому выражение (1 == '1') вычислится как true.

Подробнее о том, как пхп выполняет конвертацию типов при сравнении посмотреть можно здесь: https://www.php.net/manual/ru/types.comparisons.php

Как мы видим, в третьем условии используется оператор == , чем мы и воспользуемся. Функция sha1 и md5 возвращает строку. И если в параметре hash мы укажем неверный хеш то результат операции сравнения будет false. Т.е. при сравнении строки со строкой операция сравнения отрабатывает корректно. Но мы можем подсунуть в качестве значения hash не строку а true и тогда пхп выполнит конвертацию строки в boolean, из-за чего результатом сравнения будет true.

Итак, подсунув в параметр hash вместо нормального хеша значение true мы добились выполнения 3 условия.

Теперь нам надо добиться выполнения 7 условия. Здесь мы используем ту-же слабость php. Но дополнительно нам надо почитать доку по этой функции: https://www.php.net/manual/ru/function.strcmp.php

Нужно не просто почитать доку по этой функции, но ещё и хорошо поэкспериментировать с ней. И в ходе экспериментов мы видим, что это очень проблемная функция с абсолютно непредсказуемым результатом. Одна из проблем этой функции в том, что она может возвращать null, хотя в документации об этом не сказано (хотя должно быть сказано). Если мы в аргументе $signature вместо нормальной строки подставим массив то пхп выдаст "Warning: strcmp() expects parameter 2 to be string, array given" а сама функция вернёт значение null. И, как вы уже догадались, 0 == null

Если вам влом вручную формировать правильные значения то для прохождения авторизации в админке можете прописать браузеру следующие куки:

session=eyJhdXRoIjp7ImlkIjoxLCJ1c2VyIjoiYWRtaW4iLC Jncm91cCI6MSwiaGFzaCI6dHJ1ZSwibG9nIjoibG9jYWwiLCJz aWduYXR1cmUiOlsiZnVjayB5b3UiXX19

signature=fake

Когда мы прописали браузеру правильные куки - можем смело заходить в админку, где нас сразу встречает третий флаг: {skl_y0u_ar3_supp4_us3r!}

[ Флаг 4 ]

Потыкав форму находим в ней много вкусного: тут и загрузка файлов по ссылке и exec Естественно первым делом нас интересует exec, но поигравшись со значениями параметра command понимаем, что ни к чему хорошему нас это не приводит. Тогда играемся с формой скачивания файлов и понимаем, что с помощью неё можно получить содержимое по любой ссылке, главное чтоб в url присутствовало значение ?print=1 . Могу предположить, что для простоты содержимое ссылки скачивается функцией file_get_contents() и если это действительно так, то тогда мы можем пробовать разные пхп-шные врапперы. Первое что приходит на ум - использовать для чтения файлов схему file:// но нам мешает требование наличия ?print=1. Хм. А мешает-ли? Ведь мы можем воспользоваться нормализацией пути и использовать для этого ..

Почти в любой unix-подобной ОС есть файлы которые лежат по одному и тому-же пути, например: /etc/hosts /etc/hostname /etc/resolv.conf /etc/os-release независимо от ОС. Доступ на чтение этих файлов есть всегда и у любого юзера, поэтому проще всего пробовать прочесть их. Пробуем получить содержимое по такому url: file:///?print=1/../etc/hosts и вуаля: мы считали хост-файл

Круто. Теперь мы можем читать любые файлы на сервере. Из второго флага нам известно в какой директории лежит сайт, так что считываем файл file:///?print=1/../var/www/html/host2.developer/index.php и забираем 4 флаг: {skl_wha7_is_g0ing_0n_h3r3?}

[ Флаг 5 ]

Первое, что хочется сделать на этом этапе - узнать как можно больше информации о сервере. Чтобы удобно читать содержимое файлов я накатал функцию downloadFile($path) и на основе неё сделал скриптик flag5/cat.php (архив во вложении). Мы уже знаем, что на сервере стоит Debian 10. На мою удачу, на работе у меня оказался серверок с дебианом где есть nginx+php-fpm, поэтому мне не составило труда узнать точные пути к дефолтовым конфигам. Хотя еслиб такого сервера у меня не оказалось - я-бы установил дебиан и весь нужный софт на виртуалку, просто это заняло-бы больше времени. Покопавшись в конфигах не нашлось ничего интересного, конфигурация сервера почти дефолтовая. Конфиг php-fpm тоже дефолтовый. Из более-менее интересного:

/var/backups/dpkg.status.0 - список установленного на сервер софта

/etc/nginx/nginx.conf

/etc/nginx/sites-enabled/default

Из этих файлов мы можем узнать что сервер почти голый, ничего кроме nginx+php-fpm на него не установлено а у nginx всего два виртуальных хоста: skill.programmer (дефолтовый сайт) и host2.developer.skill.programmer. Всё это говорит о том, что не стоит тратить время на поиск уязвимостей конфигурации и на поиск каких-то дыр в других местах. На дефолтовом сайте index.php доставляет немного лулзов, но для нас он бесполезен. Лучше сосредоточиться на host2.developer.skill.programmer.

На этом флаге я проделал дофигищу бесполезной работы и проверил кучу гипотез:
  1. Может быть какой-то файл в директории skillibs модифицирован и в него встроен флаг или бекдор? Первым делом я написал скрипт который с помощью вышеупомянутой функции downloadFile целиком выкачивает все файлы из skillibs, затем на своём компе выкачал компосером все те-же версии либ и сделал сравнение файлов. Но различий найдено небыло (помимо автогенерированных файлов компосера, но это ерунда).
  2. Возможно имеет место RCE при десериализации объектов? Но пробежавшись по __destuct() и __wakeup() не нашлось ничего стоящего (и в этом я ошибался).
  3. Возможно есть какая-то дыра в автолоадере и подставляя в десериализатор специально сформированные имена классов удастся подинклудить файл из uploads. Но пхп жёстко фильтрует имена классов и неймспейсы.
  4. Хинт по 5 флагу рекомендует почитать посты из блога команды взломавшей порнхаб через дыру в сборщике мусора. Почитав сам пост об этой дыре я приуныл: c++ на должном уровне я не знаю а PHP на сервере версии 7.0.30 и в ней этой уязвимости уже нет. PHP на моём сервере той-же версии и PoC-код из вышеуказанной статьи не срабатывает.
  5. Ещё один хинт гласит, что "библиотеки меняются на глазах" - не знаю как это понимать. Может в директории skillibs периодически что-то изменяется? Для уверенности что это не так я написал скрипт который каждые 30 секунд обходит все поддиректории в skillibs и смотрит не поменялся-ли размер файлов или не появилось-ли новых файлов. Через сутки естественно ничего такого не нашлось.
  6. Попытался использовать XXE с expect:// причём в форме обратной связи тоже. Однако эксперименты на своём сервере показали что без флага LIBXML_NOENT xxe в пхп не работает.
Провал по всем направлениям очень сильно обламывает. Куча времени потрачено впустую а у тебя нет ни единой зацепки. У тебя даже интуитивно нет предположения в какую сторону копать. Я решил признать, что это не мой уровень, сдался и пошёл спать. С утра зачем-то я опять полез в код skillibs. И тут меня снова появилась надежда: в деструкторе PHPMailer вызывается метод smtpClose() а в нём $this->smtp->connected(). Если мы подсунем $this->smtp какой-то левый объект то при отсутствии метода connected() будет вызван магический метод __call(). Классов с этим методом оказалось не много и я легко пробежался по всем. С первого-же взгляда на Services_Twilio_PartialApplicationHelper меня озарило: call_user_func_array - ЭТО-ЖЕ ИМЕННО ТО, ЧТО НАДО! Я спешно склепал сериализованный объект, протестировал десериализацию и оказалось, что это реально работает. Ахаха, пятый флаг мой - подумалось. Но я ещё не знал, что ждёт меня впереди. Засабмитив сериализованный объект вместо ожидаемого OK я получил ERROR. Да, я предусмотрел что из-за preg_match надо вложить объект в массив. Но почему-то всёравно получал ERROR. Какого хрена? Пятый флаг всё ещё не мой? Я начал копать почему это происходит и обнаружил, что у меня на компе это тоже не работает. А виною всему simplexml который не хавает сериализованный объект. Как оказалось, после сериализации объекта из-под функции serialize выходит всем нам привычный сериализованный код за одним только исключением: имена всех приватных свойств объектов содержат нуль-байт. Я подумал: ну не проблема, экранируем все спецсимволы с в коды по типу � но и это не проканало. Как оказалось, стандарт XML вообще запрещает в xml наличие байт с кодом ниже 9, даже если символы экранированы. И ты можешь хоть жопу рвать (и гуглить xml binary data), но нуль-байт при любом раскладе в xml не допускается. Это огорчает. Я не должен просрать в одном шаге от последнего флага из-за такой ерунды. И тут я вспомнил, что в одной статье читал о разных способах сериализации и что, вроде как, есть способ сериализовать строку с экранированием спецсимволов. В ходе экспериментов оказалось, что пхп почему-то по умолчанию не применяет такой метод и всегда сериализует строку методом s, хотя десериализация методом S также срабатывает. Я написал функцию-костыль которая корректирует данные полученные из функции unserialize и переделывает метод сериализации строк с s на S (с экранированием нуль-байта естественно). И наконец в конце всех мытарств я получил долгожданный OK. Естественно в call_user_func_array я прописал file_put_contents и благополучно залил шелл в директорию uploads Пробежавшись по папочкам на сервере я нашёл файл http://host2.developer.skill.program...a2ff592536.txt с флагом {skl_d3s3rial1z4ti0n_is_c00l_did_y0u_l1k3_it?}

На этом всё, а теперь мне пора баиньки

PS: архив во вложении обновил с учётом пятого флага.
 
Ответить с цитированием
 





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.