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.
Setup
Download and decompress the disk image.
wget <url>/dds2-alpine.flag.img.gzgunzip dds2-alpine.flag.img.gzSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Find the partition offset with mmlsObservationI 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.bashmmls dds2-alpine.flag.imgWhat 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.Step 2
Find the file's inode number with flsObservationI 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.bashfls -r -p -o 2048 dds2-alpine.flag.img | grep down-at-the-bottomWhat 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 2048tells TSK where the filesystem starts within the disk image (in 512-byte sectors), exactly the value mmls reported.Step 3
Extract the file contents with icatObservationI 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.bashicat -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 byicat(extract content) is the standard TSK pattern for targeted file recovery from disk images, equivalent tofindpluscaton 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.