Task of the Ancient Rus
Task of the Ancient Rus
Platform: hackerlab | Category: Reversing | Type: Challenge | Difficulty: Medium | OS: Windows | Author: XESXOR | Date: 2026-04-06 | Status: Solved Techniques: transform_inversion, archive_password_recovery, trailer_carving, red_herring_elimination, binary_diffing, slack_space_decoding
Summary
Task: a multi-stage archive challenge mixes an AES-encrypted ZIP, fake ancient-style C source, a decoy assembly file, an MP3 with an appended clue, and a modified NASM executable. Solution: invert the checker to recover the ZIP password, ignore the asm red herring, carve the MP3 trailer hint, diff nasm.exe against the official build, and decode the hidden blob from .data slack.
Task of the Ancient Rus — hackerlab
Description
Задание древних Русов
English summary: the archive contains several layers of misdirection: obfuscated fake-C code, an AES-encrypted ZIP, a decoy assembly file, an MP3 with hidden trailing data, and a modified nasm.exe. The goal is to separate real clues from red herrings and recover the final CODEBY{...} flag.
Analysis
Challenge Summary
This is a multi-stage reverse challenge built around progressive clue validation. The real path is:
- reverse the fake C checker to recover the password for
flag.zip, - ignore the decoy
flag.asm, - inspect the MP3 trailer for a plaintext hint,
- compare the bundled
nasm.exewith the official NASM release, - decode the altered bytes hidden in PE slack space.
Reconnaissance
The initial ZIP contained:
flag.zipancientslavic.hnot_important.cИз архива истории.mp3
Early file triage showed that flag.zip was AES-encrypted, so the most likely starting point was the nearby source code.
ancientslavic.h defines Russian/Cyrillic macros and exposes a 32-byte constant array through бронь1..бронь32. not_important.c uses those macros to disguise a simple byte-by-byte checker.
Solution
Step 1: Reverse the fake C checker and recover the ZIP password
The checker reads user input, transforms each byte, and compares the result to the hardcoded array прав.
The effective forward transform for byte x at position i is:
text read-only • copy allowedx ^= 3 x += 7 x += 7 x -= 9 x ^= 9 x += i x ^= i x ^= i x ^= prev prev = x
The two consecutive x ^= i operations cancel out, but they are still present in the source and help sell the obfuscation.
The exact reference array is:
python read-only • copy allowedcorrect = [ 0x71,0x33,0x4d,0x65,0x11,0x27,0xa2,0xee, 0x9e,0xf2,0xc9,0xa3,0xd7,0x55,0x32,0x43, 0x3b,0x56,0x06,0x87,0xe0,0x9b,0xf9,0x86, 0xdf,0x47,0xc1,0xb5,0xef,0x7f,0xff,0xd9, ]
Reversing the transform yields the original password bytes:
python read-only • copy allowed#!/usr/bin/env python3 correct = [0x71,0x33,0x4d,0x65,0x11,0x27,0xa2,0xee,0x9e,0xf2,0xc9,0xa3,0xd7,0x55,0x32,0x43,0x3b,0x56,0x06,0x87,0xe0,0x9b,0xf9,0x86,0xdf,0x47,0xc1,0xb5,0xef,0x7f,0xff,0xd9] prev = 0 out = [] for i, c in enumerate(correct): t = c ^ prev t = (t - i) & 0xff t = t ^ 9 orig = ((t - 5) & 0xff) ^ 3 out.append(orig) prev = c print(bytes(out))
Output:
text read-only • copy allowedb'p@s$w0rD_f0R_tHe_S1aViC_@rcH1ve\n'
The trailing newline comes from fgets, so the actual ZIP password is:
text read-only • copy allowedp@s$w0rD_f0R_tHe_S1aViC_@rcH1ve
Step 2: Extract the nested archive
Use the recovered password to unpack flag.zip:
bash read-only • copy allowed7z x -y -p'p@s$w0rD_f0R_tHe_S1aViC_@rcH1ve' flag.zip
This extracts:
flag.asmnasm.exeФрагмент летописи.txt
Step 3: Confirm that flag.asm is a decoy
Reading flag.asm and concatenating the mov al, <num> immediates produces:
text read-only • copy allowedTh1S_1S_n0T_@_fl@G
So flag.asm is explicitly a red herring. It is worth checking because it looks like a classic assembly-encoded flag, but the recovered string directly tells us not to trust it.
Step 4: Inspect the MP3 and recover the hidden clue from the trailer
The MP3 does not contain the final flag directly.
exiftoolonly shows theme-like metadata.ffmpeg/ffprobeshow that the audio decodes, but the file ends with invalid trailing data.
That is the important clue: the audio itself is fine, but there is extra data appended after the legitimate MP3 stream.
Near the end of the file, at offset 436543 in a 436583-byte file, the last 40 appended bytes contain plaintext:
text read-only • copy allowedLook for ancientslavic.h on the Internet
This trailer clue explains the challenge design:
- the MP3 is not the flag container,
flag.asmis not the real payload,- the author wants the solver to stop chasing decoys and focus on the fake ancient-source theme and the hidden tooling logic around it.
Step 5: Compare nasm.exe with the official NASM build
The extracted nasm.exe is a PE32+ Windows console executable. It is clearly not a stock binary.
The reference build used for comparison was the official NASM 2.16.01 Windows x64 package:
text read-only • copy allowedhttps://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip
Hashes:
- local
nasm.exe:a5a61b4ab76b51acec376539364e7245a757607b2467d9ac56987de931c3d164 - official
nasm.exe:edd81d22451246758450f1d5bd7f4c64937ed6cee06f3c2bbbba82401b32c6d4
Only 65 bytes differ, all near raw offset 0x4ecb0 inside .data slack space. That is a classic sign of a minimally patched legitimate binary used as a hidden flag carrier.
Step 6: Decode the hidden blob from .data slack
The interesting region starts at 0x4ecb0 and contains this 37-byte blob:
text read-only • copy allowed413d44434227493f5eb09f0f633e542d544051392d6652103b2d3156125f541045525f644b
The decoding logic is simple:
python read-only • copy allowed#!/usr/bin/env python3 blob = bytes.fromhex( '413d44434227493f5eb09f0f633e542d544051392d6652103b2d3156125f541045525f644b' ) print(bytes((((b + 0x99) & 0xff) ^ 0x99) for b in blob))
Output:
text read-only • copy allowedCODEBY{REDACTED}
This is the real flag.