Привет всем, я Никита Куртин, куратор израильской высшей школы IT и безопасности HackerU.
И я продолжаю рассказывать про кибер испытания от ведущей израильской компании в области информационной безопасности Checkpoint. В предыдущем посте я описал как прошел четыре испытания, а в этом хочу рассказать о следующих трех, которых мне удалось пройти.
Для тех, кто пропустил первый пост расскажу, этим летом Checkpoint, опубликовала серию кибер испытаний.
Челлендж официально завершился к концу сентября 2018-го.
Задачи поделили на шесть категорий:
• Logic
• Web
• Programming
• Networking
• Reversing
• Surprise
По две задачки на каждое направление. Как я уже писал, Checkpoint до этого уже успел завоевать уважение и интерес с мой стороны, поэтому я решил принять эти вызовы. Однако ввиду занятости, смог позволить себе взяться лишь за 8 из 12 заданий (из четырёх разных категорий). И решить мне удалось 7 из них.
И так:
Челлендж: «Пазл»
Описание:
Наконец-то мы тебя нашли!
Нам необходимо собрать этот пазл, и как гласит пророчество – лишь ты один способен на это.
Пазл весьма причудлив. Он состоит из доски с 10 колонками и 10 рядами. Всего – 100 деталей. И каждая из них – несет в себе загадку! Состоят детали из четырёх долей: верхней, нижней, правой и левой. Каждая доля – это номер. Например:
Сверх – 12, справа – 3, снизу – 4 и слева – 5.
Чтобы пазл сложился, все детали должны расположиться на доске таким образом, чтобы каждая доля примыкала к равной по значению.
Вдобавок, доля, которая ни к чему не примыкает, а является частью границы доски, должна быть со значением 0. Остальные доли не могут иметь нулевое значение. Вот верный пример, состоящий из 4 деталей:
Вверху доски все доли, образующие границу равны нулю.
Рассмотрим верхнюю левую деталь. Её правая доля равна 9, и примыкающая к ней доля (левая доля верхней правой детали) также равна 9.
К сожалению, все наши детали перетасованы. Они приводятся в следующем формате:
Id куба [доли]; id куба, [доли];… id куба, [доли]
Где id куба – это номера от 0 до 99, а доли состоят из чисел, расположенных в порядке: верхнее, правое, нижнее, левое.
К примеру, посмотрите на следующую перетасованную доску:
Вот как выглядит строка, описывающая эту доску:
Нам нужно, чтобы ты сложил пазл!
Напиши нам строку, которая бы выглядела в точности как эта:
Id куба, сколько раз её нужно повернуть по часовой стрелке; id куба, сколько раз её нужно повернуть по часовой стрелке;… id куба, сколько раз её нужно повернуть по часовой стрелке
Строка с решением данной доски будет выглядеть так:
Вышеупомянутая строка соответствует следующей (решенной) головоломке:
Рассмотрим верхнюю левую деталь. В строке она соответствует обозначению «2,2». Как мы берем куб номер 2 от ввода:
Но мы крутим его по часовой стрелке дважды и получаем [0,19,5,0].
Теперь рассмотрим верхнюю среднюю деталь. В строке она соответствует обозначению «1,0». Поэтому мы берем куб номер 1 от ввода:
И уже вовсе не крутим его (да-да, крутить 0 раз) – значит он уже в правильном положении.
Уловил?
Теперь помоги нам сложить пазл!
Выглядит он следующим образом:
Удачи!
Теоретически эта задача может быть решена множеством различных способов. Найди свой и поделись им. Я размышлял над несколькими вариантами и в конце концов пришёл к следующим выводам:
Первое. В любое заданное время мне лишь нужно определить один куб. Для каждого куба я всегда наверняка буду знать две стороны: верхнюю и левую. В начале это 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 – для временного тестирования результата.
Код объекта куб:
Функции манипуляции стрингов:
Логика решения по поиску сочетающихся кубов:
Результат:
Челлендж: «Пинг Понг»
Описание:
Готов поспорить, что ты недостаточно быстр, чтобы победить меня.
Вот, где я:
nc 35.157.111.68 10158
Запустив данную команду, вы получаете:
С первого взгляда кажется, что это задачка по работе со стримами.
Однако после получения первых данных, кажется, что он попадает в Timeout, а затем и вовсе – накроется.
Когда данные заканчиваются, появляется новый разделитель строк.
Я воссоздал поток при помощи кода Python.
Кажись заработало, поэтому я добавил итеративный код, повторяющий алгоритм пинг-понга, и буду ждать, пока не появится флаг.
После огромного количества таких пинг-понговых перепасовок (возможно, более тысячи) между клиентом и сервером, я наконец добиваюсь цели.
Челлендж: «Протокол»
Описание:
Приветик!
Нам необходимо извлечь секретные данные из специального сервера. Особо много мы про него не знаем, зато нам удалось перехватить траффик, поддерживающий связь с этим сервером.
Также нам известно, что путь к этому секретному файлу таков: /usr/PRivAtE.txt
Ты можешь найти sniff файл здесь (ссылка на файл).
Пожалуйста расскажи нам, что же это за секрет!
Удачи!
Я скачал файл и открыл его с помощью Wireshark
И проверил зарегистрированные переговоры
Это позволило мне разобраться, что происходит
Я заметил, что там были переговоры между IP 35.157.111.68 через порт 20120 и SSH-порт 22. Надо бы проверить этот порт 20120, решил я, а затем перейти к SSH (позже я понял, что в этом не было необходимости).
Я использовал команду nc, чтобы проверить этот IP и порт, и получил ответ: «0 8 Welcome»
Я не был уверен, какой ввод он ожидал, поэтому я вернулся в Wireshark, чтобы посмотреть, может, там остались ещё какие-то зацепки.
Я отфильтровал все пакеты данных для 35.157.111.68 на порту 20120 и обнаружил легко читаемую беседу:
Я воссоздал всё это при помощи командной строки nc:
Я заметил, что ответ на мой «2 3 XOR» запрос отличался от того, который находился в файле.
Я повторил всю процедуру снова и снова, чтобы понять, меняется ли ответ каждый раз.
Как я и думал, полученные 4 значения каждый раз были разными, как и конечные данные.
Кажется, полученные четыре значения – это ключ к тому, чтобы расшифровать конечные данные.
Также я заметил, что цифры перед каждым пакетом данных не случайны.
Выглядит это следующим образом.
Первое число означает порядок: 0 -> первый, 1 -> второй, 2 -> третий, и т.д…
Второй номер означает длительность фразы 8 -> “Welcome”, 5 -> “Hello” ->, и т.д…
Я прикинул, а не является ли это ключом к расшифровке. Поскольку конечные данные представляют собой непрерывную строку блоков по 4 HEX значений и ключ XOR также является 4 HEX значений. Возможно, я смогу перебрать каждую и разделить на отдельные байты, после чего ксорнуть их байтами из ключа.
И я попытался выполнить расшифровку:
Всё получилось, но в полученных данных не было флага.
Я перечитал правила и вспомнил, что путь к этому секретному файлу таков: /usr/PRivAtE.txt
Я повторил процедуру снова, но в этот раз запросил путь «/usr/PRivAtE.txt»
Я снова попытался расшифровать окончательные данные:
И флаг оказался в моих руках:
А у вас получилось? Пишите свои идеи и варианты, буду рад комментариям.
И я продолжаю рассказывать про кибер испытания от ведущей израильской компании в области информационной безопасности Checkpoint. В предыдущем посте я описал как прошел четыре испытания, а в этом хочу рассказать о следующих трех, которых мне удалось пройти.
Для тех, кто пропустил первый пост расскажу, этим летом Checkpoint, опубликовала серию кибер испытаний.
Челлендж официально завершился к концу сентября 2018-го.
Задачи поделили на шесть категорий:
• Logic
• Web
• Programming
• Networking
• Reversing
• Surprise
По две задачки на каждое направление. Как я уже писал, Checkpoint до этого уже успел завоевать уважение и интерес с мой стороны, поэтому я решил принять эти вызовы. Однако ввиду занятости, смог позволить себе взяться лишь за 8 из 12 заданий (из четырёх разных категорий). И решить мне удалось 7 из них.
И так:
Челлендж: «Пазл»
Описание:
Наконец-то мы тебя нашли!
Нам необходимо собрать этот пазл, и как гласит пророчество – лишь ты один способен на это.
Пазл весьма причудлив. Он состоит из доски с 10 колонками и 10 рядами. Всего – 100 деталей. И каждая из них – несет в себе загадку! Состоят детали из четырёх долей: верхней, нижней, правой и левой. Каждая доля – это номер. Например:
Сверх – 12, справа – 3, снизу – 4 и слева – 5.
Чтобы пазл сложился, все детали должны расположиться на доске таким образом, чтобы каждая доля примыкала к равной по значению.
Вдобавок, доля, которая ни к чему не примыкает, а является частью границы доски, должна быть со значением 0. Остальные доли не могут иметь нулевое значение. Вот верный пример, состоящий из 4 деталей:
Вверху доски все доли, образующие границу равны нулю.
Рассмотрим верхнюю левую деталь. Её правая доля равна 9, и примыкающая к ней доля (левая доля верхней правой детали) также равна 9.
К сожалению, все наши детали перетасованы. Они приводятся в следующем формате:
Id куба [доли]; id куба, [доли];… id куба, [доли]
Где id куба – это номера от 0 до 99, а доли состоят из чисел, расположенных в порядке: верхнее, правое, нижнее, левое.
К примеру, посмотрите на следующую перетасованную доску:
Вот как выглядит строка, описывающая эту доску:
Нам нужно, чтобы ты сложил пазл!
Напиши нам строку, которая бы выглядела в точности как эта:
Id куба, сколько раз её нужно повернуть по часовой стрелке; id куба, сколько раз её нужно повернуть по часовой стрелке;… id куба, сколько раз её нужно повернуть по часовой стрелке
Строка с решением данной доски будет выглядеть так:
Вышеупомянутая строка соответствует следующей (решенной) головоломке:
Рассмотрим верхнюю левую деталь. В строке она соответствует обозначению «2,2». Как мы берем куб номер 2 от ввода:
Но мы крутим его по часовой стрелке дважды и получаем [0,19,5,0].
Теперь рассмотрим верхнюю среднюю деталь. В строке она соответствует обозначению «1,0». Поэтому мы берем куб номер 1 от ввода:
И уже вовсе не крутим его (да-да, крутить 0 раз) – значит он уже в правильном положении.
Уловил?
Теперь помоги нам сложить пазл!
Выглядит он следующим образом:
Удачи!
Теоретически эта задача может быть решена множеством различных способов. Найди свой и поделись им. Я размышлял над несколькими вариантами и в конце концов пришёл к следующим выводам:
Первое. В любое заданное время мне лишь нужно определить один куб. Для каждого куба я всегда наверняка буду знать две стороны: верхнюю и левую. В начале это 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 – для временного тестирования результата.
Код объекта куб:
Функции манипуляции стрингов:
Логика решения по поиску сочетающихся кубов:
Результат:
Челлендж: «Пинг Понг»
Описание:
Готов поспорить, что ты недостаточно быстр, чтобы победить меня.
Вот, где я:
nc 35.157.111.68 10158
Запустив данную команду, вы получаете:
С первого взгляда кажется, что это задачка по работе со стримами.
Однако после получения первых данных, кажется, что он попадает в Timeout, а затем и вовсе – накроется.
Когда данные заканчиваются, появляется новый разделитель строк.
Я воссоздал поток при помощи кода Python.
Кажись заработало, поэтому я добавил итеративный код, повторяющий алгоритм пинг-понга, и буду ждать, пока не появится флаг.
После огромного количества таких пинг-понговых перепасовок (возможно, более тысячи) между клиентом и сервером, я наконец добиваюсь цели.
Челлендж: «Протокол»
Описание:
Приветик!
Нам необходимо извлечь секретные данные из специального сервера. Особо много мы про него не знаем, зато нам удалось перехватить траффик, поддерживающий связь с этим сервером.
Также нам известно, что путь к этому секретному файлу таков: /usr/PRivAtE.txt
Ты можешь найти sniff файл здесь (ссылка на файл).
Пожалуйста расскажи нам, что же это за секрет!
Удачи!
Я скачал файл и открыл его с помощью Wireshark
И проверил зарегистрированные переговоры
Это позволило мне разобраться, что происходит
Я заметил, что там были переговоры между IP 35.157.111.68 через порт 20120 и SSH-порт 22. Надо бы проверить этот порт 20120, решил я, а затем перейти к SSH (позже я понял, что в этом не было необходимости).
Я использовал команду nc, чтобы проверить этот IP и порт, и получил ответ: «0 8 Welcome»
Я не был уверен, какой ввод он ожидал, поэтому я вернулся в Wireshark, чтобы посмотреть, может, там остались ещё какие-то зацепки.
Я отфильтровал все пакеты данных для 35.157.111.68 на порту 20120 и обнаружил легко читаемую беседу:
Я воссоздал всё это при помощи командной строки nc:
Я заметил, что ответ на мой «2 3 XOR» запрос отличался от того, который находился в файле.
Я повторил всю процедуру снова и снова, чтобы понять, меняется ли ответ каждый раз.
Как я и думал, полученные 4 значения каждый раз были разными, как и конечные данные.
Кажется, полученные четыре значения – это ключ к тому, чтобы расшифровать конечные данные.
Также я заметил, что цифры перед каждым пакетом данных не случайны.
Выглядит это следующим образом.
Первое число означает порядок: 0 -> первый, 1 -> второй, 2 -> третий, и т.д…
Второй номер означает длительность фразы 8 -> “Welcome”, 5 -> “Hello” ->, и т.д…
Я прикинул, а не является ли это ключом к расшифровке. Поскольку конечные данные представляют собой непрерывную строку блоков по 4 HEX значений и ключ XOR также является 4 HEX значений. Возможно, я смогу перебрать каждую и разделить на отдельные байты, после чего ксорнуть их байтами из ключа.
И я попытался выполнить расшифровку:
Всё получилось, но в полученных данных не было флага.
Я перечитал правила и вспомнил, что путь к этому секретному файлу таков: /usr/PRivAtE.txt
Я повторил процедуру снова, но в этот раз запросил путь «/usr/PRivAtE.txt»
Я снова попытался расшифровать окончательные данные:
И флаг оказался в моих руках:
А у вас получилось? Пишите свои идеи и варианты, буду рад комментариям.
kotermit
С первой загадкой я не понял следующее: 1. куба с 2-умя нулями может быть 4 шт., от сюда получается должно быть 4 варианта ответа? 2. еще вопрос контролировал ли ты количество кубов в строке, да бы у тебя не получились разной длины строки? 3. И все ли кубы нужно было использовать, дабы не получилась у тебя матрица 2х2?
HackerU Автор
1) Верно, потенциальных ответов четыре.
2) Да, именно для этого третья строка функции solve:
int col = index % size;
3) Да, для этого условие:
while(!cIds.empty())