Gotta Go Fast

문제

저는 엔트로피가 고갈되는 것을 걱정할 필요가 없을 거에요. 이 새로운 스크립트로 영원히 OTP를 생성할 거예요!

풀이

더보기
더보기
#!/usr/bin/env python3

import time
from Crypto.Util.number import long_to_bytes
import hashlib
from utils import listener


FLAG = b'crypto{????????????????????}'


def generate_key():
    current_time = int(time.time())
    key = long_to_bytes(current_time)
    return hashlib.sha256(key).digest()


def encrypt(b):
    key = generate_key()
    assert len(b) <= len(key), "Data package too large to encrypt"
    ciphertext = b''
    for i in range(len(b)):
        ciphertext += bytes([b[i] ^ key[i]])
    return ciphertext.hex()


class Challenge():
    def __init__(self):
        self.before_input = "Gotta go fast!\n"

    def challenge(self, your_input):
        if not 'option' in your_input:
            return {"error": "You must send an option to this server"}

        elif your_input['option'] == 'get_flag':
            return {"encrypted_flag": encrypt(FLAG)}

        elif your_input['option'] == 'encrypt_data':
            input_data = bytes.fromhex(your_input['input_data'])
            return {"encrypted_data": encrypt(input_data)}

        else:
            return {"error": "Invalid option"}


"""
When you connect, the 'challenge' function will be called on your JSON
input.
"""
listener.start_server(port=13372)

먼저 코드를 보게 되면

generate_key함수에서 현재 시간을 받은 후, 그 시간을 키값을 만든다.

그리고 encrypt함수에서는 키와 xor연산을 한다.

 

일단 json방식으로{"option": "get_flag"}형태로 입력하면 

{"encrypted_flag": "6a8d437476b499f378efcfa4f5f76c51e68627dd7555f6f6a326d524"}

방식으로 암호화된 flag값이 나오고, 

 

{"option": "encrypt_data","input_data": "6a8d437476b499f378efcfa4f5f76c51e68627dd7555f6f6a326d524"}

을 입력하면 다시 encrypt함수를 이용하여 암호화되어 

{"encrypted_data": "230e9940f3be667283b3e6d79e11876b8d52c6b76a5cd58ecdb00471"}

방식으로 나온다. 

 

먼저 xor의 성질로 다시한번 같은 값으로 xor하게되면 원래의 값이 나오게된다.

하지만 현재시간을 이용하여 키를 생성하기 때문에

터미널을 통해 입력하여 플래그 값을 구하기는 어렵다.

그래서 telnetlib를 이용하여 이를 풀어보았다.

 

import telnetlib
import json


server = telnetlib.Telnet("socket.cryptohack.org", 13372)

def readline():
    return server.read_until(b"\n")

def json_recv():
    line = readline()
    return json.loads(line.decode())

def json_send(flag):
    rq = json.dumps(flag).encode()
    server.write(rq)

print(readline())
json_send({"option": "get_flag"})
received = json_recv()

input = received["encrypted_flag"]
json_send({"option": "encrypt_data","input_data": input})
received = json_recv()

flag = received["encrypted_data"]
print(flag)
flag = bytes.fromhex(flag)
print(flag)

플래그 값은 crypto{t00_f4st_t00_furi0u5}이다.

복사했습니다!