CTF Disk Forensics: Why I Wasted 20 Minutes Before Learning the Right mount Workflow
If you've ever stared at a wrong fs type, bad option, bad superblock error and thought "I just need to recalculate the offset" — I've been there. In a CTF forensics challenge, I spent 20 minutes convinced that mount would eventually work if I just got the math right. It wouldn't. The problem wasn't the offset. It was that I skipped the diagnostic step entirely and jumped straight to mounting a disk image I didn't understand yet. This article is about what I should have done first — and how to build a decision tree that actually works under CTF pressure.
The 20-Minute Mistake That Taught Me Everything
The Setup: A 350MB Disk Image That Looked Straightforward
The challenge gave me a single file: disk.img. Running file disk.img returned DOS/MBR boot sector, and I could see ext2 in the output. My brain immediately jumped to: " Okay, it's ext2, I just mount it." That assumption cost me 20 minutes.
$ file disk.img
disk.img: DOS/MBR boot sector; partition 1 : ID=0x83, start-CHS (0x0,33,3), end-CHS (0x4,30,3), startsector 2048, 71680 sectors, code offset 0xb8
I ran mount -o loop disk.img /mnt. Error. I calculated the offset: 2048 × 512 = 1048576. Tried again with -o loop,offset=1048576. Error. I tried different sector sizes. Different offsets. Still the same error.
$ sudo mount -o loop,offset=1048576 disk.img /mnt
mount: /mnt: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or helper program, or other error.
Where I Went Wrong: Trusting file Too Much
Here's the thing about file: it identifies format, not integrity. A disk image can look like ext2 and still have a corrupted superblock, a broken partition table, or no actual filesystem data at the expected offset. I was treating file as a green light. It's not. It's just the first clue.
What I should have done — before even thinking about mounting — was check the partition structure with mmls. When I finally ran it, I saw something I hadn't expected: a large unallocated region right after the partition. The partition table wasn't just pointing somewhere I'd miscalculated. It was malformed. No amount of offset math was going to fix that.
The Diagnostic Checklist: What to Do Before Attempting mount
After this experience, I built a habit. Every disk image challenge now starts with the same three steps before I even think about mount.
Step 1 — file: Identify the Format
$ file disk.img
This tells you what you're dealing with — MBR, GPT, qcow2, LUKS, raw ext4, etc. Each one has a different path forward. If file says LUKS encrypted file, you're not mounting anything until you decrypt it. If it says QEMU QCOW Image, you need to convert first.
Step 2 — mmls or fdisk -l: Read the Partition Table
$ mmls disk.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors
Slot Start End Length Description
000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
001: ------- 0000000000 0000002047 0000002048 Unallocated
002: 000:000 0000002048 0000073727 0000071680 Linux (0x83)
This is where things get real. mmls shows you the actual partition boundaries and, crucially, any large unallocated regions. A well-designed CTF challenge will often hide data in unallocated space — or damage the partition table just enough to make mount fail while still having valid filesystem data somewhere in the image.
Step 3 — binwalk: Check for Embedded or Hidden Content
$ binwalk disk.img
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
1048576 0x100000 Linux EXT filesystem, blocks count: 71680...
binwalk scans the raw bytes for recognizable signatures. It doesn't care about partition tables. If there's a PNG, a ZIP, or an EXT filesystem header buried anywhere in the image, binwalk will find it. I now always run this before and after mmls, because sometimes the interesting data isn't in the partition — it's in the slack space after it.
The Correct mount Workflow (When Mounting Actually Makes Sense)
After the diagnostic steps confirm the filesystem is structurally intact, mounting becomes straightforward. But two things matter here that beginners often miss.
Calculating the Offset Correctly
The formula is simple: start_sector × sector_size. From the mmls output above, the partition starts at sector 2048 with 512-byte sectors:
$ sudo mount -o loop,offset=$((2048 * 512)),ro disk.img /mnt
$ ls /mnt
lost+found secret flag.txt
Using $((2048 * 512)) directly in the shell avoids the mental arithmetic errors I kept making at 2 AM during the competition.
Why -o ro Matters More Than You Think
The ro (read-only) flag felt like an optional best practice the first time I saw it in a Writeup. Then I learned why it's critical: mounting a filesystem read-write updates access timestamps (atime) across every file the OS touches during mounting. In a forensics challenge, those timestamps might be part of the puzzle. Mounting read-write can silently destroy evidence before you even start looking.
Always mount forensics images read-only. Always.
Three Scenarios Where You Should NOT Mount First
This is the part that would have saved me those 20 minutes if I'd known it earlier.
Scenario 1: Broken ext2/ext4 → File Carving with foremost
A challenge that intentionally corrupts the superblock will make mount fail no matter what offset you try. The ext4 superblock contains a magic number (0xEF53) at byte offset 1024 from the partition start. If that's missing or overwritten, the kernel refuses to mount — full stop.
The right tool here is foremost or binwalk -e. These tools don't care about filesystem structure. They carve raw file signatures directly from the binary data:
$ foremost -i disk.img -o ./carved_output
$ binwalk -e disk.img --directory=./extracted
I've seen CTF challenges where the entire filesystem structure is intact except for one zeroed-out byte in the superblock magic. mount fails. foremost recovers every file. The damage was cosmetic, not structural.
Scenario 2: LUKS Encryption → cryptsetup First
If file disk.img returns LUKS encrypted file, ver 1, you're not mounting anything without the passphrase or keyfile. The correct sequence:
$ sudo cryptsetup luksOpen disk.img ctf_volume
Enter passphrase for disk.img:
$ sudo mount /dev/mapper/ctf_volume /mnt -o ro
In CTF challenges with LUKS, the passphrase is usually hidden somewhere else in the challenge — a previous flag, a file in another challenge artifact, or encoded in the challenge description. Don't try to brute force it. Look for the key.
Scenario 3: qcow2 VM Images → Convert to Raw First
QEMU's qcow2 format is a container format. You can't mount it directly as a loop device. Convert to raw first:
$ qemu-img convert -f qcow2 -O raw disk.qcow2 disk_raw.img
$ file disk_raw.img
disk_raw.img: DOS/MBR boot sector ...
$ mmls disk_raw.img
then proceed with normal workflow
Full Trial Process Table
| Step | Action | Command | Result | Why it failed / succeeded |
|---|---|---|---|---|
| 1 | Immediate mount attempt | mount -o loop disk.img /mnt |
❌ wrong fs type | No offset specified; kernel can't find superblock |
| 2 | Mount with calculated offset | mount -o loop,offset=1048576 disk.img /mnt |
❌ wrong fs type | Partition table malformed; offset was correct but superblock corrupted |
| 3 | Try different sector sizes | offset=2048, offset=4096 |
❌ still fails | Rabbit Hole — the issue wasn't offset math |
| 4 | Run mmls to check partition structure | mmls disk.img |
✅ Found malformed table | Revealed the actual problem: broken partition structure |
| 5 | Run binwalk to find embedded content | binwalk disk.img |
✅ Found hidden archive | Flag was in a ZIP embedded in unallocated space, not in the filesystem |
| 6 | Extract with binwalk | binwalk -e disk.img |
✅ Flag extracted | Correct approach once structure was understood |
Beginner Tips: How to Avoid the Rabbit Holes
Common Errors and What They Actually Mean
| Error Message | What It Usually Means | First Thing to Try |
|---|---|---|
wrong fs type, bad superblock |
Offset wrong OR filesystem corrupted | Run mmls to verify offset, then check superblock with debugfs
|
mount: special device does not exist |
Loop device exhausted or permissions issue |
sudo losetup -a to check active loop devices |
mount: unknown filesystem type 'LUKS' |
LUKS encrypted — can't mount directly | Use cryptsetup luksOpen first |
mount: /mnt: can't read superblock |
Filesystem integrity issue | Try fsck on the loop device, or switch to file carving |
The Checklist I Keep Open During Every Disk Challenge
- Run
filefirst — never assume the format - Run
mmlsbefore calculating any offsets manually - Always use
-o rowhen mounting forensics images - If mount fails twice with different offsets, stop — the problem isn't math
- Run
binwalkon the full image, not just the partition - Check unallocated regions — that's where CTF authors hide things
Short Command Reference
| Command | Purpose | When to Use | Notes |
|---|---|---|---|
file disk.img |
Identify format | Always first | Doesn't check integrity |
mmls disk.img |
Show partition table and boundaries | Before calculating offsets | Part of Sleuth Kit |
fdisk -l disk.img |
Alternative partition viewer | When mmls isn't available | Less forensics-friendly output |
binwalk disk.img |
Scan for embedded file signatures | Always, especially when mount fails | Finds content regardless of filesystem |
binwalk -e disk.img |
Extract identified content | After binwalk identifies targets | Creates _disk.img.extracted/ directory |
foremost -i disk.img -o ./out |
Carve files by magic bytes | When filesystem is broken | Slower but thorough |
cryptsetup luksOpen |
Open LUKS-encrypted volume | When file shows LUKS format | Requires passphrase or keyfile |
qemu-img convert |
Convert qcow2 to raw | When image is qcow2 format | Required before any other analysis |
What You Learn From This Challenge
The core skill here isn't learning to use mount. It's learning to form a hypothesis about the filesystem state before committing to a tool. mount is a precision instrument — it works perfectly when the filesystem is intact, and fails immediately when it isn't. That's actually useful information.
When mount fails in a CTF, the challenge author usually put it there on purpose. The failure is a signal, not a setback. The question is: what does this failure tell you about the image structure?
In real-world digital forensics, this same mindset applies. Investigators don't mount evidence drives directly — they image them first, verify integrity with hashes, and always work read-only. The CTF challenge is teaching you the same discipline under time pressure.
The next time you see wrong fs type, resist the urge to tweak the offset. Run mmls. Run binwalk. Understand what you're looking at before you decide how to look at it.
Top comments (0)