Disk Image Forensics: Why mount Fails and How to Make the Right Call First


With 45 minutes left on the clock, I burned 20 of them on offset math.

The challenge was Forensics. One file: disk.img, 350MB, no hints. I ran file on it, saw ext2, and thought — okay, easy mount. Then got smacked with wrong fs type. Instead of stopping to think, I told myself it was just an offset problem and started cycling through sector sizes, running the same command over and over with different numbers.

Classic rabbit hole.

This post is about that. Not how to use mount — there are plenty of those. This is about when to use it, when not to, and what the actual decision point looks like mid-challenge.


Why I Didn’t Mount First — And Then Did

My initial assumption: “just a normal ext4”

The first thing I ran:

file disk.img
disk.img: Linux rev 1.0 ext2 filesystem data, UUID=...

My brain immediately went to: partition table present, ext4, flag is probably somewhere under /home. When you’ve done a few of these, you start moving on autopilot — and autopilot assumes things are structurally normal. That’s the trap.

-o loop failed immediately

sudo mount -o loop disk.img /mnt/target
mount: /mnt/target: wrong fs type, bad option, bad superblock on /dev/loop0,
       missing codepage or helper program, or other error.

My first instinct: offset. I grabbed fdisk:

fdisk -l disk.img
Disk disk.img: 350 MiB, 367001600 bytes, 716800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes

Device     Boot  Start    End  Sectors  Size Id Type
disk.img1         2048  716799  714752  349M 83 Linux

Sector size 512, start at 2048, so offset = 2048 × 512 = 1048576. Fine.

sudo mount -o loop,offset=1048576 disk.img /mnt/target

Still failed.


The Rabbit Hole: 20 Minutes of Offset Obsession

This is where I fully dug in.

“Maybe the sector size is actually 4096.” “MBR header offset is different, right?” “What if there are two partitions and I’m calculating from the wrong one?”

# trying a different sector size assumption
sudo mount -o loop,offset=1048576,sizelimit=... disk.img /mnt/target

# recalculating with 4096
python3 -c "print(2048 * 4096)"  # => 8388608
sudo mount -o loop,offset=8388608 disk.img /mnt/target

All of it failed.

Twenty minutes in, I was still searching for the “right” offset — and had never once considered that the partition table itself might be broken. I knew, in theory, that CTF disk images often have intentionally corrupt structures. But in practice I was still operating under the assumption that the image was structurally intact and I just hadn’t found the right numbers yet.

That’s the gap between knowing something and actually internalizing it.


The Turning Point: What binwalk and mmls Actually Showed Me

binwalk said nothing — which was informative

binwalk disk.img
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1048576       0x100000        Linux EXT filesystem, rev 1.0

No embedded files. Normal entropy. This ruled out the “hidden file stuffed inside” class of challenge. binwalk not finding anything is still a data point — it told me I wasn’t looking at a simple embed.

mmls showed something weird

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   0000206847   0000204800   Linux (0x83)
003:  -------   0000206848   0000716799   0000509952   Unallocated

That third entry — Unallocated, ~250MB — was too large to ignore. A region that size sitting there unused, at the end of a challenge image, isn’t an accident. Either a hidden partition, or a filesystem that had been deliberately removed from the table but not wiped.

That’s when I went back to mount — but with an actual hypothesis this time.


The Fix: Options That Actually Matter

ro wasn’t optional

I mounted the valid partition (slot 002) with the correct offset:

sudo mount -o loop,offset=1048576,ro disk.img /mnt/target

It worked.

The ro flag felt almost reflexive, but it turned out to be critical. The challenge had a timeline-based component, and mounting read-write would have silently updated access timestamps — potentially corrupting the evidence I needed. In forensics work, timestamps are evidence. Mounting rw is the kind of mistake you don’t notice until you’ve already broken something.

Here’s a comparison of what I tried and what happened:

OptionResultImpact
-o loopFailedNo offset specified
-o loop,offset=1048576FailedFS still not readable (earlier attempt)
-o loop,offset=1048576,rwSucceeded, but riskyTimestamps get modified
-o loop,offset=1048576,roSucceeded, safeStable for forensic analysis

Getting to the flag after mount

Mounting is the start, not the finish. Just running ls won’t show you much. There’s an order to this:

# 1. Check lost+found first — deleted file remnants live here
ls -la /mnt/target/lost+found/

# 2. Sweep for hidden files
find /mnt/target -name ".*" -type f 2>/dev/null

# 3. bash_history is almost always worth reading
cat /mnt/target/home/user/.bash_history

# 4. Cache and logs
find /mnt/target/home -name "*.cache" -o -name "*.log" 2>/dev/null

.bash_history had something suspicious in it. The flag was one step past that.

The point isn’t that mount was the right tool. It’s that mount alone wouldn’t have gotten me there — the exploration sequence after mounting is where the actual work happens.


Cases Where mount Was the Wrong First Move

This one worked out. Others haven’t.

Case 1: File carving challenge

Image contains an intentionally broken ext2. mount returns wrong fs type and there’s nowhere to go from there. The right tool is foremost or binwalk -e — carve through the raw bytes and let it reconstruct whatever’s buried.

foremost -i raw.img -o ./recovered/

Sticking with mount here costs 15+ minutes and yields nothing.

Case 2: LUKS encryption

file encrypted.img
# => LUKS encrypted file, ver 2

mount will immediately error with unknown filesystem type 'crypto_LUKS'. You need cryptsetup first, then mount the decrypted device:

sudo cryptsetup luksOpen encrypted.img ctf_vol
sudo mount /dev/mapper/ctf_vol /mnt/target

Case 3: qcow2 VM snapshot

Common in VM-based forensics challenges. Trying to mount a .qcow2 directly does nothing useful.

# Convert to raw first
qemu-img convert -f qcow2 -O raw vm.qcow2 vm_raw.img

# Then mount normally
sudo mount -o loop,ro vm_raw.img /mnt/target

The extension .img doesn’t tell you the format. Always run file before assuming you can mount directly.


Tool Decision Cheatsheet

ToolSpeed to First InfoRabbit Hole ResistanceFailure FeedbackSwitch to mount when…
mountMediumLowPoor (cryptic errors)FS integrity is confirmed
binwalkFastMediumGood (absence = info)Embedded files are ruled out
mmlsFastHighGood (shows structure)Partition layout is understood
AutopsySlowHighGood (visual overview)Time allows for full GUI pass
foremostMediumMediumMediumFS is confirmed broken

The short version:

  • If you know the FS is intact: mount is the right call.
  • If you don’t know yet: run mmls or binwalk first.
  • If wrong fs type keeps coming back: stop, step back, re-examine your assumptions.

Why mount Fails: The Superblock

When the kernel tries to mount an ext4 filesystem, it looks for the superblock at byte offset 1024 from the start of the partition. The superblock contains a magic number — 0xEF53 — that identifies it as ext.

If your offset calculation is off, the kernel reads garbage as a superblock, doesn’t find the magic number, and throws wrong fs type.

Partition start (sector 2048) → byte offset 1048576
        ↓
Superblock expected at: 1048576 + 1024 = 1049600 bytes
        ↓
If 0xEF53 isn't there → mount fails with "wrong fs type"

Once I understood this, wrong fs type stopped being a frustrating dead end and started being a diagnostic signal: either the offset is wrong, or the filesystem is genuinely damaged. Two different problems, two different next steps.

On the MBR vs GPT front: if fdisk reports “DOS Partition Table”, you’re dealing with MBR and the numbers are straightforward. If you see a GUID, it’s GPT — the offset math is different and you’ll want to use gdisk or parted instead.


Reproducible First-Move Flow

# 1. Identify the format
file disk.img

# 2. Read the partition structure
mmls disk.img
fdisk -l disk.img

# 3. Look for anomalies
# → Large unallocated region → possible hidden partition or wiped FS
# → Broken partition table → skip mount, go to carving

# 4. Mount with confirmed offset (ro is non-negotiable)
sudo mount -o loop,offset=$(python3 -c "print(START_SECTOR * SECTOR_SIZE)"),ro disk.img /mnt/target

# 5. If mount fails
binwalk disk.img                         # check for embedded content
foremost -i disk.img -o ./out/           # carve raw bytes
file disk.img | grep -i luks             # check for encryption

# 6. If encrypted
sudo cryptsetup luksOpen disk.img vol_name
sudo mount /dev/mapper/vol_name /mnt/target

Closing: mount Is a Tool, Not a Starting Point

The most time I’ve wasted in disk forensics — CTF or otherwise — has come from reaching for a tool before forming a hypothesis. mount is powerful. When the filesystem is intact and you know your offset, it’s faster than almost anything else for getting a navigable view of the image. But it’s built on the assumption that things are structurally normal, and that assumption is exactly what a well-designed challenge will break.

Knowing when to use it is a different skill than knowing how to use it.

Next time you get a disk.img, start with file and mmls. Let the structure tell you what tool it needs. Mount can wait.


Further Reading

Most of the articles linked below come from alsavaudomila.com, a site focused on practical CTF write-ups and tool breakdowns. The writing tends to skip the theory-first approach and get straight to how tools behave in actual challenge conditions — which makes it a useful reference when you’re mid-competition and need to know what a tool does under pressure, not in a lab.

If this post got you interested in forensics tooling more broadly, CTF Forensics Tools: The Ultimate Guide for Beginners on that site is a solid place to build out your toolkit — it covers the landscape of tools you’ll encounter across different challenge types, not just disk images.

The site also has a few other tool-focused deep dives that pair well with what’s covered here. If you’ve run into challenges where the artifact isn’t a disk image but a PDF, pdfdumper in CTF: Extracting PDF Content and Common Challenge Patterns walks through the extraction workflow in the same practical style. Password-protected archives are another common Forensics staple — zip2john in CTF: Extracting ZIP Passwords and Common Challenge covers how to approach those without burning time on the wrong tool first. And if you’ve ever stared at a QR code embedded in a challenge image wondering what to do with it, zbarimg in CTF: QR/Barcode Decoding Techniques and Common Challenge Patterns has you covered.

Leave a Reply

Your email address will not be published. Required fields are marked *