IMG_20250320_141657_803.jpg
154.6 KB
Друзья, публикуем для вас два райтапа с Tinkoff CTF 2024 от ТОП-10 на Codeby Games!
"Элементарно, Ватсон!" от @Max_RSC
Я выделяю два основных способа решить "Ватсона": посредством программирования и классическим методом с помощью двух цилиндров и ленты из бумаги. К сожалению, и тот, и другой способы достаточно продолжительные по времени. Поскольку речь идет о соревнованиях, мы не можем себе позволить тратить время там, где его тратить вовсе не обязательно. Я опишу третий способ: быстрое решение с помощью онлайн-сервиса.
Вам наверняка известно, что шифр, который дан – это модифицированный вариант скиталы, она же сцитала, она же шифр Древней Спарты, достаточно эффективный для своего времени шифр. Насколько мне известно, первым работу скиталы описал Плутарх. Разумеется, изобретателем этого шифра философ не является.
В отличие от оригинальной скиталы в "ватсоновском" варианте используется два шифровальных цилиндра вместо одного, а также добавлена пара других усложнений. Однако схема решения остается прежней: нужно найти ключ. В оригинальной скитале ключом выступают длина и диаметр цилиндра. В данном случае ключ – это количеств букв на виток.
Мы воспользуемся замечательным сеpвиcом dCode. В поиске находим Scytale Cipher, вставляем шифртекст в соответствующее поле, просим сохранить пунктуацию (Keep punctuation and spaces), выбираем опцию Try all possible sizes, другими словами запускаем брутфорс-атаку и... видим, что у нас ничего не вышло: все еще нечитаемый текст. Почему так? Потому что мы не указали ключ – количество букв на виток, за это отвечает опция Number of letters per turn of band.
Я предвижу вопрос: "Максим, но как узнать длину ключа?". Есть много способов, я назову самый очевидный: перебор всех возможных вариантов – всех возможных длин. Перебор займет не больше пяти минут, потому что длина ключа – 32 буквы на виток. Результат можно наблюдать на скриншоте.
Хочу отметить, что в картотекe, которую мы расшифровали, будет присутствовать не один флаг, а несколько. Правильный флаг начинается с "tctf{Cr1...". Строки разбиты, но продолжение флага долго искать не придется.
"Глухой видеофон" от @Max_RSC
Открываем hex-редактор, изучаем картинку. Отсутствие маркера FF D9 в конце файла позволяет нам понять, что в картинке может быть спрятан другой файл.
Продолжаем изучение, например с помощью утилиты strings. Hаходим сигнатуру "....ftypisom" – это однозначно говорит о том, что в картинке спрятан файл формата mp4. Нам осталось лишь извлечь этот файл из картинки. Для этого я написал скрипт на Питоне: в цикле for последовательно перебираются байты картинки до тех пор, пока не найдется сигнатура 0000001с6674797069736f ("....ftypisom" в hex-нотации), сразу после этого все в том же цикле создается файл result.mp4, куда записываются байты, начиная с сигнатуры. Здесь важно убедиться, что скрипт корректно обрабатывает байты и не пропускает важные данные. Последним шагом в скрипте выполняется операция from hex.
Теперь запускаем result.mp4 как видеоролик любым просмотрщиком – в видеоролике и будет находиться флаг.
#crypto #stegano #TinkoffCTF2024
"Элементарно, Ватсон!" от @Max_RSC
Я выделяю два основных способа решить "Ватсона": посредством программирования и классическим методом с помощью двух цилиндров и ленты из бумаги. К сожалению, и тот, и другой способы достаточно продолжительные по времени. Поскольку речь идет о соревнованиях, мы не можем себе позволить тратить время там, где его тратить вовсе не обязательно. Я опишу третий способ: быстрое решение с помощью онлайн-сервиса.
Вам наверняка известно, что шифр, который дан – это модифицированный вариант скиталы, она же сцитала, она же шифр Древней Спарты, достаточно эффективный для своего времени шифр. Насколько мне известно, первым работу скиталы описал Плутарх. Разумеется, изобретателем этого шифра философ не является.
В отличие от оригинальной скиталы в "ватсоновском" варианте используется два шифровальных цилиндра вместо одного, а также добавлена пара других усложнений. Однако схема решения остается прежней: нужно найти ключ. В оригинальной скитале ключом выступают длина и диаметр цилиндра. В данном случае ключ – это количеств букв на виток.
Мы воспользуемся замечательным сеpвиcом dCode. В поиске находим Scytale Cipher, вставляем шифртекст в соответствующее поле, просим сохранить пунктуацию (Keep punctuation and spaces), выбираем опцию Try all possible sizes, другими словами запускаем брутфорс-атаку и... видим, что у нас ничего не вышло: все еще нечитаемый текст. Почему так? Потому что мы не указали ключ – количество букв на виток, за это отвечает опция Number of letters per turn of band.
Я предвижу вопрос: "Максим, но как узнать длину ключа?". Есть много способов, я назову самый очевидный: перебор всех возможных вариантов – всех возможных длин. Перебор займет не больше пяти минут, потому что длина ключа – 32 буквы на виток. Результат можно наблюдать на скриншоте.
Хочу отметить, что в картотекe, которую мы расшифровали, будет присутствовать не один флаг, а несколько. Правильный флаг начинается с "tctf{Cr1...". Строки разбиты, но продолжение флага долго искать не придется.
"Глухой видеофон" от @Max_RSC
Открываем hex-редактор, изучаем картинку. Отсутствие маркера FF D9 в конце файла позволяет нам понять, что в картинке может быть спрятан другой файл.
Продолжаем изучение, например с помощью утилиты strings. Hаходим сигнатуру "....ftypisom" – это однозначно говорит о том, что в картинке спрятан файл формата mp4. Нам осталось лишь извлечь этот файл из картинки. Для этого я написал скрипт на Питоне: в цикле for последовательно перебираются байты картинки до тех пор, пока не найдется сигнатура 0000001с6674797069736f ("....ftypisom" в hex-нотации), сразу после этого все в том же цикле создается файл result.mp4, куда записываются байты, начиная с сигнатуры. Здесь важно убедиться, что скрипт корректно обрабатывает байты и не пропускает важные данные. Последним шагом в скрипте выполняется операция from hex.
Теперь запускаем result.mp4 как видеоролик любым просмотрщиком – в видеоролике и будет находиться флаг.
#crypto #stegano #TinkoffCTF2024
❤10👍1🔥1
#crypto
Алиса не знает алгебру
Автор: @Max_RSC (ТОП-10 на платформе Codeby Games)
Ссылка на задание 🚩
Прежде всего отмечу два важных момента:
1. Если вы не математик, для решения таска вам потребуется уверенный навык программирования на языке Python. Надеюсь, это понятно.
2. В процессе решения таска ни в коем случае не разрывайте соединение с сервером, иначе работу придется начинать по новой.
Подключаемся к серверу:
Мы получили значения N, e_1 и e_2. Скопируем их куда-нибудь — еще пригодятся.
В подавляющем большинстве случаев в тасках, где фигурирует RSA, мы имеем дело с реализацией одноименного алгоритма, имеющей ту или иную уязвимость. В данном случае уязвимость заключается в том, что используются две экспоненты e_1 и e_2 вместо одной e, как должно быть в RSA. Подобное "нововведение" сразу наводит на мысль о Common Modulus Attack.
Внимательно изучив скрипт, который нам предоставили организаторы, мы сможем понять логику работу сервера: одно и то же сообщение шифруется с использованием сначала одной экспоненты e_1 и модуля N, затем с использованием другой экспоненты e_2 и модуля N. На выходе получается не один шифртекст c как должно быть, а два разных шифртекста c1 и c2. Это серьезная уязвимость и в CTF мы еще не раз встретим подобные таски.
Возвращаемся к серверу. Про действия [1] и [2] в принципе можно забыть, так как для решения таска они не понадобятся. Выбираем действие [4]. Сервер отдает нам два шифртекста, каждый из которых представляет собой сообщение, зашифрованное с использованием одного и того же модуля, но разных экспонент. Думаю, вы уже сообразили, что эти шифртексты уязвимы для Common Modulus Attack. Давайте договоримся, что в данном случае первый шифртекст — это c1, a второй — это c2. Однако шифртексты нам даны в hex-формате. Значит, прежде чем мы сможем с ними работать, нужно перевести эти два шифртекста из hex-формата в base10. Сделаем это с помощью Питона:
Теперь воспользуемся скриптом, который любезно расшифрует для нас ключ:
Если на вашей машине нет библиотеки libnum, то для начала придется ее установить:
Выполнив скрипт, мы получим расшифрованный ключ, который, разумеется, я вам не покажу, чтобы вы не жульничали, а сделали хоть что-нибудь самостоятельно и следовательно, научились чему-нибудь новому.
Возвращаемся к серверу и на этот раз выбираем действие [3]. Вводим расшифрованный ключ, после чего сервер отдаст нам флаг.
#codebygames
Алиса не знает алгебру
Автор: @Max_RSC (ТОП-10 на платформе Codeby Games)
Ссылка на задание 🚩
Прежде всего отмечу два важных момента:
1. Если вы не математик, для решения таска вам потребуется уверенный навык программирования на языке Python. Надеюсь, это понятно.
2. В процессе решения таска ни в коем случае не разрывайте соединение с сервером, иначе работу придется начинать по новой.
Подключаемся к серверу:
nc 62.173.140.174 11002
Мы получили значения N, e_1 и e_2. Скопируем их куда-нибудь — еще пригодятся.
В подавляющем большинстве случаев в тасках, где фигурирует RSA, мы имеем дело с реализацией одноименного алгоритма, имеющей ту или иную уязвимость. В данном случае уязвимость заключается в том, что используются две экспоненты e_1 и e_2 вместо одной e, как должно быть в RSA. Подобное "нововведение" сразу наводит на мысль о Common Modulus Attack.
Внимательно изучив скрипт, который нам предоставили организаторы, мы сможем понять логику работу сервера: одно и то же сообщение шифруется с использованием сначала одной экспоненты e_1 и модуля N, затем с использованием другой экспоненты e_2 и модуля N. На выходе получается не один шифртекст c как должно быть, а два разных шифртекста c1 и c2. Это серьезная уязвимость и в CTF мы еще не раз встретим подобные таски.
Возвращаемся к серверу. Про действия [1] и [2] в принципе можно забыть, так как для решения таска они не понадобятся. Выбираем действие [4]. Сервер отдает нам два шифртекста, каждый из которых представляет собой сообщение, зашифрованное с использованием одного и того же модуля, но разных экспонент. Думаю, вы уже сообразили, что эти шифртексты уязвимы для Common Modulus Attack. Давайте договоримся, что в данном случае первый шифртекст — это c1, a второй — это c2. Однако шифртексты нам даны в hex-формате. Значит, прежде чем мы сможем с ними работать, нужно перевести эти два шифртекста из hex-формата в base10. Сделаем это с помощью Питона:
c1_hex = '43e2b4c84aff770b7388499cc2af2535655de75aa333b5e97fbe1f45b626c9d5b09901a5863ff2da652018058a9e87110b721c40593ac4d36ccdf1b3933d5dd2'
c1 = int(c1_hex, 16)
c2_hex = '55e70b7b592aa36ec9a7d61e4bd7930d590447cc1a243f2aeba2ff132e42bd8dcc1a4fdfef8659ed5f9aa96724290f2cdc80a6e353849b3d51c1524b071cea34'
c2 = int(c2_hex, 16)
Теперь воспользуемся скриптом, который любезно расшифрует для нас ключ:
from libnum import *
def common_modulus(e1, e2, c1, c2, N):
a, b, d = xgcd(e1,e2)
if b < 0:
c2 = invmod(c2, N)
b = -b
if a < 0:
c1 = invmod(c1, N)
a = -a
m = (pow(c1,a,N) * pow(c2,b,N)) % N
return [m, a, b, d]
def pad(m, d, i, N):
if -d*4*i < 0:
f = pow(invmod(2, N), d*4*i, N)
else:
f = pow(2, -d*4*i, N)
return m * f % N
N = # сюда пишем нашу N
e_1 = # сюда пишем нашу e_1
c1 = # сюда пишем нашу c1
e_2 = # сюда пишем нашу e_2
c2 = # сюда нашу c2
m, _, _, _ = common_modulus(e_1,e_2,c1,c2,N) plaintext = n2s(m)
print(plaintext.decode())
Если на вашей машине нет библиотеки libnum, то для начала придется ее установить:
pip install libnum
Выполнив скрипт, мы получим расшифрованный ключ, который, разумеется, я вам не покажу, чтобы вы не жульничали, а сделали хоть что-нибудь самостоятельно и следовательно, научились чему-нибудь новому.
Возвращаемся к серверу и на этот раз выбираем действие [3]. Вводим расшифрованный ключ, после чего сервер отдаст нам флаг.
#codebygames
❤7🔥3🤯1
#crypto
Нулевой шифр
От @Max_RSC (ТОП-10 на платформе Codeby Games)
Ссылка на задание
Для решения таска потребуется уверенный навык программирования на Python. Надеюсь, это понятно.
Сначала заглянем в request.txt. В GET-запросе видим параметр FLAG со значением в виде строки, обернутой в base64:
FLAG=lUmU56gHyTe0DabyGJIZEI9mGyx/4NG1tX8yhml1KmQWEdfQ3TNNkU3z1w==
Скопируем эту строку куда-нибудь — еще пригодится. Про файл request.txt можно забыть, больше он не понадобится.
Идем в sourceCode.txt.
Эта строка сообщает нам о том, что используется алгоритм шифрования RC4, он же ARC4, он же Rivest Cipher 4. По сегодняшним меркам этот алгоритм шифрования считается устаревшим и больше не является криптографически безопасным.
Эти строки сообщают нам о том, что ключ — это первые шесть символов флага. Другими словами, CODEBY.
Эта строка сообщает нам о том, что ключ хешируется, но для шифрования используются лишь первые 16 байт ключа. Мы получили всю необходимую информацию и теперь можем с легкостью расшифровать флаг. Кстати, не рекомендую делать это посредством онлайн-декодера — скорее всего, у вас ничего не получится, да и необходимости в этом нет. Все что нужно сделать — это лишь немного переписать код. Приступаем:
Третью, четвертую и пятую строки можно скопировать из функции без изменений.
Прилагаю скрипт целиком с моими комментариями:
Выполняем скрипт и получаем флаг.
Рекомендую не бездумно копировать скрипт, а подумать над прочитанным и написать скрипт самостоятельно. Помните, что цель решения таска — это не получить флаг и чуть-чуть подняться в рейтинге, а научиться чему-нибудь новому.
#codebygames
Нулевой шифр
От @Max_RSC (ТОП-10 на платформе Codeby Games)
Ссылка на задание
Для решения таска потребуется уверенный навык программирования на Python. Надеюсь, это понятно.
Сначала заглянем в request.txt. В GET-запросе видим параметр FLAG со значением в виде строки, обернутой в base64:
FLAG=lUmU56gHyTe0DabyGJIZEI9mGyx/4NG1tX8yhml1KmQWEdfQ3TNNkU3z1w==
Скопируем эту строку куда-нибудь — еще пригодится. Про файл request.txt можно забыть, больше он не понадобится.
Идем в sourceCode.txt.
cipher = Cipher(algorithms.ARC4(hashed_key), mode=None, backend=default_backend())
Эта строка сообщает нам о том, что используется алгоритм шифрования RC4, он же ARC4, он же Rivest Cipher 4. По сегодняшним меркам этот алгоритм шифрования считается устаревшим и больше не является криптографически безопасным.
FLAG = '******{***********************************}'.encode()
key = FLAG[:6]Эти строки сообщают нам о том, что ключ — это первые шесть символов флага. Другими словами, CODEBY.
hashed_key = hashlib.sha256(key).digest()[:16]
Эта строка сообщает нам о том, что ключ хешируется, но для шифрования используются лишь первые 16 байт ключа. Мы получили всю необходимую информацию и теперь можем с легкостью расшифровать флаг. Кстати, не рекомендую делать это посредством онлайн-декодера — скорее всего, у вас ничего не получится, да и необходимости в этом нет. Все что нужно сделать — это лишь немного переписать код. Приступаем:
key = b'CODEBY'
FLAG= base64.b64decode('lUmU56gHyTe0DabyGJIZEI9mGyx/4NG1tX8yhml1KmQWEdfQ3TNNkU3z1w==')
Третью, четвертую и пятую строки можно скопировать из функции без изменений.
Прилагаю скрипт целиком с моими комментариями:
# Подключаем нужные библиотеки (или устанавливаем, если их нет)
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64
import hashlib
# Декодируем флаг из base64
FLAG= base64.b64decode('lUmU56gHyTe0DabyGJIZEI9mGyx/4NG1tX8yhml1KmQWEdfQ3TNNkU3z1w==')
# Обратите внимание, что ключ — это байтовая строка
key = b'CODEBY'
# Хешируем ключ, но используем лишь его первые 16 байт
hashed_key = hashlib.sha256(key).digest()[:16]
# Указываем, что хотим использовать алгоритм шифрования ARC4
cipher = Cipher(algorithms.ARC4(hashed_key), mode=None, backend=default_backend())
encryptor = cipher.encryptor()
# Передаем флаг на вход функции, которая производит расшифровку
ct = encryptor.update(FLAG) + encryptor.finalize()
# Печатаем флаг
print(ct)
Выполняем скрипт и получаем флаг.
Рекомендую не бездумно копировать скрипт, а подумать над прочитанным и написать скрипт самостоятельно. Помните, что цель решения таска — это не получить флаг и чуть-чуть подняться в рейтинге, а научиться чему-нибудь новому.
#codebygames
❤11🔥1
#crypto
Веселый RSA
От @Max_RSC (ТОП-10 на платформе Codeby Games)
Ссылка на задание
Даны три шифртекста, которые представляют собой одно и то же сообщение. Подсказка намекает, что Боб плохо разбирается в RSA, поэтому при шифровании допустил серьезную ошибку. Действительно, мы видим, что вместо стандартной экспоненты e = 65537 он использовал значения 5, 7 и 13, a модули n1, n2 и n3 настолько малы, что с легкостью раскладываются на множители. Это можно назвать критической уязвимостью.
Если мы возьмем первое по счету сообщение и попробуем вычислить приватную экспоненту d, то поймем, что это невозможно:
На простом языке это означает, что в процессе шифрования пользователь допустил фатальную ошибку.
Возьмем второе по счету сообщение и попробуем найти приватную экспоненту d – то же самое:
Возьмем третье по счету сообщение. Похоже, что это сообщение было зашифровано правильно, а значит, можно вычислить d:
После нахождения d мы с легкостью расшифровываем шифртекст:
Мы получили трехзначное число, которое, разумеется, я вам не покажу, чтобы вы не жульничали, а решили таск самостоятельно и следовательно, научились чему-нибудь новому.
Считаем от этого числа хеш-сумму по алгоритму SHA256:
Получившуюся строку обoрачиваем в CODEBY и сдаем флаг.
#codebygames
Веселый RSA
От @Max_RSC (ТОП-10 на платформе Codeby Games)
Ссылка на задание
Даны три шифртекста, которые представляют собой одно и то же сообщение. Подсказка намекает, что Боб плохо разбирается в RSA, поэтому при шифровании допустил серьезную ошибку. Действительно, мы видим, что вместо стандартной экспоненты e = 65537 он использовал значения 5, 7 и 13, a модули n1, n2 и n3 настолько малы, что с легкостью раскладываются на множители. Это можно назвать критической уязвимостью.
Если мы возьмем первое по счету сообщение и попробуем вычислить приватную экспоненту d, то поймем, что это невозможно:
>>> d = pow(e, -1, phi)
Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: base is not invertible for the given modulus
На простом языке это означает, что в процессе шифрования пользователь допустил фатальную ошибку.
Возьмем второе по счету сообщение и попробуем найти приватную экспоненту d – то же самое:
>>> d = pow(e, -1, phi)
Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: base is not invertible for the given modulus
Возьмем третье по счету сообщение. Похоже, что это сообщение было зашифровано правильно, а значит, можно вычислить d:
>>> d = pow(e, -1, phi)
>>> d
# 288613
После нахождения d мы с легкостью расшифровываем шифртекст:
>>> message = pow(c, d, n)
Мы получили трехзначное число, которое, разумеется, я вам не покажу, чтобы вы не жульничали, а решили таск самостоятельно и следовательно, научились чему-нибудь новому.
Считаем от этого числа хеш-сумму по алгоритму SHA256:
>>> from hashlib import sha256
>>> result = sha256(str(message).encode()).hexdigest()
Получившуюся строку обoрачиваем в CODEBY и сдаем флаг.
#codebygames
❤9🔥2