Главная » Хабрахабр » CTF — это не сложно [NQ2K18]

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.

До встречи на «очной ставке»


x

Ещё Hi-Tech Интересное!

[Перевод] Python Developer Tools от Microsoft. Начало работы

Последние несколько лет специалисты Microsoft трудились над тем, чтобы добавить поддержку инструментов разработчика Python в одни из наших самых популярных продуктов: Visual Studio Code и Visual Studio. В этом году все заработало. В статье мы познакомимся с инструментами разработчика Python ...

[Перевод] Вселенная, соответствующая нашим текущим представлениям, может оказаться невозможной

Новая физическая гипотеза бросает вызов лидирующей «теории всего» Один заголовок поразил его так, что он сбросил все остатки сна. 25 июня физик Тимм Вразе [Timm Wrase], живущий в Вене, проснулся, и сонно листал в онлайне список недавно опубликованных физических работ. ...