CHALLENGE OVERVIEW

We are provided with a python script that uses a compiled pyc crypto library to check if our input is the flag.

from calc import cipher

def main():
    user_input = input("Enter input: ")
    cipher_text = cipher(user_input.encode())
    if cipher_text == b"A\xd3\x87nb\xb3\x13\xcdT\x07\xb0X\x98\xf1\xdd{\rG\x029\x146\x1ah\xd4\xcc\xd0\xc4\x14\xc99'~\xe8y\x84\x0cx-\xbf\\\xce\xa8\xbdh\xb7\x89\x91\x81i\xc5Yj\xeb\xed\xd1\x0b\xb4\x8bZ%1.\xa0w\xb2\x0e\xb5\x9d\x16\t\xd0m\xc0\xf8\x06\xde\xcd":
        print("Correct!")
    else:
        print("Fail!")

if __name__ == '__main__':
    main()

Basically we need to decompile calc.pyc to understand how the encryption works and get the flag.


SOLVE

To decompile calc.pyc I used pycdc

pycdc calc.pyc

The decompiled code made me think of RC4 encryption algorithm, based on this knowledge I fixed the decompiled code (which was not totally correct). The result was this:

MOD = 256

def KSA(key):
	key_length = len(key)
	S = list(range(MOD))
	j = 0
	for i in range(MOD):
		j = (j + S[i] + key[i % key_length]) % MOD
		S[i], S[j] = S[j], S[i]
	return S
  
def PRGA(S):
	i = 0
	j = 0
	while True:
		i = (i + 1) % MOD
		j = (j + S[i]) % MOD
		S[i], S[j] = S[j], S[i]
		K = S[(S[i] + S[j]) % MOD]
		yield K
  

def get_keystream(key):
	S = KSA(key)
	return PRGA(S)
  

def cipher(text):
	key = 'neMphDuJDhr19Bb'
	key = (lambda a: [ ord(c) ^ 48 for c in a ])(key)
	keystream = get_keystream(key)
	text = text[-2:] + text[:-2]
	res = []
	for c in text:
		val = c ^ next(keystream)
		res.append(val)
	return bytes(res)

calc.py

As you can see the key is known so we just need to write a function to decrypt the known ciphertext with the known key. This is a good task for chatGPT!

MOD = 256
 
def KSA(key):
	key_length = len(key)
	S = list(range(MOD))
	j = 0
	for i in range(MOD):
		j = (j + S[i] + key[i % key_length]) % MOD
		S[i], S[j] = S[j], S[i]
		return S
  
def PRGA(S):
	i = 0
	j = 0
	while True:
		i = (i + 1) % MOD
		j = (j + S[i]) % MOD
		S[i], S[j] = S[j], S[i]
		K = S[(S[i] + S[j]) % MOD]
		yield K
  
 
def get_keystream(key):
	S = KSA(key)
	return PRGA(S)
  
def decipher(ciphertext):
	key = 'neMphDuJDhr19Bb'
	key = (lambda a: [ ord(c) ^ 48 for c in a ])(key)
	keystream = get_keystream(key)
	decrypted = []
	for c in ciphertext:
		val = c ^ next(keystream)
		decrypted.append(val)
		return bytes(decrypted)
  
ciphertext = b"A\xd3\x87nb\xb3\x13\xcdT\x07\xb0X\x98\xf1\xdd{\rG\x029\x146\x1ah\xd4\xcc\xd0\xc4\x14\xc99'~\xe8y\x84\x0cx-\xbf\\\xce\xa8\xbdh\xb7\x89\x91\x81i\xc5Yj\xeb\xed\xd1\x0b\xb4\x8bZ%1.\xa0w\xb2\x0e\xb5\x9d\x16\t\xd0m\xc0\xf8\x06\xde\xcd"
plaintext = decipher(ciphertext)
flag = (plaintext[2:] + plaintext[:2]).decode()
print(flag)

FLAG: codegate2024{da5d6bd71ff39f66b8b7200a92b0116b4f8e5e27d25d6119e63d3266bd4c8508}