Challenge Name: SecurePad
Category: Reverse Engineering / Crypto
Description:
SecurePad™ — “Security Through Obscurity… and Comic Sans.” A custom encryption algorythm powered notepad.
1. Description
The challenge provides a Windows executable SecurePad.exe and an encrypted file flag.enc. The goal is to reverse the “custom encryption algorythm” and decrypt the flag.
2. Analysis
Binary Overview
- File Type: PE32 executable for MS Windows (GUI)
- Architecture: Intel i386
- Symbols: None (Stripped)
Static analysis using strings revealed:
- References to
Comic Sans. - Usage of
SystemFunction036(RtlGenRandom) for generating random keys. - A fake flag
CTF{5011d_5n4k3}.
Reverse Engineering
Disassembling the “Save” function at 0x4014eb revealed a multi-step encryption process:
- XOR Layer 1: The plaintext is XORed with an 8-byte random key.
- Custom RC4 Cipher:
- S-box Init: A custom loop initializes the S-box where
S[i(i+1)/2 mod 256] = i(i+1)/2 mod 256. Indices not hit by the triangular sequence remain zero. - KSA: A standard RC4 Key Scheduling Algorithm using the 8-byte random key as the seed.
- PRGA: A standard RC4 Pseudo-Random Generation Algorithm XORs the buffer with the keystream.
- S-box Init: A custom loop initializes the S-box where
- XOR Layer 2: The buffer is XORed with the same 8-byte random key again.
Note: Since XOR is commutative and the key is applied twice, the two simple XOR layers effectively cancel out for the first 8 bytes (and XOR with 0 for the rest), leaving the custom RC4 cipher as the primary encryption.
File Format (flag.enc)
The file structure was identified as:
- 0x00 - 0x1B: Ciphertext (28 bytes)
- 0x1C - 0x2F: Padding (zeros)
- 0x30 - 0x33: Plaintext length (28)
- 0x37 - 0x3E: 8-byte random key used for the cipher
- 0x3F: Random key length (8)
3. Solution
The decryption requires replicating the specific S-box initialization and then applying standard RC4 decryption using the key found in the file footer.
Exploitation Script
import struct
def decrypt(filename):
with open(filename, "rb") as f:
data = f.read()
length = 28
ciphertext = data[:length]
random_key = data[0x37:0x3f]
# 1. Replicate S-box initialization (Half-zero triangular pattern)
s = [0] * 256
bl = 0
for cl in range(256, 0, -1):
bl = (bl - cl) & 0xFF
s[bl] = bl
# 2. RC4 KSA with extracted key
j = 0
for i in range(256):
j = (j + s[i] + random_key[i % 8]) & 0xFF
s[i], s[j] = s[j], s[i]
# 3. RC4 PRGA Decryption
res = bytearray()
i = 0
j = 0
for buf_idx in range(length):
i = (i + 1) & 0xFF
j = (j + s[i]) & 0xFF
s[i], s[j] = s[j], s[i]
res.append(ciphertext[buf_idx] ^ s[(s[i] + s[j]) & 0xFF])
return res
flag = decrypt("flag.enc")
print(flag.decode(errors='ignore'))
4. Flag
CTF{r0ll_y0ur_0wn_b4d_c0d3}