CTF — это не сложно [NQ2K18]


    И вновь завершился очередной отборочный online-этап ежегодного соревнования по кибербезопасности — NeoQUEST-2018.

    Что было? Хм… Оказалось, что в Атлантиде тоже используют Android, но файлы передают по старинке: с помощью Bluetooth, беспокоятся о безопасности транзакций и создают распределенные сети, взламывают сайты конкурентов и используют информационную разведку, а ещё — почти все компьютеры работают на таинственном «QECOS», написанном на LUA, но с большим количеством опечаток. Как здесь выжить? Читайте под катом.

    «Но ведь уже есть несколько WriteUp'ов! Зачем ещё?» — скажете вы, но этот — не такой как у других. Здесь мы рассмотрим некоторые задания из NQ18 со стороны человека, который вообще может ничего не знать об информационной безопасности.

    Задание #1 — «Зелёное объединение»

    Нашему вниманию представляется файл с расширением APK и отсылка к Unity. Если мы не знаем, что значат эти «иероглифы» — используем любую поисковую систему. Становится понятно, что ничего не понятно файл представляет собой архивный исполняемый файл, а значит необходимо провести распаковку.

    Далее у нас несколько вариантов. Первый — мой традиционный. Второй — правильный.

    1. Открываем «1.apk» в iDefense MAP Strings или SysInternals Strings. Из прошлого опыта знаем, что ключ едва ли будет меньше 32 символов. Ищем всё подозрительное и похожее на ключ. Находим.


      К сожалению, ничего кроме первого ключа найти таким образом не получится.
    2. Ищем в интернете что-нибудь наподобие «apk unpacker» и находим — DevXUnity-Unpacker Magic Tools. Запускаем. Открываем нужный нам файл: «1.apk».


      Неистово «протыкиваем» всё, что двигается.


      Первый ключ сразу бросается в глаза. Продолжаем изучать структуру файла. Обращаем внимание на файлы: button.cs, key_part_N и ветку "*** ***".

      Файл button.cs содержит в себе функцию GetSequenceKey(), состоящую из массива чисел, а также переменную «text» (34 символа) из звёздочек и точек. Очень похоже, что массив это ASCII код. Проверяем: convert the height to hex!!!

      Наc вежливо просят перевести высоты в HEX. Интересно, о каких высотах речь? Теперь настало время посмотреть телевизор на рисунок кнопки:


      Разноцветные «ступеньки»… и сколько их? Ровно 34!

      Любым удобным методом мерим высоту в пикселях и переводим в HEX. На выходе получаем следующий массив значений: ['68', '5b', '59', '00', '59', '58', '40', '44', '17', '58', '48', '57', '14', '47', '45', '48', '16', '58', '4f', '11', '5c', '55', '00', '5b', '49', '41', '40', '45', '0c', '0e', '11', '02', '00', '19']
      Вписываем эти значения вместо «вертикально расположенных» в функции GetSequenceKey()
      Далее по функции видим, что эти значения будут гаммироваться со строкой в переменной «text». Кажется, что мы где-то уже видели эти звездочки. Бинго!


      Меняем звёздочки в функции на найденный текст. Переписываем всё, например, на Python:

      #!/usr/bin/python2
      text_ojb='You hold the key to my heart . . .'
      heigth=['68', '5b', '59', '00', '59', '58', '40', '44', '17', '58', '48', '57', '14', '47', '45', '48', '16', '58', '4f', '11', '5c', '55', '00', '5b', '49', '41', '40', '45', '0c', '0e', '11', '02', '00', '19']
      heigth_int=[int(x,16) for x in heigth]
      array=heigth_int
      arg = ''
      for i in range(len(array)):
          arg += chr(array[i] ^ ord(text_ojb[i]))
      print(arg)

      В результате получаем: 14, 17, 7, 24, 16, 11, 3, 21, 1, 7

      Похоже, что это последовательность. Кого? Чего? И вновь пришло время вспомнить что ты делал прошлым летом про найденные key_part_N в ресурсах файла. Собираем ключ (40 символов) из полученной последовательности и гордимся!

    Задание #2 — «Пара-пара-пар!»

    Нам выдали файл и сказали что-то про Bluetooth. Что бы это могло значить? Откроем текстовым редактором.


    Ничего не понятно. Какие-то символы и модели телефонов. Попробуем «загуглить» первое попавшееся слово — "btsnoop"

    Ага. Это дамп трафика сетевого взаимодействия Bluetooth устройств. Нужно снова воспользоваться силой земли и найти все инструменты, способные анализировать сетевой трафик. Самая популярная из таких программ — Wireshark. Устанавливаем. Открываем наш файл — 1513 сетевых пакетов.

    Что с этим делать дальше? RTFM и только хардкор!

    Немного пролистав пакеты, можно заметить, что идёт обмен между Galaxy S6 (смартфон) и неким устройством — ActionsS_32:8f:a3 (TS007). Снова "гуглим". Беспроводная гарнитура.

    Сделаем предположение, что между устройствами должна идти передачи звукового файла.
    Wireshark позволяет в автоматическом режиме отследить очередь пакетов передачи аудиофайлов: Telephony -> RTP -> RTP Streams


    Программа смогла выявить и распознать передачу одного звукового файла. Жмём «Analyze», а затем «Play Streams»


    А вот и наша звуковая дорожка. Слушаем, осознаём тщетность бытия, идём либо учить азбуку Морзе, либо прямо из этого окошка на слух переписываем сигнал в точки и тире: "·– – ·–·· ·– –· – ·· –·· ·– ····· ––––– ····· ·––––". Ищем сайт декодирования кода Морзе. Например, вот этот. Получаем слово: «atlantida5051».
    И казалось бы, что на этом всё, но нет! Мы же знаем, что ключ — 40 символов. Берём от ключа SHA1 — задание выполнено!

    Задание #4 — «Дирижабль? Ага!»

    Суть выполнения этого задания очень хорошо расписал @Nokta_strigo. Однако, получение второго ключа описано слишком умными для обывателя словами. А мы что? А мы сделаем это заданием через… Microsoft Excel 2016 и без программирования (нет, это не шутка)
    Первым делом, открываем базу данных сайта NeoChat с помощью DB Browser for SQLite:


    Видим, что в таблице есть 5 зашифрованных записей разной длины. Но как их восстановить и получить SecondKey?

    Вспоминаем, что кроме этой базы данных у нас есть ещё и копия всех профилей пользователей. Тот, который нам нужен (admin) имеет ID = 4 (смотрим на таблицу)


    А вот и его папка, где следует искать данные. Переходим в неё и открываем файлы «data.json» и «content.json». Что нам из них необходимо:

    "username": "admin"
    "address": "1NeoChatZK4DxZJdg5WwocwxcUppA1eJgL"
    "cert_user_id": "neochatadmin@zeroid.bit"

    Итак, теперь мы можем сопоставить табличные зашифрованные значения и исходные. Но каков алгоритм шифрования? Секрет кроется в файле «lfsr.js»:

    data[i] = data[i] ^ keystream[i]

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

    keystream[i] = XOR(HEX(шифротекст[i]), HEX(исходный_текст[i]))

    Восстанавливаем keystream:

    cac66cfa99e9c4 = XOR(84a303b9f188b0,4e656f43686174) <- SiteName
    25f089bcb0f2c713f7936d7fc8b708ffcac66cfa99e9c4 = XOR(6e656f6368617461646d696e407a65726f69642e626974, 4b95e6dfd893b37293fe041188cd6d8da5af08d4fb80b0) <- AdminCert
    d7c2b1cb2d881566404f3e25f089bcb0f2c713f7936d7fc8b708ffcac66cfa99e9c4 = XOR(e68cd4a46ee074121a040a6188d3f6d495f24480fc0e08b0d45d8fba875d9fd38e88, 314e656f436861745a4b3444785a4a64673557776f637778635570704131654a674c) <- SiteAddress

    Видим, что для всех операций шифрования применяется один и тот же keystream (обратите внимание, что получается одна и та же строка, если смотреть на неё задом наперёд).

    Чтобы расшифровать SecondKey необходимо ещё 72 символа, но где их достать?

    А теперь, мои юные падаваны, настало время основ криптографии.
    LFSR — Регистр сдвига с линейной обратной связью (РСЛОС) — имеет ряд недостатков. Один из них — возможность восстановить цепочку методом корреляционного вскрытия, либо с помощью алгоритма Берлекэмпа — Мэсси (далее — АБМ).

    Здесь у нас есть снова два варианта решения поставленной задачи:

    1. Перевернуть keystream, а также открытый и закрытый текст, потом восстановить последовательность при помощи полинома, получить открытый текст, а затем снова перевернуть результат
    2. Восстановить последовательность из конца в начало, т.е. по принципу «AS IS» (для таких извращенцев как я)

    Как вы уже догадались, здесь я опишу именно второй способ. Запускаем универсальное средство криптоанализа — CrypTool. Используем модуль «Алгоритм Берлекэмпа — Мэсси» из вкладки «Криптоанализ». Добавляем элемент «Text Input», соединив его со входом модуля АБМ, а для выхода генератора полинома добавляем «Text Output». Преобразуем полученный keystream (68 символов) в бинарный вид и вписываем в «Text Input». Запускаем проект.


    На выходе мы получаем полином формирования псевдослучайной последовательности РСЛОС. Да, он такой страшный. Да, будем работать через Excel. Нет, верёвки и мыла нет.

    Ещё не забыли, что мы делаем? Правильно — восстанавливаем последовательность ПСЧ
    А теперь изюминка этого поста — открываем Microsoft Excel 2016 (начиная с этой версии была добавлена функция ИСКЛИЛИ() для нескольких аргументов).

    Перематываем страницу куда-нибудь до столбца «ААА». И в строчку размещаем наш keystream в бинарном виде (по биту в каждую ячейку).

    Теперь необходимо понять — что же такое полином (который мы получили). Немного теории:
    Полином, в данном случае — это ключ формирования псевдослучайной последовательности. К примеру, если у вас есть последовательность «010101» и вы задаёте для неё полином: $x^3 + x + 1$, то следующий элемент последовательности будет всегда генерироваться по формуле: x[i] = x[i-3] ^ x[i-1]. После первой итерации у нас будет: «0101010», после второй: «01010100», после третьей: «010101001». Точно также и у нас. Эй! Убери ножницы от глаз.
    В данном примере я рассмотрел нормальную генерацию последовательности «от начала в конец», а нам нужна наоборот. Вернёмся к нашей книге Excel.

    Теперь, зная, что такое полином, необходимо чуть-чуть его поменять и записать формулу генерации ППСЧ в ячейку ZZ[1] (если keystream начинается с AAA[1]).

    В чём преимущество Excel? В том, что здесь вам не нужно думать о том как изменить формулу, какие индексы будут относительно генерируемого элемента, ибо все ячейки имеют относительный адрес. Всё, что нужно — изменить первый и последний аргументы формулы (по сути — поменять местами). Мы получим (в ячейке ZZ[1]):

    =ЕСЛИ(ИСКЛИЛИ(AEV1;AEU1;AER1;AEP1;AEO1;AEN1;AEM1;AEL1;AEI1;AEH1;AEG1;
    AEC1;AEB1;AEA1;ADX1;ADW1;ADU1;ADT1;ADO1;ADK1;ADJ1;ADI1;ADH1;ADG1;ADE1;ADB1;
    ADA1;ACY1;ACR1;ACQ1;ACP1;ACN1;ACL1;ACK1;ACI1;ACH1;ACF1;ACE1;ABZ1;ABV1;ABU1;
    ABS1;ABP1;ABM1;ABL1;ABK1;ABF1;ABE1;ABD1;ABB1;ABA1;AAZ1;AAX1;AAV1;AAU1;AAS1;AAJ1;
    AAH1;AAF1;AAE1;AAB1;AAA1;AEX1);1;0)

    А теперь просто берём за уголок ячейки и вытягиваем её [формулу] влево до, например, ячейки AA[1].

    Поздравляю! Вы восстановили последовательность.

    Переводим из бинарного вида в HEX и берём последние 140 символов:
    «847bf908c48a48cf4a4dd8b9d965d3867bc55e2aa33a56197228e1050ffb5157f21e4c1ad7c2b1cb2d881566404f3e25f089bcb0f2c713f7936d7fc8b708ffcac66cfa99e9c4»
    Теперь делаем XOR(keystream, secondkey) и декодируем из HEX в текстовый вид:
    «CALCULATEMYSHA1suA1EeNRrIiIeGUopBSyVLU7juqgNaOmGLsTf2erZHfQ0VgB6CwxykY»
    Строка как бы говорит нам, что нужно получить дайджест SHA1. Конец.

    Задание #6 — «Кто тут инженер?»

    Уже в брифинге в нас кидают парой пар заумных слов: акселерометр, RTTY, смещение, чашка.

    Файл представляет собой форматированный в два столбца, текст: время и значение.
    Тщательно поискав, можно узнать, что некоторое программное обеспечение для работы с RTTY (например, fldigi) позволяет воспроизвести запись эфира из «WAV» файлов — функция playback. Может нам нужно сделать из текстового файла — аудиофайл?

    Снова используем поиск в мировой паутине — говорят, что всем известный аудиоредактор Audacity умеет это делать.

    Запускаем. Выбираем «Создание» -> «Sample Data Import». Указываем путь до файла. Ошибка: Audacity не понимает такую структуру файла. Что же, я бы тоже не сразу понял, что от меня хотят.
    Давайте подумаем: а нужно ли нам время? А пространство? Запомним, что там 9.961 секунд, удаляем левый столбец и оставляем только значения.

    Повторно импортируем:


    Сразу заметно, что Audacity не понимает «сырые данные» сверх нормированных (от -1 до 1) значений.

    Самое быстрое и рабочее решение — разделить каждое значение в файле на максимальное. Любым удобным способов реализуем это (и даже здесь Excel может помочь). И ещё раз импортируем:


    Очень краси… Стоп! А почему весь файл длится 0,135 секунд? Там, кажется, около 10 секунд было.

    Ещё раз выделяем всю аудиодорожку и выбираем «Эффекты» -> «Смена скорости». Выставляем следующие значения:


    Вот теперь хорошо! Экспортируем в аудиофайл с расширением «WAV».

    Запускаем fldigi: «Op Mode» -> «RTTY» -> «Custom». Выставляем следующие настройки во вкладке «Tx»:


    Сохраняем настройки и закрываем конфигурационное окно.
    Выбираем «File» -> «Audio» -> «Playback» и указываем путь до экспортированного аудиофайла «WAV». На вопрос о зацикливании воспроизведения отвечаем утвердительно. Настраиваем приёмник и «ловим ключ»:



    На этой ноте данный WriteUp заканчивается, но огорчаться не стоит: впереди ещё много времени, чтобы наточить свои навыки для победы в конкурсах и олимпиаде по кибербезопасности, которые (я уверен) точно будут в рамках МиТСОБИ.

    Большое спасибо организаторам и каждому из тех, кто принимал участие в создании NeoQUEST-2018.

    До встречи на «очной ставке»
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 3

      +2
      Спасибо за отличный write-up! :) Ждём на «Очной ставке»!
        0

        В шестом задании baud rate, вроде бы 45.45 должен быть. Но у меня три символа принялись с ошибками, пришлось в блокноте вручную решать.


        bay

          +1

          КДПВ нужно было брать из третьего задания =)

          Only users with full accounts can post comments. Log in, please.