Странный код (Strange Code)
Странный код (Strange Code)
Platform: hackerlab | Category: Crypto | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-04-05 | Status: Solved Techniques: base64_case_bruteforce, printable_ascii_constraint_filtering, vigenere_decryption, vigenere_known_plaintext_attack
Summary
Task: a Python file encrypted with Vigenère cipher — structure preserved but keywords unrecognizable. Solution: identify Vigenère key 'code' via known-plaintext (Python keywords), decrypt the script, then brute-force base64 case recovery (case destroyed by cipher) with printable ASCII constraints to extract the flag.
Странный код (Strange Code) — Hackerlab
Description
У меня что-то со зрением или это новый язык программирования?
English summary: A zip file strange_code.zip contains code.py — a file that looks like Python code but with all letters shifted/substituted. The structure (indentation, colons, parentheses, quotes, equals signs) is preserved, but keywords are unrecognizable. The goal is to figure out the cipher, decrypt the code, and extract the flag.
Analysis
Step 1: Examine the encrypted code
The file code.py contains:
kassth wmos dw z
wptqfw fcgh64 eu p64
i = "u09gfxnbs000wp83crixznixznujurqqvt8zvn80l0patrq9"
i = d64.p64giecgi(h).rhgqrh()
g = "ecqktoww!\p"
rhj r(h, g=0.2):
jqf f mp h:
svkbw(g, gbg='', jnivl=vfxi)
z.goigd(g)
t(e+s)
Key observations:
- Python-like structure is intact:
import-like statements, function definition withdef-like keyword,for-like loop,print-like call - Only alphabetic characters are affected; digits, spaces, symbols, and newlines are unchanged
- All letters are lowercase
Step 2: Identify the cipher via known plaintext
Matching ciphertext keywords to Python keywords:
| Ciphertext | Plaintext | Length |
|---|---|---|
kassth | import | 6 |
wptqfw | import | 6 |
rhj | def | 3 |
svkbw | print | 3 |
jqf | for | 3 |
Computing shifts (ciphertext - plaintext mod 26) for each alphabetic character position:
| Position | Cipher | Plain | Shift | Key letter |
|---|---|---|---|---|
| 0 | k | i | 2 | c |
| 1 | a | m | 14 | o |
| 2 | s | p | 3 | d |
| 3 | s | o | 4 | e |
| 4 | t | r | 2 | c |
| 5 | h | t | 14 | o |
| ... | ... | ... | ... | repeating |
| |
The shift pattern 2, 14, 3, 4 repeats — this is a Vigenère cipher with key "code" (c=2, o=14, d=3, e=4). The key cycles over alphabetic characters only; non-alpha characters are passed through without advancing the key position.
Step 3: Decrypt the code
Applying Vigenère decryption with key "code" recovers the original Python script:
python read-only • copy allowedimport time as x import base64 as b64 f = "q09erujze000tl83adftxzftxzrfsdnmtf8wrl80x0mwrdn9" e = b64.b64decode(f).decode() c = "congrats!\n" def p(t, d=0.2): for c in t: print(c, end='', flush=True) x.sleep(d) p(c+e)
The script decodes a base64 string and prints "congrats!" followed by the decoded flag with a typewriter effect.
Step 4: Recover the base64 string's case
Critical problem: The Vigenère cipher operates mod 26 within the lowercase alphabet, so ALL letters in the encrypted file became lowercase. But base64 is case-sensitive — A-Z encodes values 0-25, while a-z encodes values 26-51. The cipher destroyed the original case information.
Solution: Split the 48-character base64 string into 12 groups of 4 characters. Each 4-char group decodes independently to 3 bytes. For each group, brute-force all case combinations of alphabetic characters (2^n where n = number of alpha chars in the group, max 2^4 = 16 per group) and keep only those producing valid printable ASCII bytes.
Additional constraints from the known flag format CODEBY{...}:
- Groups 0-1 (bytes 0-5): must decode to
CODEBY - Group 2 (byte 6): must start with
{ - Group 11 (byte 35): must end with
}
Step 5: Case recovery results
| Group | Lowercase | Correct case | Decoded |
|---|---|---|---|
| 0 | q09e | Q09E | COD |
| 1 | rujz | RUJZ | EBY |
| 2 | e000 | e000 | {M4 |
| 3 | tl83 | Tl83 | N_7 |
| 4 | adft | aDFT | h1S |
| 5 | xzft | XzFT | _1S |
| 6 | xzrf | XzRf | 4 |
| 7 | sdnm | SDNM | H3L |
| 8 | tf8w | TF8w | L_0 |
| 9 | rl80 | Rl80 | F_4 |
| 10 | x0mw | X0Mw | _C0 |
| 11 | rdn9 | RDN9 | D3} |
Correct base64 string: Q09ERUJZe000Tl83aDFTXzFTXzRfSDNMTF8wRl80X0MwRDN9
Solution
python read-only • copy allowed#!/usr/bin/env python3 """ Solve script for "Strange Code" (Hackerlab) Vigenère cipher on Python code + base64 case recovery """ import base64 import itertools # Read the encrypted code with open("code.py", "r") as f: ciphertext = f.read() # Step 1: Vigenère decryption with key "code", cycling on alpha chars only key = "code" key_shifts = [ord(c) - ord('a') for c in key] # [2, 14, 3, 4] def decrypt_vigenere(text, key_shifts): result = [] alpha_idx = 0 for ch in text: if ch.isalpha(): shift = key_shifts[alpha_idx % len(key_shifts)] if ch.islower(): dec = chr((ord(ch) - ord('a') - shift) % 26 + ord('a')) else: dec = chr((ord(ch) - ord('A') - shift) % 26 + ord('A')) result.append(dec) alpha_idx += 1 else: result.append(ch) return ''.join(result) plaintext = decrypt_vigenere(ciphertext, key_shifts) print("Decrypted code:") print(plaintext) # Step 2: Extract the base64 string from the decrypted code import re b64_match = re.search(r'"([A-Za-z0-9+/=]+)"', plaintext) b64_lower = b64_match.group(1) print(f"\nBase64 string (all lowercase): {b64_lower}") # Step 3: Recover case by brute-forcing each 4-char group # Each group of 4 base64 chars decodes to 3 bytes independently groups = [b64_lower[i:i+4] for i in range(0, len(b64_lower), 4)] recovered = "" for gi, group in enumerate(groups): alpha_pos = [i for i, c in enumerate(group) if c.isalpha()] candidates = [] for combo in itertools.product([False, True], repeat=len(alpha_pos)): chars = list(group) for idx, upper in enumerate(combo): if upper: chars[alpha_pos[idx]] = chars[alpha_pos[idx]].upper() variant = ''.join(chars) try: # Pad for independent decoding decoded = base64.b64decode(variant + '==')[:3] if all(0x20 <= b <= 0x7E for b in decoded): candidates.append((variant, decoded)) except Exception: pass if len(candidates) == 1: recovered += candidates[0][0] else: # Apply flag format constraints best = candidates[0][0] if candidates else group for variant, decoded in candidates: text = decoded.decode('ascii', errors='replace') # Group 0-1: CODEBY, Group 2: starts with {, Group 11: ends with } if gi == 0 and text == "COD": best = variant; break elif gi == 1 and text == "EBY": best = variant; break elif gi == 2 and text.startswith("{"): best = variant; break elif gi == 11 and text.endswith("}"): best = variant; break recovered += best print(f"\nRecovered base64: {recovered}") flag = base64.b64decode(recovered).decode() print(f"Flag: {flag}")