Guided lab: build a disk image, then take it apart

The first lab for a machine of your own. You create the evidence yourself, delete a file from it, and then recover the file you deleted, which is the only way to be certain the recovery worked.

ATT&CK
T1070.004

Most disk forensics teaching starts with somebody handing you an image and telling you what is in it. This one starts with you making the image, which means that when you go looking for the deleted file at the end, you already know exactly what you are looking for. Nothing is a surprise, and that is the point: you are checking the tools against ground truth you set yourself.

Twenty minutes, and about 70MB of disk. Everything you need was installed by the provisioner on the lab machine page.

What you need

A VM running Ubuntu 24.04 or Debian 12 with the toolkit installed, and a snapshot you can roll back to. sleuthkit, parted and dosfstools are the three that matter here.

Everything below runs in ~/lab/evidence. Nothing touches a real disk: you are working inside a file, attached to a loop device, and the last step detaches it.

Build the volume

cd ~/lab/evidence

# a 64MB file that will pretend to be a disk
dd if=/dev/zero of=case01.raw bs=1M count=64 status=progress

# one FAT32 partition, starting at the conventional 1MiB offset
parted -s case01.raw mklabel msdos
parted -s case01.raw mkpart primary fat32 1MiB 100%

# attach it, so the kernel exposes the partition as a block device
LOOP=$(sudo losetup -fP --show case01.raw)
echo "attached as $LOOP"

sudo mkfs.vfat -F 32 -n EVIDENCE "${LOOP}p1"

losetup -fP finds the first free loop device and scans the partition table, so you get /dev/loopNp1 as well as /dev/loopN. The -P is the part people forget, and without it the partition never appears.

Put something on it, then delete it

sudo mkdir -p /mnt/case01
sudo mount "${LOOP}p1" /mnt/case01

# three files, one of which is about to have a bad day
echo "quarterly figures, final version" | sudo tee /mnt/case01/report.txt
echo "notes from the call on tuesday"   | sudo tee /mnt/case01/notes.txt
echo "SECRET-CANARY-7F3A2B please do not exfiltrate me" \
  | sudo tee /mnt/case01/payroll.txt

sudo sync
sudo rm /mnt/case01/payroll.txt
sudo sync

sudo umount /mnt/case01
sudo losetup -d "$LOOP"

The canary string in the third file is there so you can prove, later, that what you recovered is the file you deleted and not something that merely looks like it.

Read the layout

mmls case01.raw

Q1

What sector does the partition start at, and why that number?

Stuck? Where to look

Read the Start column for the row whose description mentions FAT32. Then think about what 1MiB is, in 512-byte sectors.

Show the answer

2048. You asked parted for a partition beginning at 1MiB, and 1,048,576 ÷ 512 = 2048 sectors.

That offset is a convention rather than a rule, and it exists because aligning the partition to a 1MiB boundary keeps filesystem blocks aligned with the erase blocks of an SSD and the stripe width of a RAID. You will see 2048 on almost every modern disk, and 63 on older ones, which is a rough dating signal in itself.

Every Sleuth Kit tool that reads a filesystem needs to be told where that filesystem starts, because a raw image has no idea. That is what -o does, and forgetting it is the single most common beginner error with these tools.

fsstat -o 2048 case01.raw | head -30

Q2

What is the cluster size, and how many sectors is that?

Show me the method

Look for "Sectors per cluster" and "Cluster Size" in the CONTENT INFORMATION section of the fsstat output.

Show the answer

On a 64MB FAT32 volume mkfs.vfat will typically choose 1 sector per cluster, so a cluster is 512 bytes.

The number matters more than it looks. A cluster is the smallest unit the filesystem will allocate, so a one-byte file still consumes a whole cluster, and the unused remainder is slack space: whatever was in those bytes before is still there. On a volume with 32KB clusters that slack is where a surprising amount of recoverable evidence lives.

Find what is still there

fls -o 2048 -r case01.raw

Q3

How many files does fls list, and how does it mark the deleted one?

Stuck? Where to look

Compare the list against the three files you created. Look at the start of each line.

Show the answer

Three entries, and the deleted one is prefixed with *.

payroll.txt is still listed because deleting a file on FAT does not remove its directory entry. It overwrites the first character of the name with 0xE5 and marks the clusters free in the allocation table. The entry, the size and the starting cluster all survive, which is why the file is recoverable at all, and why fls can tell you it existed.

On FAT you will often see the first character of the recovered name replaced, which is why Sleuth Kit sometimes prints something like _ayroll.txt.

Recover it

Take the inode number fls printed for the deleted entry, and read the content straight out of the image.

# replace 5 with the number fls gave you
icat -o 2048 case01.raw 5

Q4

Does the recovered content contain the canary string, and what would it mean if it did not?

Show the answer

It should print SECRET-CANARY-7F3A2B please do not exfiltrate me.

If it did not, the clusters would have been reallocated to another file and overwritten in between. On a volume this quiet that will not happen, which is exactly why a real recovery is far less reliable: on a live system the clusters freed by a deletion are the first ones the next write will take.

That is the practical rule the exercise is teaching. Recoverability is a function of how much has happened since, not of how the file was deleted. It is also why powering a machine down rather than letting it keep running is sometimes the right call, and why "it has been three weeks" is a real answer to "can you get it back".

Q5

payroll.txt was 47 bytes and the cluster is 512. What happened to the other 465 bytes, and where would you look for them in a real case?

Stuck? Where to look

The filesystem allocated a whole cluster. It did not clear it first.

Show the answer

They are slack space, and they still hold whatever was in that cluster before, which on a freshly formatted volume is zeroes.

In a real case that remainder is one of the more productive places to look, because nothing clears it: a cluster that previously held part of a browser cache entry or a deleted document still holds it, under a live file that only uses the first few hundred bytes. blkls extracts unallocated space and slack for exactly this, and it is what carving tools like foremost and binwalk then run across.

Try it:

blkls -o 2048 case01.raw > unallocated.bin
ls -lh unallocated.bin
strings unallocated.bin | grep -i canary

What to take from this

You have now done, on a volume you built, the four moves that every disk examination starts with: find the partition, identify the filesystem, list what is there including what has been deleted, and pull content out by inode without mounting anything.

The reasoning transfers directly. What does not transfer is the certainty: you knew the answers before you started, and on a real image you will not. That is what the artifact reference is for, and it is why the entries there each say what an artifact does not prove.

Clean up

# check nothing is still attached before you roll back
losetup -a
sudo rm -f ~/lab/evidence/case01.raw ~/lab/evidence/unallocated.bin

Then restore your snapshot, which is the habit worth building more than any of the commands above.

Corrections and additions are welcome: this is a working document. Get in touch, or post a case of your own in the community.

Discussion

Guidelines

Sign in to comment. Corrections and additions are the point: this is a working document.