ImaginaryCTF, Umasscybersec и n00bzCTF: самые интересные задачи по ИБ - Академия Selectel

ImaginaryCTF, Umasscybersec и n00bzCTF: самые интересные задачи по ИБ

Тирекс Тирекс Самый зубастый автор 12 августа 2024

Разбираем задачи по информационной безопасности. Пригодится новичкам, которые хотят прокачать свои навыки.

Изображение записи

Автор: Иван, ведущий инженер по информационной безопасности

Давно я не публиковал свои похождения по CTF — пора это исправить! За прошедшее время мне удалось попробовать себя в трех турнирах. В ImaginaryCTF, посвященном кибербезопасности, Umasscybersec, адаптированном под Губку Боба, и n00bzCTF, который сделали для опытных n00bz.

Категорий задач на турнирах было много. Среди них — OSINT, Reverse, Forensics, Pwn и Web. Последнее направление для меня самое интересное, поэтому его я и выбрал. Что из этого получилось, показываю в статье!

Readme

Задание

Попробуйте прочитать файл file.txt.

readme.tar.gz →

readme.chal.imaginaryctf.org →

Решение

1. Перехожу по ссылке и убеждаюсь, что она работает. Открываю код страницы. 

2. В коде страницы ничего интересного — надо искать глубже. Запускаю dirsearch.

Сервер отвечает ошибкой 404 на запросы страниц flag.txt и index.html. А в файле default.conf с настройками nginx находится такая конфигурация:


    server {
    listen       80 default_server;
    listen  [::]:80;
    root /app/public;

    location / {
        if (-f $request_filename) {
            return 404;
        }
        proxy_pass http://localhost:8000;
    }
}

В директиве location есть условие проверки наличия файла. Если запрашиваемый в URL файл существует, то сервер возвращает ошибку 404. Результаты поиска dirsearch и эта конфигурация подтверждают, что на сервере есть оба файла: flag.txt, index.html. Необходимо как-то обойти это условие — есть несколько вариантов.

3. Вручную или с помощью модуля Intruder в burpsuite можно перебрать предлагаемые варианты нагрузок. В результате вместо /flag.txt можно запросить страницу по такой форме: 


    GET /flag.txt/.

4. Сервер вернул внятный ответ — флаг в кармане!

Journal

Задание

Дорогой дневник, в этом приложении нет LFI. 

journal-dist.zip →

journal.chal.imaginaryctf.org → 

Решение

На страницы находятся лишь ссылки на пять файлов с текстами. Однако наибольший интерес вызывает URL:


    http://journal.chal.imaginaryctf.org/?file=file1.txt

Имя запрашиваемого файла передается в параметре file, который потенциально может быть уязвимым.

1. Смотрю приложенные конфигурационные файлы. Начинаю с index.php.

В нем находятся те самые ссылки на текстовые файлы, а также некая функция assert, которая вместе с strpos проверяет наличие многоточия в имени запрашиваемого файла. Вероятно, так реализована защита от cmd-инъекции. Далее просто проверяется наличие файла и отдается содержимое, если условие истинно.

2. По логике кода понятно, что можно попробовать обратиться по пути flag.txt. Иду смотреть Dockerfile.

Самая интересная строка в файле выглядит так:


    RUN mv /flag.txt /flag-’tr -dc A-Za-z0-9 < /dev/random | head -c 20’.txt

В имя файла flag.txt добавляется двадцать случайных символов. При этом сам файл с флагом находится в корневом каталоге. Значит, чтобы добраться до ОС сервера, необходимо работать с функцией:


    assert("strpos('$file', '..') === false") or die("Invalid file!");

3. Так как передаваемое в параметр file значение используется в функции strpos без какой-либо валидации, можно провести php-инъекцию. Она будет выглядеть следующим образом:


    ‘).system(“ls”);//

В результате строка кода примет такой вид:


    assert("strpos('‘).system(“ls”);//', '..') === false") or die("Invalid file!");

Все, что будет после знака комментария «//», программа проигнорирует. До него будет выполнено strpos(‘’).system(‘ls’). Кроме того, должна появиться ошибка выполнения функции assert, т. к. она принимает два параметра.

4. Пробую подать нагрузку: 

Все работает — файлы текущего каталога отдаются.

5. Поднимаюсь по файловой системе до корневого каталога, где должен находиться файл с флагом.

Действительно, файл есть. Брутить имя, конечно, было бы очень долгим занятием. 

6. Читаю файл и получаю заветный флаг!

Passwordless

Задание

Устали от хранения паролей? Не беспокойтесь! Этот сверхзащищенный веб-сайт не содержит паролей!

app.py → 

24.199.110.35:40150 →

Решение

На странице задания встречает такая форма ввода логина:

Если ввести любое имя, то происходит редирект.

1. В коде страницы нет ничего интересного — иду в исходники. В app.py есть следующий скрипт маршрутизации запроса:


    @app.route('/<uid>')
def user_page(uid):
    if uid != str(uuid.uuid5(leet,'admin123')):
        return f'Welcome! No flag for you :('
    else:
        return flag

Флаг отдается только в случае, если перейти по ссылке:


    str(uuid.uuid5(leet,'admin123'))

В самом начале файла задается значение переменной leet:


    global leet=uuid.UUID('13371337-1337-1337-1337-133713371337')

2. Пробую сформировать целевую ссылку — для этого в IDLE выполняю часть кода из конфигурационного файла:


    import uuid

leet=uuid.UUID('13371337-1337-1337-1337-133713371337')
print(uuid.uuid5(leet,'admin123'))

На выходе получаю следующую строку:


    3c68e6cc-15a7-59d4-823c-e7563bbb326c

3. Используя полученную строку, собираю новую ссылку и пробую обратиться по ней:


    http://24.199.110.35:40150/3c68e6cc-15a7-59d4-823c-e7563bbb326c

Готово — сервер возвращает флаг: n00bz{1337-13371337-1337-133713371337-1337}.

Holesome Birthday Party

Задание

Тебя только что пригласили на день рождения Губки Боба! Но он решил испытать вашу дружбу, прежде чем выдать входной билет. Сможешь ли ты пройти испытания и заслужить право попасть на вечеринку?

holesomebirthdayparty.ctf.umasscybersec.org →

Решение

Губка Боб ждет на своем дне рождения только настоящих друзей — надо обязательно попасть на тусовку!

1. Перехожу по ссылке, вижу первое задание:

Похоже, необходимо поработать с HTTP-запросом и в заголовке User-Agent указать «Bikini Bottom»:


    User-Agent: Bikini Bottom

Отлично! Первое задание пройдено. 

2. Далее необходимо поменять дату в запросе через заголовок Date. Гуглю — оказывается, у Губки Боба день рождения 14 июля. Меняю дату на нужную.

Готово — перехожу к следующему заданию. 

3. Теперь Боб хочет учить французский язык, поэтому просит говорить соответствующе. 

В HTTP-запросе язык указывается в заголовке Accept-Language — меняю на fr:

Прекрасно, двигаюсь дальше.

4. Именинник просит захватить печенье со вкусом шоколадной крошки. Пойду навстречу и добавлю в HTTP-запрос Cookie с требуемым значением.

Губка Боб выдал билет на тусовку, но что-то в нем не так… 

В Cookie прилетает новое значение (Login=eyJsb2dnZWRpbiI6IGZhbHNlfQ==) — логин в BASE-64 кодировке. У Burpsuite есть модуль Decode, воспользуюсь им: 

Меняю на true и отдаю в заголовке. Финальный HTTP-запрос (с учетом предыдущих заданий) будет следующим:

Флаг получен — вечеринка тусовка с грустным Сквидвардом началась!

CTF турниры помогают расширить знания о, казалось бы, понятных функциях языков программирования или конфигурации nginx. А также позволяют поработать со структурой протокола HTTP.

Надеюсь, подобный разбор заданий поможет начинающим игрокам в CTF понять способы подхода к процессу поиска флагов. До встречи в следующих частях!