• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

CTF Codeby Games - Абсолютная безопасность [Writeup]

Kevgen

Green Team
04.08.2020
41
84
BIT
375

absolute_security.jpg


Всем привет!

Сегодня рассмотрим задание "Абсолютная безопасность" из раздела криптографии на Codeby Games.

Итак, приступим!​


Ищем вектор

Нам дается IP'шник, и три подсказки:
  • Возможно проверка на утечку флага является "узким местом"?
  • Вы не любите кошек? Да вы просто не умеете их готовить!
  • Я думаю стоит накапливать зашифрованные флаги.

Откроем IP. Видим, что он обнаружил контент, который не может обработать браузер.

ip_error_response.png


Поэтому смотрим на вторую подсказку и запускаем netcat (для винды - ncat) и подключаемся: ncat 62.173.140.174 11000

Для взаимодействия у нас есть две команды: "request" и "exit". Если с "exit" все ясно, то с "request" нет. Для этого смотрим вверх и видим кусок кода, который используется при отправке request'а.

ip_ncat.png


Python:
async def gen_enc_flag():
    rand_bytes = urandom(23)
    enc = bytes(i ^ j for i, j in zip(flag, rand_bytes))
    for i in range(23):
        assert enc[i] != flag[i], "leak detected"
    return enc.hex()

Я в коде не силен, поэтому просто загрузил код в ChatGPT :)

code_chatGPT.png


За его ответ судить не берусь, но общее понимание появилось.
Сначала функция генерирует 23 рандомных байта, далее она делает XOR байта первого символа флага с первым сгенерированным байтом, потом тоже самое со вторым и.т.д.
После XOR'ов всех символов флага программа проверяет на равенство каждый байт зашифрованного флага и изначального. Если таковой есть, то печатает "Leaked some plaintext".

Получается, что в каждом зашифрованном флаге на своем месте нет ни одного символа от изначального.
Т.е если флаг - CODEBY{eto_ne_flag}, то первый байт (43 для "C") нам никогда не встретится. Тоже самое и для остальных символов.

Сбор флагов

Тут мы обращаемся к третьей подсказке "Я думаю, стоит накапливать зашифрованные флаги". Осталось определиться с количеством собираемых флагов. Слышал, что 5000 достаточно, но я определил для себя - 30000. Так сказать, наверняка :).

Ясно дело, что вручную это ооочень долго, поэтому автоматизируем, используя pynput для ввода с клавиатуры.

Сам код:
Python:
import time
import pynput
from pynput.keyboard import Key, Controller
keyboard = Controller()  # Create the controller
i=0
time.sleep(10)
while i<30000 :
    keyboard.type('request')
    time.sleep(0.1)
    keyboard.press(Key.enter)
    time.sleep(0.1)
    i+=1

Перед тем, как запускать, идем обратно в netcat, останавливаем и опять запускаем, но уже с записью в файл: ncat 62.173.140.174 11000 -o dump.txt
Запускаем скрипт и переходим в окно netcat'а.
Ждем. Сборка 30000 шифрованных флагов у меня заняла ≈ 1.5-2 часа.

По окончании сбора флагов получаем файл. Теперь нам надо почистить файл от лишнего, оставив только флаги. Открываем VSCode и удаляем ненужное. Я не стал это автоматизировать, т.к делается это за две минуты простой заменой.

Наш дамп до:

dump_before.png


После:

dump_after.png

Находим флаг

Теперь создаем второй скрипт для нахождения флага:

Python:
start = 0
end = 2

two_bytes = []
text = ''
hex_numbers = ['00','01','02','03','04','05','06','07','08','09','0a','0b','0c','0d','0e','0f',
               '10','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f',
               '20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f',
               '30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f',
               '40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f',
               '50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f',
               '60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f',
               '70','71','72','73','74','75','76','77','78','79','7a','7b','7c','7d','7e','7f',
               '80','81','82','83','84','85','86','87','88','89','8a','8b','8c','8d','8e','8f',
               '90','91','92','93','94','95','96','97','98','99','9a','9b','9c','9d','9e','9f',
               'a0','a1','a2','a3','a4','a5','a6','a7','a8','a9','aa','ab','ac','ad','ae','af',
               'b0','b1','b2','b3','b4','b5','b6','b7','b8','b9','ba','bb','bc','bd','be','bf',
               'c0','c1','c2','c3','c4','c5','c6','c7','c8','c9','ca','cb','cc','cd','ce','cf',
               'd0','d1','d2','d3','d4','d5','d6','d7','d8','d9','da','db','dc','dd','de','df',
               'e0','e1','e2','e3','e4','e5','e6','e7','e8','e9','ea','eb','ec','ed','ee','ef',
               'f0','f1','f2','f3','f4','f5','f6','f7','f8','f9','fa','fb','fc','fd','fe','ff',]

remove = "{}'"
for i in range(23):
    with open('C:/Users/event/Desktop/dump.txt', 'r') as f:
     for line in f:
        first_two = line[start:end]
        two_bytes.append(first_two)
    data = set(hex_numbers) - set(two_bytes)
    clear_data = ''.join([char for char in data if char not in remove])
    bytes_object = bytes.fromhex(clear_data)
    text = "".join([text, bytes_object.decode("utf-8")])
    start += 2
    end += 2
    two_bytes = []
    print(text)

Здесь мы объявляем массив всех hex-символов (hex_numbers).
Далее достаем все hex-значения символов из дампа и находим единственное неиспользованное. Его перегоняем в ASCII и добавляем в text.

Запускаем, получаем флаг, сдаем. :cool:

Спасибо за прочтение!

Есть критика или пожелание - пишите!)
 
Последнее редактирование модератором:

Exited3n

Red Team
10.05.2022
694
248
BIT
541

Всем привет!

Сегодня рассмотрим задание "Абсолютная безопасность" из криптографии от Codeby Games.

Итак, приступим!​


Ищем вектор

Нам дается IP'шник, и три подсказки:
  • Возможно проверка на утечку флага является "узким местом"?
  • Вы не любите кошек? Да вы просто не умеете их готовить!
  • Я думаю стоит накапливать зашифрованные флаги.

Откроем IP. Видим, что он обнаружил контент, который не может обработать браузер.

Посмотреть вложение 70988

Поэтому смотрим на вторую подсказку и запускаем netcat (для винды - ncat) и подключаемся: ncat 62.173.140.174 11000

Для взаимодействия у нас есть две команды: "request" и "exit". Если с "exit" все ясно, то с "request" нет. Для этого смотрим вверх и видим кусок кода, который используется при отправке request'а.

Посмотреть вложение 70989

Python:
async def gen_enc_flag():
    rand_bytes = urandom(23)
    enc = bytes(i ^ j for i, j in zip(flag, rand_bytes))
    for i in range(23):
        assert enc[i] != flag[i], "leak detected"
    return enc.hex()

Я в коде не силен, поэтому просто загрузил код в ChatGPT :)

Посмотреть вложение 70990

За его ответ судить не берусь, но общее понимание появилось.
Сначала функция генерирует 23 рандомных байта, далее она делает XOR байта первого символа флага с первым сгенерированным байтом, потом тоже самое со вторым и.т.д.
После XOR'ов всех символов флага программа проверяет на равенство каждый байт зашифрованного флага и изначального. Если таковой есть, то печатает "Leaked some plaintext".

Получается, что в каждом зашифрованном флаге на своем месте нет ни одного символа от изначального.
Т.е если флаг - CODEBY{eto_ne_flag}, то первый байт (43 для "C") нам никогда не встретится. Тоже самое и для остальных символов.

Сбор флагов

Тут мы обращаемся к третьей подсказке "Я думаю стоит накапливать зашифрованные флаги".
Осталось определиться с количеством собираемых флагов. Слышал, что 5000 достаточно, но я определил для себя - 30000. Так сказать, наверняка :).
Ясно дело, что вручную это ооочень долго, поэтому автоматизируем, используя pynput для ввода с клавиатуры.

Сам код:
Python:
import time
import pynput
from pynput.keyboard import Key, Controller
keyboard = Controller()  # Create the controller
i=0
time.sleep(10)
while i<30000 :
    keyboard.type('request')
    time.sleep(0.1)
    keyboard.press(Key.enter)
    time.sleep(0.1)
    i+=1

Перед тем как запускать, идем обратно в netcat, останавливаем и опять запускаем, но уже с записью в файл: ncat 62.173.140.174 11000 -o dump.txt
Запускаем скрипт и переходим в окно netcat'а.
Ждем. Сборка 30000 шифрованных флагов у меня заняла ≈ 1.5-2 часа.

По окончании сбора флагов получаем файл.
Теперь нам надо почистить файл от лишнего, оставив только флаги. Открываем VSCode и удаляем ненужное.
Я не стал это автоматизировать, т.к делается это за две минуты простой заменой.

Наш дамп до:

Посмотреть вложение 70992

После:

Посмотреть вложение 70993


Находим флаг

Теперь создаем второй скрипт для нахождения флага:

Python:
start = 0
end = 2

two_bytes = []
text = ''
hex_numbers = ['00','01','02','03','04','05','06','07','08','09','0a','0b','0c','0d','0e','0f',
               '10','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f',
               '20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f',
               '30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f',
               '40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f',
               '50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f',
               '60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f',
               '70','71','72','73','74','75','76','77','78','79','7a','7b','7c','7d','7e','7f',
               '80','81','82','83','84','85','86','87','88','89','8a','8b','8c','8d','8e','8f',
               '90','91','92','93','94','95','96','97','98','99','9a','9b','9c','9d','9e','9f',
               'a0','a1','a2','a3','a4','a5','a6','a7','a8','a9','aa','ab','ac','ad','ae','af',
               'b0','b1','b2','b3','b4','b5','b6','b7','b8','b9','ba','bb','bc','bd','be','bf',
               'c0','c1','c2','c3','c4','c5','c6','c7','c8','c9','ca','cb','cc','cd','ce','cf',
               'd0','d1','d2','d3','d4','d5','d6','d7','d8','d9','da','db','dc','dd','de','df',
               'e0','e1','e2','e3','e4','e5','e6','e7','e8','e9','ea','eb','ec','ed','ee','ef',
               'f0','f1','f2','f3','f4','f5','f6','f7','f8','f9','fa','fb','fc','fd','fe','ff',]

remove = "{}'"
for i in range(23):
    with open('C:/Users/event/Desktop/dump.txt', 'r') as f:
     for line in f:
        first_two = line[start:end]
        two_bytes.append(first_two)
    data = set(hex_numbers) - set(two_bytes)
    clear_data = ''.join([char for char in data if char not in remove])
    bytes_object = bytes.fromhex(clear_data)
    text = "".join([text, bytes_object.decode("utf-8")])
    start += 2
    end += 2
    two_bytes = []
    print(text)

Здесь мы объявляем массив всех hex символов (hex_numbers).
Далее достаем все hex значения символов из дампа и находим единственное неиспользованное. Его перегоняем в ASCII и добавляем в text.

Запускаем, получаем флаг, сдаем. :cool:

Спасибо за прочтение!


Есть критика или пожелание - пишите!)
Молодец!

Давным давно решал этот таск, тогда сделал так:
Bash:
while true; do echo 'request' | ncat 62.173.140.174 11000 | grep '[+]' >> hashes.txt; sleep 0.1; done

2к флагов достаточно.

Решалка:
Python:
with open('hashes.txt', 'r') as file:
    hashes = file.readlines()

list1 = []
flag = []
symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}!$@%^&*()"

for i in range(len(hashes)):
    hashes[i] = bytes.fromhex(hashes[i])

for x in range(23):
    for a in symbols:
        for i in range(len(hashes)):
            if hashes[i][int(x)] == ord(a):
                if a in list1:
                    list1.remove(a)
                break
            else:
                if a not in list1:
                    list1.append(a)
    flag += list1
print(''.join(flag))
 

yetiraki

Green Team
07.02.2023
60
105
BIT
345
Сорян, что вмешиваюсь. Спасибо за райтап, но вот сборы ответов мне не удалось собрать ни первым, ни вторым способом, потэтому я написал свой скрипт с блэкджеком и... Пришлось совмещать алгоритмы, зато в одном месте все и сразу =)
Может быть кому-то пригодится.

Python:
from pwn import *

io = remote('62.173.140.174', 11000)

hashes = []
io.recvuntil(b'$ ')

print("Getting hashes...")
count = 5000
for i in range(count):
    io.sendline(b'request')
    io.recvuntil(b'$ ')
    if io.recv(4) == b'[-] ':
        continue
    hashes.append(io.recv(46).decode('ascii'))
    io.recvline()
io.close()
#print(f"Hashes we got: {hashes}")

print("Decoding hashes...")
list1 = []
flag = []
symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}!$@%^&*()"

for i in range(len(hashes)):
    hashes[i] = bytes.fromhex(hashes[i])

for x in range(23):
    for a in symbols:
        for i in range(len(hashes)):
            if hashes[i][int(x)] == ord(a):
                if a in list1:
                    list1.remove(a)
                break
            else:
                if a not in list1:
                    list1.append(a)
    flag += list1
print(''.join(flag))
 
  • Нравится
Реакции: Cruel Lord и Kevgen
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!