Intro to Forensics


Intro to Forensics Dojo.

This module walks you through the essential tools of digital forensics, one at a time. Each challenge introduces a single tool, explains how it works, and gives you a hands-on task to complete with it. Work through them in order, each one builds on the last.


Note: Some challenges require you to investigate image files visually. You may want to copy them to your local machine using scp:

scp -i path-to-key [email protected]:/challenge/* ./

Make sure you have the required tools installed before starting.

Refer to each tool's official documentation to learn how to use it, or just read the challenge description.



Challenges

file

file reads a file's header bytes to determine what type it actually is, regardless of its extension.

Example:

// magic number of a PNG file
89 50 4e 47 0d 0a 1a 0a

// magic number of a ZIP file
50 4b 03 04

// Plain ASCII text has no required magic number.

You can verify this yourself by running:

xxd your_ascii_file | head

and noticing the text starts immediately, with no magic header showing:

00000000: 7468 6973 2069 7320 6173 6369 6920 6669  this is ascii fi
00000010: 6c65 200a                                le .

file is important because it lets you understand what type of file you're actually dealing with, independent of its extension, and where to move on from there.

Check the files in /challenge in sequence. The password consists of the file types joined with underscores, wrapped in file{}.

Once you find it, run /challenge/check and enter the password to get the flag.

Example:

file my_file
my_file: MKL, XXX-Z XXX

file my_file2
my_file2: XYC, XXX-Z XXX

The password will look something like this: `file{MKL_XYC}`

strings

strings what a command Ha, I know you are going to skip this... just in case, it scans a file and prints every run of printable characters it finds, regardless of the file's type. It doesn't need to understand the file's structure at all, just raw bytes.

Example:

strings -n 10 file.bin

-n sets the minimum length of a printable run to print. By default, strings only shows runs of 4 or more characters, anything shorter is silently skipped. If you know (or suspect) the string you're looking for is short, lower this with -n, or you'll miss it entirely even though it's sitting right there in the file.

Find the password embedded in /challenge/image.png.

The password is wrapped in strings{}.

Once you find it, run /challenge/check and enter the password to get the flag.

xxd

xxd is a command-line utility used to create and analyze hexadecimal dumps of files.

Every byte can be represented by two hexadecimal digits.

For example:

48 65 6c 6c 6f

Represents:

Hello

You can inspect a file's raw bytes using:

xxd mystery.bin

I bet you do not know that You can also reverse a hexadecimal dump using:

_> cat sec.txt 
49 74 27 73 20 61 20 55 4e 49 58 20 73 79 73 74 65 6d 21 20 49 20 6b 6e 6f 77 20 74 68 69 73 21
_> xxd -r -p sec.txt 
It's a UNIX system! I know this!

Find the hidden password inside /challenge/mystery.bin.

The password consists of hex bytes supplied as a continuous string (such as "abcd", with no spaces or dashes), wrapped in xxd{}.

Once you find it, run /challenge/check and enter the password to get the flag.

exiftool

exiftool allows you to read, write, and edit metadata in a wide variety of files.

Example:

# Basic metadata extraction
_> exiftool image.jpeg

ExifTool Version Number         : 12.76
File Name                       : image.jpeg
Directory                       : .
File Size                       : 146 kB
...
File Permissions                : -rw-rw-r--
File Type                       : JPEG
File Type Extension             : jpg


# More detailed metadata inspection
_> exiftool -a -u -g1 -s image.jpeg

---- ExifTool ----
ExifToolVersion                 : 12.76
---- System ----
FileSize                        : 710 kB
FilePermissions                 : -rw-rw-r--
---- File ----
FileType                        : JPEG
...
---- PNG ----
...
---- Composite ----
...

Find the password in the metadata of /challenge/image.

The password is wrapped in exiftool{}. Read the description in the metadata to understand how the password was generated.

Once you find it, run /challenge/check and enter the password to get the flag.

Going Further

ExifTool is a lot more powerful than just reading basic details! You can read more about its extensive features, supported formats, and documentation on the official ExifTool website.

zsteg

zsteg is an open-source command-line tool written in Ruby, used to detect and extract data hidden inside PNG and BMP image files via steganography.

The difference between zsteg and tools like strings/exiftool is what kind of hidden data each one looks for: strings and exiftool extract embedded text and metadata that already exists as readable bytes in the file. zsteg extracts data hidden inside the pixel values themselves, one bit at a time, data that never appears as readable text anywhere in the file at all.

To understand how: suppose we have a secret message HI, converted to binary: H = 01001000, I = 01001001. An image's pixels are raw bytes, and each pixel is conceptually 3 bytes, one each for Red, Green, and Blue. The hiding technique loops over each color byte and overwrites its least significant bit (LSB) with the next bit of the secret message, one bit per byte, a change small enough that it's invisible to the human eye.

Example:

zsteg -a image.png

imagedata           .. text: "something here"
b1,rgb,lsb,xy       .. text: "exiftool{THERE_IS_NO_SPOON}"

-a tells zsteg to try every bit depth / channel / pixel-order combination instead of just the most common default, since the hiding method can vary.

Find the password hidden in the pixel data of /challenge/image.png.

The password is wrapped in zsteg{}.

Once you find it, run /challenge/check and enter the password to get the flag.

Going Further

zsteg supports many more bit-depth, channel, and ordering combinations than the default scan, You can read more about its full option set and source on the official zsteg GitHub repository.

binwalk

binwalk is a tool for searching binary images for embedded files and executable code, It can also identify and optionally extract them.

After a ZIP file is embedded into a file, strings can sometimes reveal its content if it contains printable ASCII characters:

_> echo "fake_password{inside_a_zip_file}" > flag.txt
_> zip secret.zip flag.txt
_> cat image.png secret.zip > image_cp.png
_> strings image_cp.png | grep fake
fake_password{inside_a_zip_file}

binwalk Example:

_> binwalk challenge.png 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 500 x 300, 8-bit/color RGB, non-interlaced
41            0x29            Zlib compressed data, default compression
1142          0x476           Zip archive data, at least v2.0 to extract, compressed size: 78, uncompressed size: 78, name: message.txt
1318          0x526           End of Zip archive, footer length: 22

As we can see, it successfully found message.txt. We can use the flag -e or --extract to automatically extract known file types.

However, as we mentioned previously, simply appending a ZIP file to an image doesn't hide its contents.

If the ZIP archive contains unencrypted printable text, strings may reveal it without extracting the archive.

That's why we've password-protected the ZIP file. You can find its password by applying what you've learned so far.

Find the hidden ZIP-password, extract the ZIP file, unzip it, and reveal what's hidden inside.

The password submitted to the checker should be wrapped in binwalk{CAPITAL_LETTERS_WITH_UNDERSCORES}.

Once you find it, run /challenge/check and enter the password to get the flag.

Steghide

steghide is a steganography program that is able to hide data in various kinds of image and audio files. The JPEG, BMP, WAV and AU file formats are supported for use as a cover file. There are no restrictions on the format of the secret data.

Overview: how does it work?

The secret data is first compressed and encrypted. The passphrase then seeds a pseudo-random number generator, which picks out a sequence of pixel positions in the cover file, this is where the data could go. Positions that already happen to hold the right value by chance are skipped. For the rest, a graph-matching algorithm pairs up positions so the data can be embedded by swapping their values with each other, rather than overwriting them, any leftover positions that can't be paired are overwritten directly instead.

This is the actual explanation steghide documents in its man page, it's genuinely a bit dense, so I'd recommend reading man steghide directly if you want the full technical detail rather than relying on a summary.

Example of how you can hide data using steghide:

_> steghide embed -cf test.jpeg -ef sec.txt -sf hidden.jpg
Enter passphrase:
Re-Enter passphrase:
embedding "sec.txt" in "test.jpeg"... done
writing stego file "hidden.jpg"... done

-ef, --embedfile, specify the file that will be embedded (the file that contains the secret message)

-cf, --coverfile, specify the cover file that will be used to embed data. The cover file must be in one of the following formats: AU, BMP, JPEG, or WAV.

-sf, --stegofile, specify the name for the stego file that will be created.

Get info about a file: steghide info file_name

_> steghide info hidden.jpg
"hidden.jpg":
  format: jpeg
  capacity: 3.9 KB
Try to get information about embedded data? (y/n) y
Enter passphrase:
  embedded file "sec.txt":
    size: 17.0 Byte
    encrypted: rijndael-128, cbc
    compressed: yes

Extract a hidden file: steghide extract -sf file_name

_> steghide extract -sf hidden.jpg
Enter passphrase:
wrote extracted data to "sec.txt".

_> cat sec.txt
I know kung fu: Show me.

Use steghide to extract the secret hidden inside /challenge/image.jpg.

It will ask for a passphrase, sometimes Enter alone can do the job.

The password is wrapped in steghide{}.

Once you find it, run /challenge/check and enter the password to get the flag.

Going Further

Check out man steghide for more information.

foremost

foremost is a file carving tool. It scans raw bytes for known file headers and footers and recovers files without needing a filesystem table, a filename, or an extension.

A filesystem maintains metadata describing files and where their data is stored. When that table is missing (deleted files, formatted disks, raw images) or when a file is hidden inside another, you can't ask "where are the files?" so you scan for signatures instead. For example, a JPEG starts with FF D8 FF and ends with FF D9.

Appending files to each other is enough to hide them. Many image viewers stop parsing at the end of the image, so additional data appended afterward may go unnoticed:

_> ls
audio.wav  img_1.jpg  img_2.jpg
_> cat img_1.jpg img_2.jpg audio.wav > final
_> file final
final: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 1379x919, components 3

It still opens as a normal image, and the second image and the WAV sit invisible after it.

binwalk Example:

_> binwalk -e final

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             JPEG image data, JFIF standard 1.01
530503        0x81847         JPEG image data, EXIF standard
530515        0x81853         TIFF image data, little-endian offset of first image directory: 8

_> ls
audio.wav  final  img_1.jpg  img_2.jpg

binwalk reported a second JPEG at offset 530503 (the TIFF header at 530515 is part of that same image), but -e extracted nothing. The -e flag automatically extracts only the file types it has extraction rules for, and JPEG isn't one of them. To pull out other formats, we need to tell binwalk what to carve with --dd, using 'type:extension'. 

_> binwalk --dd="jpg:jpg" final
# same report, nothing extracted

_> binwalk --dd="jpeg:jpg" final
_> ls
audio.wav  final  _final.extracted  img_1.jpg  img_2.jpg
_> ls _final.extracted/
0.jpg  81847.jpg

Both images were carved, but binwalk never mentioned the WAV at the end of the file, so it can't be extracted this way. 

foremost Example:

_> foremost -i final -o output
Processing: final
|*|
_> ls output/
audit.txt  jpg  wav
_> cat output/audit.txt
...
Num      Name (bs=512)         Size      File Offset     Comment

0:       00000000.jpg          518 KB              0
1:       00001036.jpg          1 MB           530503
2:       00003131.wav          1 MB          1603404

3 FILES EXTRACTED
jpg:= 2
rif:= 1  # rif is the file type category Foremost uses for RIFF-based files, including WAV.

As we can see, foremost found and carved both JPEGs and the WAV in one command, even though final is named and typed as a single image. It works from the content, not the name. The audit file lists every file found and its offset. You can confirm the hidden file yourself without any tool:

_> xxd -s 1603404 -l 16 final
0018774c: 5249 4646 2434 1100 5741 5645 666d 7420  RIFF$4..WAVEfmt 

You should see RIFF....WAVE at that offset

You can also carve by hand with dd, which is exactly what foremost automates.

Keep in mind that fragmented files can be carved incompletely, formats without a clear footer rely on a max size and may include junk, and a random byte sequence can look like a header (false positive).

Use binwalk for an overview, then foremost or dd to carve, and verify with xxd.

Find the hidden file inside the provided image, carve it out, and reveal what's hidden inside.

The password will not be like previous challenges. You will have to find it, combine its parts using underscores, and wrap the final result with foremost{}.

You don't have to worry about capital letters or order you will figure that out.

Once you find it, run /challenge/check and enter the password to get the flag.


30-Day Scoreboard:

This scoreboard reflects solves for challenges in this module after the module launched in this dojo.

Rank Hacker Badges Score