Disk, disk, sleuth! II picoCTF 2021 Solution

Published: April 2, 2026

Description

All we know is the file is called 'down-at-the-bottom.txt'. Use Sleuth Kit inode tools on dds2-alpine.flag.img.gz to find and read it.

Download and decompress the disk image.

bash
wget <url>/dds2-alpine.flag.img.gz
bash
gunzip dds2-alpine.flag.img.gz

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Find the partition offset with mmls
    Observation
    I noticed the challenge provides a raw disk image file rather than a bare filesystem, which suggested the image contains a partition table and that I would need to identify where the target filesystem partition starts before any Sleuth Kit file-listing tools could read it.
    Run mmls to print the partition table. The Linux partition's starting sector is what you'll feed to -o on the next commands.
    bash
    mmls dds2-alpine.flag.img
    What didn't work first

    Tried: Run fls directly on the raw image without the -o offset, e.g. fls dds2-alpine.flag.img

    Without -o, fls tries to parse the very beginning of the image as a filesystem superblock and finds only the MBR partition table header, returning no file entries or an error like 'Cannot determine file system type'. The Linux ext2 filesystem starts at sector 2048, not sector 0. mmls is needed first to identify that starting offset.

    Tried: Skip mmls and guess the offset by trying common values like -o 63 or -o 512

    Older MBR-partitioned disks used a 63-sector offset for the first partition, but modern images (including this one) align partitions to 2048-sector boundaries. Using -o 63 gives an invalid superblock error. The correct offset must be read from the partition table with mmls rather than assumed.

    Learn more

    Sample mmls output on this image:

    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   0000262143   0000260096   Linux (0x83)

    The Linux partition starts at sector 2048, so every subsequent TSK command needs -o 2048.

  2. Step 2
    Find the file's inode number with fls
    Observation
    I noticed the challenge names the exact target file ('down-at-the-bottom.txt') but gives no path or inode number, which suggested using fls to recursively list all filesystem entries from the partition offset and grepping for that filename to obtain the inode.
    Use fls to list filesystem entries in the image. The -r flag recurses, -p prints full paths, -o 2048 is the partition offset from mmls. Grep for the filename and read the inode column.
    bash
    fls -r -p -o 2048 dds2-alpine.flag.img | grep down-at-the-bottom
    What didn't work first

    Tried: Mount the disk image with mount -o loop,offset=1048576 and then use find to locate the file

    Calculating the byte offset (2048 sectors * 512 bytes = 1048576) and mounting works on a live system if you have root, but forensic best practice avoids mounting evidence images because the OS may write access-time updates or journal entries, altering the image. The fls approach reads the filesystem structures directly in read-only mode.

    Tried: Run fls without -r and manually navigate directories by inode, passing each directory inode back to fls

    fls without -r only shows the entries in one directory at a time, so you would have to manually descend into each subdirectory. The -r flag recurses automatically, and piping to grep is far faster. This manual approach also requires knowing the root inode (usually 2 on ext2), adding extra steps.

    Learn more

    Reading fls output. A typical line looks like this; the inode number is the second column:

    r/r 18582:	root/down-at-the-bottom.txt
    ^   ^         ^
    |   |         path (full because of -p)
    |   inode (this is what you pass to icat)
    type (regular file / regular file)

    Inodes are the data structures in Unix filesystems (ext2/3/4, UFS) that store file metadata: permissions, timestamps, owner, and pointers to the data blocks. Every file and directory has an inode number. The filename is stored in the directory entry, which maps names to inode numbers.

    fls (file listing) from The Sleuth Kit lists directory entries directly from the raw disk image without mounting it. The partition offset -o 2048 tells TSK where the filesystem starts within the disk image (in 512-byte sectors), exactly the value mmls reported.

  3. Step 3
    Extract the file contents with icat
    Observation
    I noticed fls returned the inode number for down-at-the-bottom.txt, and the challenge prompt said to use Sleuth Kit inode tools, which pointed directly to icat as the tool for reading a file's data blocks from the raw image given only that inode number.
    Use icat with the inode number found in the previous step to extract and print the file contents. icat reads file data blocks directly from the raw image given just the inode number.
    bash
    icat -o 2048 dds2-alpine.flag.img <inode_number>
    What didn't work first

    Tried: Use icat without -o 2048, running icat dds2-alpine.flag.img <inode_number>

    Without the partition offset, icat attempts to interpret the start of the raw image as a filesystem, which is the MBR, not ext2. It will either error with 'Cannot determine file system type' or read garbage data blocks instead of the actual file. The -o 2048 offset is required on every TSK command that operates on files inside the partition.

    Tried: Copy the inode number from the fls column but accidentally use the file type prefix digits instead

    The fls output line looks like 'r/r 18582: root/down-at-the-bottom.txt'. The inode is 18582, but the 'r/r' type prefix and the colon can cause confusion when copying. Passing a wrong number causes icat to read an unrelated inode's data blocks, producing garbled output or an empty result rather than the flag.

    Learn more

    icat (inode cat) extracts the content of a file given its inode number, reading directly from the raw disk image. This works even for deleted files (whose directory entries have been removed but whose inode and data blocks have not yet been overwritten). It is a key tool in deleted file recovery.

    The workflow of fls (find inode) followed by icat (extract content) is the standard TSK pattern for targeted file recovery from disk images, equivalent to find plus cat on a live filesystem but operating on the raw image. For memory-side forensics with a similar inspect-without-mounting workflow, see Volatility 3 for memory forensics.

Interactive tools
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
  • File Magic IdentifierIdentify file types from magic numbers. Paste hex bytes or drop a file to detect PNG, JPEG, ZIP, PDF, ELF, PCAP, SQLite, and dozens of other formats.
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.

Flag

Reveal flag

picoCTF{f0r3ns1c4t0r_n0v1c3_...}

fls lists filesystem entries (including deleted files) by inode; icat extracts a file's content given its inode number - critical for deleted file recovery.

Key takeaway

Unix filesystems decouple filenames from file data through inodes: directory entries map names to inode numbers, and inodes point to the actual data blocks. The Sleuth Kit exploits this separation to enumerate and extract files from raw disk images without mounting them, which is essential when a filesystem is damaged, encrypted at the volume level, or part of a forensic evidence image that must not be altered. The same inode-based model means deleted files remain recoverable until their inode and data blocks are reallocated, a property investigators rely on in real incident response and data recovery.

Related reading

Want more picoCTF 2021 writeups?

Useful tools for Forensics

What to try next