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}