//ChronoFolder
Flag: Vianu_CTF{t1m3_m@st3r_4728290}
>TL;DR
The archive contains many decoy files, but their timestamps (mtime) are the real payload.
- Extract the zip.
- Sort the extracted
.txtfiles by mtime. - Select only the files whose minute-of-hour is a Fibonacci number:
1, 2, 3, 5, 8, 13, 21, 34. - Concatenate those selected filenames (stems), then Base64-decode → flag.
>Challenge premise
We’re given a recovered directory that looks nearly empty. This is a classic forensics pattern: the "message" is often hidden in:
- Hidden files or weird filenames
- File timestamps (mtime/atime/ctime)
- Extended attributes
- Embedded metadata in images
- Archive structure tricks
The challenge name ChronoFolder is an immediate hint that time matters.
>1) Initial triage (what’s in the folder?)
From the challenge directory:
cd /home/noigel/CTF/VianuCTF/Forensics/ChronoFolder
ls -la
I found two key files:
chall-20251208T215041Z-1-001.zipchall-20251208T215041Z-1-001.zip:Zone.Identifier
Why Zone.Identifier matters
On Windows, Zone.Identifier is an Alternate Data Stream (ADS) that can store “downloaded from the internet” metadata.
On Linux, you may see it as a separate file when a zip was created/extracted on Windows or transferred in a way that preserved the stream name.
It’s not always useful, but it’s a clue that the evidence was handled across platforms.
>2) List the archive contents and extract
Before extracting, I like to list the archive:
unzip -l chall-20251208T215041Z-1-001.zip | sed -n '1,200p'
Then extract into a fresh directory:
rm -rf extracted
mkdir extracted
unzip -q chall-20251208T215041Z-1-001.zip -d extracted
find extracted -maxdepth 3 -printf '%y %p\\n' | sed -n '1,200p'
This revealed a folder full of .txt files, plus a misnamed “png” that was actually a WebP.
At this point there were obvious decoys:
flag.txtcontainedVianu_CTF{try_harder}(clearly not the final solution)ffaH.txtcontainedVianu_CTF{n0t_r34l_4t_4ll}(also a decoy)
So I pivoted to what the challenge name suggested: chronology.
>3) Why timestamps? (Reasoning)
The title: ChronoFolder
CTF designers often encode the intended method in the name:
- “Chrono” → time
- “Folder” → filesystem-level artifacts
What I checked first
I sorted files by modification time (mtime):
find extracted/chall -maxdepth 1 -type f -name '*.txt' -printf '%T@\\t%f\\n' | sort -n | sed -n '1,200p'
This produced a very “engineered” sequence:
- Many files spaced by neat minute increments
- A long run of files on the same day/time window
That’s not how organic user files look. It strongly suggests intentional timestamp encoding.
>4) The key hint: Fibonacci numbers in image metadata
The file 676767.png was actually WebP:
file extracted/chall/676767.png
# RIFF ... Web/P image
I inspected metadata:
exiftool extracted/chall/676767.png | sed -n '1,200p'
The User Comment contained:
btw i like these numbers 1,2,3,5,8,13
That’s the Fibonacci sequence.
Why this is the “aha” moment
At this point we have:
- Challenge title screams timestamps
- An image metadata hint screams Fibonacci
So the natural hypothesis is:
“Pick items based on a Fibonacci rule applied to timestamps.”
There are multiple ways Fibonacci could be applied:
- Fibonacci indices (1st, 2nd, 3rd, 5th file…)
- Fibonacci time deltas between mtimes
- Fibonacci minute values inside the timestamp
The simplest interpretation (and often the correct one in CTFs) is:
Use Fibonacci numbers as minute-of-hour values.
Because they gave raw numbers like 1,2,3,5,8,13 (not “1st, 2nd, …”) and because timestamps naturally contain minutes.
>5) Verify the minute-of-hour hypothesis
I printed each .txt file in chronological order with its UTC time:
python3 - <<'PY'
import pathlib, datetime
p=pathlib.Path('extracted/chall')
items=sorted([f for f in p.glob('*.txt')], key=lambda f: f.stat().st_mtime)
base=datetime.datetime.utcfromtimestamp(items[0].stat().st_mtime).replace(second=0)
print('base',base)
for i,f in enumerate(items,1):
dt=datetime.datetime.utcfromtimestamp(f.stat().st_mtime)
delta=int((dt-base).total_seconds()/60)
print(f"{i:02d} {dt.strftime('%H:%M')} (+{delta:02d}m) {f.name}")
PY
Then I selected files whose minute is Fibonacci:
1, 2, 3, 5, 8, 13, 21, 34, 55, ...
In this dataset, the useful ones were:
- minute
01→Vmlh.txt - minute
02→bnVf.txt - minute
03→Q1RG.txt - minute
05→e3Qxb.txt - minute
08→TNfbU.txt - minute
13→BzdDN.txt - minute
21→yXzQ3Mj.txt - minute
34→gyOTB9.txt
Notice how the selected stems look like Base64 chunks (e.g., Vmlh, bnVf, Q1RG, e3Qx...).
That’s a huge confirmation signal.
>6) Extract the message from filenames (Base64)
The solution is to concatenate the filename stems (without .txt) in chronological order and Base64-decode.
I used this script:
python3 - <<'PY'
import base64, pathlib, datetime, re
p=pathlib.Path('extracted/chall')
items=sorted([f for f in p.glob('*.txt')], key=lambda f: f.stat().st_mtime)
fib_minutes={1,2,3,5,8,13,21,34,55}
sel=[]
for f in items:
dt=datetime.datetime.utcfromtimestamp(f.stat().st_mtime)
if dt.minute in fib_minutes:
sel.append((dt.minute,f))
concat=''.join(f.stem for _,f in sel)
print('concat:', concat)
pad='='*((4-len(concat)%4)%4)
raw=base64.urlsafe_b64decode(concat+pad)
print('decoded:', raw)
m=re.search(rb'Vianu_CTF\\{[^}]{0,200}\\}', raw)
print('flag:', m.group(0).decode() if m else 'no match')
PY
Output included:
- Decoded:
Vianu_CTF{t1m3_m@st3r_4728290}
That matches the required format.
>7) Notes on decoys (why they’re there)
You’ll see at least two tempting strings:
flag.txt→Vianu_CTF{try_harder}ffaH.txt→Vianu_CTF{n0t_r34l_4t_4ll}
These are deliberate “time wasters”. The correct solution is distinguished by:
- It uses the challenge theme (time/chronology)
- It uses the explicit hint (Fibonacci numbers)
- It produces a clean Base64 decode into a properly formatted flag
>References
unzipmanual (listing/extracting zip archives): https://linux.die.net/man/1/unzipfindmanual (printing mtimes via%T@): https://man7.org/linux/man-pages/man1/find.1.htmlstatmanual (file timestamps): https://man7.org/linux/man-pages/man1/stat.1.html- ExifTool documentation (reading image metadata): https://exiftool.org/
- Base64 (RFC 4648): https://www.rfc-editor.org/rfc/rfc4648