CrypTopiaShell - cryptography - cryptopia

Writeup - by bylal

The challenge is a shell that takes base64-encoded bytes following this format:

The magic number bytes + the length of the shellcode as a 6-byte value + the length of the signature as a 6-byte value + your shellcode + your signature.

The idea is that if your shellcode can be executed by os.system and if self.__sign == your signature, then the shellcode will be executed.

So, if we manipulate the signature value of our message, we are good.

Luckily, in the sign function, if gen == 0 before the while loop, we are assured that the signature equals zero at the end. The value of gen before the while loop is not influenced by either P or K, the two values we don’t know.

Therefore, the solution is simply to add a bytes after our script that modifies gen to be 0 and sets the signature to b”\x00” * 256.

What I did to set gen to 0 is that I keep track of the new value of gen after the signing part with my script. Then I add padding so that the shellcode reaches 64 characters. For each byte of gen, I add its value + 128.

You cannot include any null byte inside your shellcode because os.system will crash before running it. which is why I add 128 for the binary decomposition.

import pwn
from Crypto.Util.number import long_to_bytes
from base64 import b64encode

def find_m(gen, k):
    data = [1 for i in range(64 - k)]
    for i in range(k, len(data) + k):
        gen = (gen ^ (data[i - k] << (i % 64))) & 2**64-1
    for i in range(64):
        data.append(((gen >> i) & 1) + 128)
        gen = (gen ^ (data[-1] << (i % 64))) & 2**64-1
    return data

def modify(data, gen):
    for i in range(len(data)):
        gen = (gen ^ (data[i] << (i % 64))) & 2**64-1
    return gen

src = pwn.remote("0.cloud.chals.io", 13064)

print(src.recvuntil(b"$ "))

G = 0x8b6eec60fae5681c
MAGIC = b"\x01\x02CrypTopiaSig\x03\x04"
bl = G.bit_length()



shell = b"cat .passwd;"



String = MAGIC + b"\x00" * 5 +  long_to_bytes(128) + b"\x00" * 4 + long_to_bytes(2048)

new_G = modify(shell, G)

m = find_m(new_G, len(shell))

String += shell + bytes(m) + b"\x00" * (2048 // 8)

final = b64encode(String)

src.sendline(final)

print(src.recvuntil(b"$ "))

The flag is: N0PS{d0nT_s1gN_W17h_ChK5uMz}