KPMG CTF 2026 - Onion Layers
Challenge Description
An encrypted payload named
chall.encwas discovered. Like an onion, secrets have layers. Peel away each layer to recover the flag.
Step 1 - Inspecting the Challenge File
Opening chall.enc revealed a continuous sequence of 8-bit space-delimited binary strings:
01001110 01010100 01000001 00110000 01011001 01101010 01010010 01101100 ...
There were 104 binary octets in total.
Step 2 - Decoding the Layers
We loaded the ciphertext into CyberChef to peel each encoding stage:
Layer 1: From Binary
Converting the space-delimited binary octets to ASCII characters produced a 104-character string:
NTA0YjRlNTQ1ZjU4NDc1NTdiNmIzMzMzNmY1ZjY3NzMzNTZmNmIzMzM1NjY1ZjY3MzMzNTZmNmYzNDYyMzM2OTY4NWY2ZjMxNzA2MzM1NWY2NDZkNWY2MzZkMzE2MDZkN2Q=
The character set and trailing = padding clearly indicated standard Base64 encoding.
Layer 2: From Base64
Decoding the Base64 layer yielded a 78-character ASCII hexadecimal string:
504b4e545f5847557b6b33336f5f6773335f6f34623369685f6f3170335f346d5f306d31306d7d
Layer 3: From Hex
Decoding the hex representation revealed an obfuscated flag structure:
PKNT_XGU{k33o_gs3_o4b3ih_o1p3_4m_0m10m}
Notice the prefix PKNT_XGU matching the format of KPMG_CTF.
Layer 4: Atbash Cipher
Comparing PKNT_XGU to KPMG_CTF:
P(16th letter) aligns withK(11th letter:27 - 16 = 11)K(11th letter) aligns withP(16th letter)N(14th letter) aligns withM(13th letter:27 - 14 = 13)T(20th letter) aligns withG(7th letter:27 - 20 = 7)
This is the classic Atbash substitution cipher, where each alphabet letter is mirrored across the alphabet (A <-> Z, B <-> Y, C <-> X). Non-alphabetic characters and digits remain unchanged.
Applying the Atbash transform yielded the flag:
KPMG_CTF{p33l_th3_l4y3rs_l1k3_4n_0n10n}

Solve Script
The entire decoding pipeline can be executed in Python:
import base64
def atbash(s: str) -> str:
res = []
for c in s:
if 'a' <= c <= 'z':
res.append(chr(ord('z') - (ord(c) - ord('a'))))
elif 'A' <= c <= 'Z':
res.append(chr(ord('Z') - (ord(c) - ord('A'))))
else:
res.append(c)
return ''.join(res)
with open('chall.enc', 'r') as f:
raw = f.read().strip()
# Layer 1: Binary to ASCII
layer1 = bytes(int(b, 2) for b in raw.split()).decode()
# Layer 2: Base64 to Hex string
layer2 = base64.b64decode(layer1).decode()
# Layer 3: Hex to string
layer3 = bytes.fromhex(layer2).decode()
# Layer 4: Atbash substitution
flag = atbash(layer3)
print("Flag:", flag)Flag
KPMG_CTF{p33l_th3_l4y3rs_l1k3_4n_0n10n}
Summary
The challenge required recognizing cascading layers of data representation: binary octets -> Base64 string -> hexadecimal representation -> monoalphabetic Atbash substitution cipher. Reversing each step in order revealed the flag.