Mount the image
# Simple mount (read-only, safe)
sudo mkdir /mnt/img
sudo mount -o ro,loop partition4.img /mnt/img
# ext4 with recovery (if dirty/unclean)
sudo mount -o ro,loop,noload partition4.img /mnt/img
# Browse everything including hidden files
ls -laR /mnt/img
find /mnt/img -type f | sort
find /mnt/img -name ".*" # hidden files
find /mnt/img -size +0c # non-empty files
# Unmount when done
sudo umount /mnt/img
Filesystem tree & timestamps
# Full tree with sizes
tree -ash /mnt/img
# Sort by modification time (newest first)
find /mnt/img -type f -printf "%T@ %p\n" | \
sort -rn | head -20
# Files modified in last 24h (relative to img)
find /mnt/img -newer /mnt/img -type f
# istat: inode details (sleuthkit)
istat partition4.img <inode_number>
# fls: file listing with inode info
fls -r partition4.img # recursive
fls -rd partition4.img # deleted files only
Identify & extract everything
# Identify all files by magic (not extension)
find /mnt/img -type f -exec file {} \;
# binwalk: scan for embedded files
binwalk -e suspicious_file # extract embedded
binwalk -Me suspicious_file # recursive extract
binwalk --dd='.*' file # extract ALL signatures
# foremost: file carving by header/footer
foremost -i partition4.img -o ./carved/
foremost -t jpg,png,pdf,zip -i partition4.img
# photorec: comprehensive carving (interactive)
photorec partition4.img
Archives & compressed files
# Test and list zip contents
unzip -l file.zip
unzip -t file.zip # test integrity
unzip -P password file.zip # with password
# Crack zip password
zip2john file.zip > hash.txt
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
# or
hashcat -m 13600 hash.txt rockyou.txt
# tar/gz
tar -tzvf archive.tar.gz # list contents
tar -xzvf archive.tar.gz # extract
Sleuthkit / TSK
# List ALL files including deleted (marked with *)
fls -r partition4.img
fls -rd partition4.img # deleted only
fls -rp partition4.img # full paths
# Get inode number from fls output, then:
# icat: extract file by inode
icat partition4.img <inode> > recovered_file
# istat: metadata for an inode
istat partition4.img <inode>
# ils: list inodes (including deleted)
ils -e partition4.img # everything
ils partition4.img | head -30
extundelete & ext4magic
# extundelete: recover deleted from ext3/4
extundelete partition4.img --restore-all
extundelete partition4.img --restore-directory /home
extundelete partition4.img --restore-file /etc/passwd
# ext4magic: more powerful ext4 recovery
ext4magic partition4.img -R # recover all deleted
ext4magic partition4.img -f / # specific directory
# debugfs: interactive ext2/3/4 explorer
debugfs partition4.img
# inside debugfs:
# ls -d / list all incl. deleted
# lsdel list deleted inodes
# dump <inode> /tmp/out dump by inode
Journal analysis
# ext4 keeps a journal — may contain old data
# Extract the journal inode (usually inode 8)
icat partition4.img 8 > journal.bin
# Strings from journal
strings journal.bin | grep -i "flag\|CTF\|picoCTF"
# jcat / jls (sleuthkit journal tools)
jls partition4.img
jcat partition4.img <seq> > block.bin
Autopsy (GUI)
# Full forensic suite — good for ext4
autopsy
# Then open browser to http://localhost:9999/autopsy
# Add image → analyze → deleted files tab
# CLI equivalent batch mode:
autopsy -c /path/to/case.conf
# Autopsy finds:
# - deleted files (unallocated space)
# - file slack space
# - hidden partitions
# - keyword search across image
Images (JPEG / PNG)
# steghide: embed/extract from JPEG/BMP/WAV
steghide info image.jpg # check if data embedded
steghide extract -sf image.jpg # extract (prompts passphrase)
steghide extract -sf image.jpg -p "" # empty passphrase
# stegseek: crack steghide passphrase
stegseek image.jpg /usr/share/wordlists/rockyou.txt
# zsteg: LSB steg in PNG/BMP
zsteg image.png # try all channels
zsteg -a image.png # all methods
zsteg -e b1,rgb,lsb,xy img.png # specific channel
# stegsolve (java GUI): visual analysis
java -jar stegsolve.jar
# exiftool: check all metadata
exiftool image.jpg
exiftool -comment image.jpg # just the comment field
Audio (WAV / MP3)
# Open in Audacity → view spectrogram
# Flags often hidden in spectrogram view
audacity audio.wav
# sonic-visualiser: spectrogram analysis
sonic-visualiser audio.wav
# mp3stego / wav steg tools
steghide extract -sf audio.wav
# DeepSound (Windows tool via wine)
# Decode DTMF tones
multimon-ng -t wav -a DTMF audio.wav
# LSB in WAV with python
python3 -c "
import wave, struct
w = wave.open('audio.wav')
frames = w.readframes(w.getnframes())
bits = [frame & 1 for frame in frames]
chars = [chr(int(''.join(map(str,bits[i:i+8])),2)) for i in range(0,len(bits)-8,8)]
print(''.join(chars)[:200])
"
Other steg techniques
# outguess: JPEG steg
outguess -r image.jpg output.txt
# jsteg
jsteg reveal image.jpg output.txt
# whitespace steg (SNOW)
stegsnow -C file.txt # tabs/spaces hide data
# Binary image: bin → bytes → PNG (like your challenge)
python3 -c "
bits = open('data.txt').read().replace('\n','').replace(' ','')
data = bytes(int(bits[i:i+8],2) for i in range(0,len(bits),8))
open('out.bin','wb').write(data)
"
file out.bin # identify what it is
# Least significant bit manual check
python3 -c "
from PIL import Image
img = Image.open('image.png').convert('RGB')
bits = [px[c]&1 for px in img.getdata() for c in range(3)]
chars = [chr(int(''.join(map(str,bits[i:i+8])),2)) for i in range(0,len(bits)-8,8)]
print(''.join(filter(lambda c: 32<=ord(c)<127, chars))[:300])
"
strings & grep
# Basic strings
strings partition4.img | grep -i "flag\|CTF\|pico"
# Wide strings (Unicode / Windows)
strings -el partition4.img # little-endian 16-bit
strings -eb partition4.img # big-endian 16-bit
# Minimum length filter
strings -n 6 partition4.img | grep "picoCTF{"
# Hex dump around a hit
grep -boa "picoCTF{" partition4.img # byte offset
xxd partition4.img | grep "picoCTF"
# Bulk extract printable
strings -n 4 partition4.img > all_strings.txt
grep -iE "password|secret|flag|key|token|admin" all_strings.txt
dd & raw extraction
# Extract bytes at specific offset
dd if=partition4.img of=chunk.bin \
bs=1 skip=<offset> count=<size>
# Skip in blocks (faster for large images)
dd if=partition4.img of=sector.bin \
bs=512 skip=<sector> count=1
# Extract unallocated space
blkls partition4.img > unalloc.bin
strings unalloc.bin | grep "picoCTF"
# blkcat: dump a specific block
blkcat partition4.img <block_number>
exiftool
# Full metadata dump
exiftool file.jpg
# All files in a directory
exiftool /mnt/img/ -r
# Interesting fields to check
exiftool -Comment -Artist -Copyright \
-GPSLatitude -GPSLongitude \
-CreateDate -ModifyDate file.jpg
# GPS coordinates → copy to Google Maps
exiftool -n -GPSLatitude -GPSLongitude file.jpg
# Remove all metadata (for comparison)
exiftool -all= file.jpg
PDF / Office / misc
# PDF analysis
pdfinfo file.pdf
pdf-parser file.pdf # peepdf alternative
pdfextract file.pdf # extract embedded files
strings file.pdf | grep -i "flag"
# Office documents (docx = zip)
unzip -l file.docx
unzip file.docx -d ./docx_extracted/
cat ./docx_extracted/word/document.xml
# olevba: macros in Office
olevba file.doc
# pngcheck: PNG chunk analysis
pngcheck -v image.png
Decode common encodings
# base64
echo "cGljb0NURnt..." | base64 -d
# base32
echo "NBSWY3DPE..." | base32 -d
# hex
echo "7069636f435446" | xxd -r -p
python3 -c "print(bytes.fromhex('7069636f435446').decode())"
# rot13
echo "cvpbPGS{..." | tr 'A-Za-z' 'N-ZA-Mn-za-m'
# URL decode
python3 -c "from urllib.parse import unquote; print(unquote('%70%69%63%6f'))"
# identify unknown encoding
cyberchef # use "Magic" recipe online
dcode.fr # cipher identifier
Hash identification & cracking
# Identify hash type
hash-identifier <hash>
hashid <hash>
nth -t <hash> # name-that-hash
# Common hash lengths
# 32 chars = MD5
# 40 chars = SHA1
# 56 chars = SHA224
# 64 chars = SHA256
# 128 chars = SHA512
# Crack with hashcat
hashcat -m 0 hash.txt rockyou.txt # MD5
hashcat -m 100 hash.txt rockyou.txt # SHA1
hashcat -m 1400 hash.txt rockyou.txt # SHA256
# Online rainbow tables
# crackstation.net / hashes.com
Build the timeline
# Step 1: generate bodyfile (TSK format)
# -r recursive -m prepend mountpoint / = root
fls -r -m / partition4.img > bodyfile.txt
# Step 2: convert to human-readable timeline
mactime -b bodyfile.txt -d > timeline.csv
# Step 3: sort by date — anomalies float to top/bottom
sort timeline.csv | head -30 # oldest first
sort -r timeline.csv | head -30 # newest first
# Filter to specific date range
mactime -b bodyfile.txt 1970-01-01,1990-01-01
mactime -b bodyfile.txt -d -z UTC 1980-01-01,2000-01-01
Spot anomalous timestamps
# Grep for suspicious years
grep "1970\|1969\|1971\|1985\|1980" timeline.csv
# Sort bodyfile directly by mtime (field 9, epoch int)
sort -t'|' -k9 -n bodyfile.txt | head -20
# bodyfile format (pipe-delimited):
# MD5|name|inode|perms|uid|gid|size|atime|mtime|ctime|crtime
# 1 2 3 4 5 6 7 8 9 10 11
# Example anomalous line:
# Tue Jan 01 1985 18:00:00,41,macb,r/rrw-r--r--,0,0,4945,"/bin/bcab"
# ↑ impossible date ↑size ↑inode ↑path
Extract the timestomped file
# File accessible via mount? Try icat directly instead
# "Bad message" on mount = inode metadata mangled on purpose
# icat bypasses VFS and reads raw blocks from image
# Get inode from timeline (7th CSV field, or field 3 in bodyfile)
grep "1985\|1970" timeline.csv
# → Tue Jan 01 1985 18:00:00,41,macb,...,4945,"/bin/bcab"
# ↑ inode = 4945
# Extract by inode directly
icat partition4.img 4945 > /tmp/recovered
file /tmp/recovered
cat /tmp/recovered
strings /tmp/recovered
xxd /tmp/recovered | head
binwalk -e /tmp/recovered
MAC timestamps explained
| Letter | Meaning | Updated when |
| M | Modified | File content written |
| A | Accessed | File read |
| C | Changed | Inode metadata changed |
| B | Born (crtime) | File created (ext4 only) |
| Timestomping tell | What it means |
| macb all same time | Tool set all at once (sloppy) |
| M before B (born) | Modified before created — impossible |
| Epoch 0 / 1970 | Timestamp zeroed out |
| M/A normal, C old | Only mtime/atime touched |
| Year far in past | Arbitrary fake timestamp set |
Decision tree
file / fsstat→
mount -o ro,loop→
fls -r (deleted?)→
icat → recover
fls -r -m / → bodyfile→
mactime → anomaly→
icat <inode>→
bypass bad mount
strings | grep CTF→
binwalk -e→
find hidden files→
exiftool / steghide
blkls (unalloc)→
foremost carve→
debugfs lsdel→
extundelete --restore-all
Full checklist for partition4.img
# 1. Recon
file partition4.img
fsstat partition4.img
dumpe2fs partition4.img | head -40
# 2. Mount and browse
sudo mount -o ro,noload,loop partition4.img /mnt/img
find /mnt/img -type f | xargs file
find /mnt/img -name ".*" # hidden files
ls -laR /mnt/img
# 3. Grep for flag directly
strings partition4.img | grep "picoCTF{"
grep -ria "picoCTF" /mnt/img/
# 4. MAC timeline — spot timestomped files
fls -r -m / partition4.img > bodyfile.txt
mactime -b bodyfile.txt -d | grep "197[0-9]\|198[0-9]\|Jan 01 1970"
# extract suspicious inode directly:
icat partition4.img <inode> > /tmp/timestomped && cat /tmp/timestomped
# 5. Check deleted files
fls -rd partition4.img
# recover suspicious inodes:
icat partition4.img <inode> > /tmp/recovered
# 5. Carve unallocated space
blkls partition4.img > /tmp/unalloc.bin
foremost -i /tmp/unalloc.bin -o /tmp/carved/
strings /tmp/unalloc.bin | grep "picoCTF"
# 6. Full recovery attempt
extundelete partition4.img --restore-all
ls RECOVERED_FILES/
Common hiding spots in CTF images
| Location | How to find it |
| Timestomped file | fls -r -m / img > body.txt → mactime → icat |
| Deleted file | fls -rd → icat |
| Hidden file (.name) | find -name ".*" |
| File inside file | binwalk -e |
| Image metadata | exiftool comment/artist/GPS |
| Image LSB steg | zsteg / steghide |
| Unallocated space | blkls + strings |
| Journal blocks | icat img 8 → strings |
| Slack space | blkls -s (file slack) |
| Superblock backup | dumpe2fs backup locations |
| Extended attributes | getfattr -R /mnt/img |
| Alternate data stream | rare on ext4, common on NTFS |
| Encoded in filename | fls -r | base64 -d |
QUICK START for partition4.img →
① sudo mount -o ro,noload,loop partition4.img /mnt/img
② strings partition4.img | grep "picoCTF{"
③ fls -rd partition4.img (deleted files → icat)
④ fls -r -m / partition4.img > body.txt && mactime -b body.txt -d | grep "197\|198" (timestomping)
⑤ icat partition4.img <inode> > /tmp/out (bypass bad mount)
⑥ blkls partition4.img | strings | grep picoCTF
⑦ extundelete partition4.img --restore-all