Secret Blueprints 2

Задание

В процессе исследования пустоши были найдены новые чертежи. Они похожи на предыдущие, но, кажется, в этот раз данные защищены лучше, или все же нет?

Решение

Для решения задания дан архив, содержащий два файла.

Файл source.py сожержит код, который был использован для шифрования флага:

import random
import os
import math
from Crypto.Util.number import getStrongPrime
    
def parse_n_parameters_from_file(file_path):
    #
    # Secret information
    #
 
def flag_to_number(flag):
    return int.from_bytes(flag.encode('utf-8'), byteorder='big')
 
def encrypt_by_public_key(flag):
    flag = flag_to_number(flag)
    #
    # Secret information
    #
 
def main():
    flag = os.getenv("CTF_FLAG")    
    encrypted_flag, n = encrypt_by_public_key(flag)
    with open('/app/http/data/data.txt', 'w') as file:
        file.write(f"e: {3}\n")
        file.write(f"n: {n}\n")
        file.write(f"flag: {encrypted_flag}\n")
 
main()

Файл data.txt содержит данные вида:

e: 3
n: 729174757040172253523548163365790180105209361709917836113773695791537173645448911673257779543603917831880168814616571903180059703041918465096284975303919012033369879858126724540154708473261631395527829506091617084411411005754395467251041858298316019868386083835160290028260408550568787162207173074873203720776161206294391980851854208450368517903886253691764261792956089442981355120178178865263514917743801822928703749282742848104144449978980748583977852090696499986587052000157417577621827068494304201744167296702227994061056789063322097343147666776243701184240957871732345952556444633377034915714528120761252271554421502520930493883941229132496132499509077155317833405135132522109076984513299615384637838586831937446262775982400700005562319150770737553041516941956706734770303774303838288601645024441696843526329512279059656442391542914320563791533453979185048494656728812021253833210175353305384051067649973358457252040824507975971956569048004806796493116922682921515708837865481328655772358455376871461687421353970677105107018470213275984416184077179512172970334612571485302982112440736335585098959350785942203444115433784502673977228892139748216641122377140677166971994959496329973698734112087353061564844811335693993051001431387
flag: 410815861252838831918185733230727124592662045196246756397662046386628909333868652953773049628495691120478988944672330277552406403000914861875971171942977386357921716113731779686142286137514672407861580433915215907250773723946673776607348711383614736360395743321688673707030933130649106303047054840161216256102820685595379501012778742311222515924108655132458817278520714625000

Из анализа содержимого файлов, предложенных для выполнения задания, а также из повтора названия задания, необходимо было сделать вывод о том, что для шифрования флага был использован RSA.

Однако в этот раз для шифрования флага применялся открытый ключ:

encrypted_flag, n = encrypt_by_public_key(flag)

Сразу отметим маленькое значение параметра e=3. Так как шифротекст в RSA получается путем возведения в степень e по модулю n, то, если исходное сообщение в степени e будет меньше n, полученный шифротекст останется равным исходному сообщению в степени e. В таком случае можно получить исходное сообщение просто взяв корень степени e из шифротекста. В данном случае искомый флаг будет равен корню третьей степени из зашифрованного значения.

Более подробно про это можно прочитать здесь.

Ниже приведен код для решения данного задания:

import gmpy2
from Crypto.Util.number import getStrongPrime
    
def number_flag_to_string(number_flag):
    byte_length = (number_flag.bit_length() + 7) // 8
    byte_data = number_flag.to_bytes(byte_length, byteorder='big')
    return byte_data.decode('utf-8')
 
def parse_parameters_from_file(file_path):
    params = {}
    with open(file_path, 'r') as file:
        for line in file:
            line = line.strip()
            if line:
                key, value = line.split(": ")
                params[key] = int(value)
    return params
 
def main():
    data = parse_parameters_from_file("data.txt")
    encrypted_flag = data["flag"]
    number_flag = gmpy2.iroot(encrypted_flag, 3)[0]
    flag = number_flag_to_string(number_flag)
    print(flag)
 
main()

Найденный флаг для приведенных исходных данных:

ptech2024{17d2c5ab414a641c1620623cb5b8cd081f6e749f}