Interstellar Chat

This is a challenge from Cryptography section of Standcon 2021. The challenge uses AES_CTR to encrypt stuff

Statement

I’ve been trying to pirate interstellar chat for the longest time, however their super secure defences have been preventing me from doing so. Could you help me break in and get the flag?

Observation

Noticed that the flag is appended to a text and it is sent to us.

Also, the server is using the same key and nonce is used to encrypt different texts!

This is usually vulnerable because we can recover the OTP generated by AES_CTR if we know what the original text was.

After recovering the OTP, we can decrypt the text easily.

Solution

The problem now here being that we don’t really know the plaintext of the 2nd part because it append traceback.format_exc() to the text.

We will have to intentionally trigger an error and predict the traceback message to retrive back the OTP.

For that reason, the author also provided the file location of the server!

So, we send a wrong formatted json data to the server. Since the decoding of json data will fail, and error will be trigger.

By predicting the error text, we recover the OTP and the flag by decrypting the first text.

from pwn import *
import json

r = remote('20.198.209.142', 55001)
reply = r.recvn(347)
nonce = reply[:8]
ciphertext = reply[8:]

def createMsg(id, text):
    msg = {'id': id, 'text': text, 'timestamp': time.time()}
    return json.dumps(msg).encode()

FLAG = 'flag{test}'

id = f'#99999'
t = 'Welcome to the interstellar chat! Our super ultra secure software that is powered ' + \
    'by cylomin technology! As a loyal subscriber of our service, we are offering you ' + \
    f'a flag!\n{FLAG}\n'
print(len(t))
t += 'Would you like to extend your subscription? (y/n)'

msg = createMsg(id, t)

index = msg.index(b',') + 1
payload = nonce + ciphertext[:index]
payload2 = b' "text": "y"}}'

for i in range(len(payload2)):
    payload += bytes([ciphertext[index + i] ^ msg[index + i] ^ payload2[i]])

r.sendline(payload)
error = r.recv(347)[8:]

s = b'{"id": null, "text": "Oopsy Daisy we have done goofed. We apologise for our development team\'s incompetence\\nTraceback (most recent call last):\\n  File \\"/opt/interstellar/server.py\\", line 57, in run\\n    text = loads(dec(reply).decode())[\'text\']\\n  File \\"'

flag = b''

temp = b''
for i in range(len(msg)):
    temp += bytes([ciphertext[i] ^ error[i] ^ msg[i]])
print(temp)

for i in range(len(s)):
    flag += bytes([ciphertext[i] ^ error[i] ^ s[i]])
print(flag)
     

flag : STC{435_15_0nly_600d_1f_y0u_kn0w_h0w_70_1mpl3m3n7_17}

Updated: