Привет всем, я Никита Куртин, куратор израильской высшей школы IT и безопасности HackerU.

И я продолжаю рассказывать про кибер испытания от ведущей израильской компании в области информационной безопасности Checkpoint. В предыдущем посте я описал как прошел четыре испытания, а в этом хочу рассказать о следующих трех, которых мне удалось пройти.

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

Задачи поделили на шесть категорий:

• Logic
• Web
• Programming
• Networking
• Reversing
• Surprise

По две задачки на каждое направление. Как я уже писал, Checkpoint до этого уже успел завоевать уважение и интерес с мой стороны, поэтому я решил принять эти вызовы. Однако ввиду занятости, смог позволить себе взяться лишь за 8 из 12 заданий (из четырёх разных категорий). И решить мне удалось 7 из них.

И так:

Челлендж: «Пазл»

Описание:

Наконец-то мы тебя нашли!
Нам необходимо собрать этот пазл, и как гласит пророчество – лишь ты один способен на это.

Пазл весьма причудлив. Он состоит из доски с 10 колонками и 10 рядами. Всего – 100 деталей. И каждая из них – несет в себе загадку! Состоят детали из четырёх долей: верхней, нижней, правой и левой. Каждая доля – это номер. Например:


image

Сверх – 12, справа – 3, снизу – 4 и слева – 5.

Чтобы пазл сложился, все детали должны расположиться на доске таким образом, чтобы каждая доля примыкала к равной по значению.

Вдобавок, доля, которая ни к чему не примыкает, а является частью границы доски, должна быть со значением 0. Остальные доли не могут иметь нулевое значение. Вот верный пример, состоящий из 4 деталей:

image

Вверху доски все доли, образующие границу равны нулю.

Рассмотрим верхнюю левую деталь. Её правая доля равна 9, и примыкающая к ней доля (левая доля верхней правой детали) также равна 9.

К сожалению, все наши детали перетасованы. Они приводятся в следующем формате:
Id куба [доли]; id куба, [доли];… id куба, [доли]

Где id куба – это номера от 0 до 99, а доли состоят из чисел, расположенных в порядке: верхнее, правое, нижнее, левое.

К примеру, посмотрите на следующую перетасованную доску:

image

Вот как выглядит строка, описывающая эту доску:

image

Нам нужно, чтобы ты сложил пазл!

Напиши нам строку, которая бы выглядела в точности как эта:

Id куба, сколько раз её нужно повернуть по часовой стрелке; id куба, сколько раз её нужно повернуть по часовой стрелке;… id куба, сколько раз её нужно повернуть по часовой стрелке

Строка с решением данной доски будет выглядеть так:

image

Вышеупомянутая строка соответствует следующей (решенной) головоломке:

image

Рассмотрим верхнюю левую деталь. В строке она соответствует обозначению «2,2». Как мы берем куб номер 2 от ввода:

image

Но мы крутим его по часовой стрелке дважды и получаем [0,19,5,0].

Теперь рассмотрим верхнюю среднюю деталь. В строке она соответствует обозначению «1,0». Поэтому мы берем куб номер 1 от ввода:

image

И уже вовсе не крутим его (да-да, крутить 0 раз) – значит он уже в правильном положении.

Уловил?
Теперь помоги нам сложить пазл!

Выглядит он следующим образом:

image

Удачи!

Теоретически эта задача может быть решена множеством различных способов. Найди свой и поделись им. Я размышлял над несколькими вариантами и в конце концов пришёл к следующим выводам:

Первое. В любое заданное время мне лишь нужно определить один куб. Для каждого куба я всегда наверняка буду знать две стороны: верхнюю и левую. В начале это 0 и 0. У следующего куба наверху также будет 0, а слева – цифра, соответствующая номеру правой доли предыдущего куба.
Второе. Из-за огромного количества различных вариаций между кубами, мне стоит попробовать совершать как можно меньше шагов и избавиться от бессмысленной проверки при первом же отрицательном результате.

Третье. Чтобы работать с разными кубами, мне всегда нужно помнить их изначальное положение (id), количество поворотов от начальной точки и, видимо, номера сторон (верхней, правой, нижней, левой).

Четвёртое. Начальные входные данные – это стринг. И выходные данные тоже стринг (а не текущие позиции).

Исходя из всего этого, я выработал для себя следующую стратегию:

Двигаться линейно – слева направо до того момента, пока не упрусь в правый угол. Далее спускаться на строку вниз и начинать слева с нижнего числа куба, который находится выше.
Соответствие следует проверять после каждого вращения. Так если уже совершено 4 поворота и до сих пор нет ни одного совпадения для данного куба, берусь за следующий. Каждый проверяемый куб потенциально можно проверить и со всеми другими деталями, для этого я могу рекурсивно повторить инициализацию каждого из них с полным набором всех других кубов.
Чтобы отслеживать все манипуляции с исходными данными, я выбрал способ объектно-ориентированного программирования, в котором куб – это объект, имеющий id, число вращений и четыре стороны: верхнюю, правую, нижнюю и левую.

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

К примеру, если необходимо одно вращение (от [1,2,3,4] до [4,1,2,3]), но сначала было ошибочно совершено три вращения (в настоящее время [2,3,4,1]), в следующий раз потребуется 2 (от текущего [2,3,4,1] до необходимого [4,1,2,3]). 3 плюс 2 равно 5. И 5 % 4 = 1, а это то, что нужно.
Мне всегда нужно отслеживать используемые кубы и предотвращать повторные проверки. Для этого я использую таблицу id кубов. И если сравниваемый куб совпадает, я удаляю его из списка.

Я выбрал следующие структуры данных:

HashMap – чтобы связывать id (первоначальное положение) и куб, построенный из входной строки.
Stack – чтобы проверять связанные id кубов.
Array – для временного тестирования результата.

Код объекта куб:

image

Функции манипуляции стрингов:

image

Логика решения по поиску сочетающихся кубов:

image

Результат:

image

Челлендж: «Пинг Понг»

Описание:

Готов поспорить, что ты недостаточно быстр, чтобы победить меня.
Вот, где я:
nc 35.157.111.68 10158


Запустив данную команду, вы получаете:

image


С первого взгляда кажется, что это задачка по работе со стримами.

Однако после получения первых данных, кажется, что он попадает в Timeout, а затем и вовсе – накроется.

Когда данные заканчиваются, появляется новый разделитель строк.

Я воссоздал поток при помощи кода Python.
Кажись заработало, поэтому я добавил итеративный код, повторяющий алгоритм пинг-понга, и буду ждать, пока не появится флаг.

image

После огромного количества таких пинг-понговых перепасовок (возможно, более тысячи) между клиентом и сервером, я наконец добиваюсь цели.

image

Челлендж: «Протокол»

Описание:

Приветик!
Нам необходимо извлечь секретные данные из специального сервера. Особо много мы про него не знаем, зато нам удалось перехватить траффик, поддерживающий связь с этим сервером.
Также нам известно, что путь к этому секретному файлу таков: /usr/PRivAtE.txt

Ты можешь найти sniff файл здесь (ссылка на файл).

Пожалуйста расскажи нам, что же это за секрет!
Удачи!


Я скачал файл и открыл его с помощью Wireshark

image

И проверил зарегистрированные переговоры

image

Это позволило мне разобраться, что происходит

image

Я заметил, что там были переговоры между IP 35.157.111.68 через порт 20120 и SSH-порт 22. Надо бы проверить этот порт 20120, решил я, а затем перейти к SSH (позже я понял, что в этом не было необходимости).

Я использовал команду nc, чтобы проверить этот IP и порт, и получил ответ: «0 8 Welcome»

image

Я не был уверен, какой ввод он ожидал, поэтому я вернулся в Wireshark, чтобы посмотреть, может, там остались ещё какие-то зацепки.

Я отфильтровал все пакеты данных для 35.157.111.68 на порту 20120 и обнаружил легко читаемую беседу:

image

image

image

image

image

Я воссоздал всё это при помощи командной строки nc:

image

Я заметил, что ответ на мой «2 3 XOR» запрос отличался от того, который находился в файле.
Я повторил всю процедуру снова и снова, чтобы понять, меняется ли ответ каждый раз.

image

image
Как я и думал, полученные 4 значения каждый раз были разными, как и конечные данные.
Кажется, полученные четыре значения – это ключ к тому, чтобы расшифровать конечные данные.
Также я заметил, что цифры перед каждым пакетом данных не случайны.

Выглядит это следующим образом.

Первое число означает порядок: 0 -> первый, 1 -> второй, 2 -> третий, и т.д…
Второй номер означает длительность фразы 8 -> “Welcome”, 5 -> “Hello” ->, и т.д…

Я прикинул, а не является ли это ключом к расшифровке. Поскольку конечные данные представляют собой непрерывную строку блоков по 4 HEX значений и ключ XOR также является 4 HEX значений. Возможно, я смогу перебрать каждую и разделить на отдельные байты, после чего ксорнуть их байтами из ключа.

И я попытался выполнить расшифровку:

image

Всё получилось, но в полученных данных не было флага.

image

Я перечитал правила и вспомнил, что путь к этому секретному файлу таков: /usr/PRivAtE.txt

Я повторил процедуру снова, но в этот раз запросил путь «/usr/PRivAtE.txt»

image

Я снова попытался расшифровать окончательные данные:

image

И флаг оказался в моих руках:

image

А у вас получилось? Пишите свои идеи и варианты, буду рад комментариям.

Комментарии (2)


  1. kotermit
    09.11.2018 11:17
    +1

    С первой загадкой я не понял следующее: 1. куба с 2-умя нулями может быть 4 шт., от сюда получается должно быть 4 варианта ответа? 2. еще вопрос контролировал ли ты количество кубов в строке, да бы у тебя не получились разной длины строки? 3. И все ли кубы нужно было использовать, дабы не получилась у тебя матрица 2х2?


    1. HackerU Автор
      09.11.2018 11:17

      1) Верно, потенциальных ответов четыре.

      2) Да, именно для этого третья строка функции solve:
      int col = index % size;

      3) Да, для этого условие:
      while(!cIds.empty())