MetaDetective

The cheat sheet covers OSINT metadata extraction from documents, images, and files for Red Team reconnaissance.

#Getting Started

#Installation

# Required system dependency (all methods)
sudo apt install libimage-exiftool-perl  # Debian/Ubuntu/Kali
brew install exiftool                    # macOS
winget install OliverBetz.ExifTool       # Windows

# pip (recommended)
pip install MetaDetective
metadetective -h

# Direct single-file download (no install, no deps)
curl -O https://raw.githubusercontent.com/aurelienguidi/MetaDetective/stable/src/MetaDetective/MetaDetective.py
python3 MetaDetective.py -h

# Docker
docker pull aurelienguidi/metadetective
docker run --rm -v $(pwd)/loot:/data aurelienguidi/metadetective -d /data

# Git clone
git clone https://github.com/franckferman/MetaDetective.git
cd MetaDetective
python3 src/MetaDetective/MetaDetective.py -h

#Quick Reference One-Liners

# Analyze a directory (deduplicated singular view - default)
metadetective -d ./loot/

# Per-file display (all metadata per document)
metadetective -d ./loot/ --display all

# Formatted output (vertical list with markers)
metadetective -d ./loot/ --format formatted

# Summary stats + timeline
metadetective -d ./loot/ --summary --timeline

# Scrape + download from target site (depth 1 minimum for real use)
metadetective --scraping --url https://target.com/ \
  --download-dir ~/loot/ --depth 2 --threads 8

# Scan preview (no download, just list files found)
metadetective --scraping --scan --url https://target.com/ --depth 1

# Export to HTML report
metadetective -d ./loot/ -e html -o ~/results/

#MetaDetective Commands

#File & Directory Analysis

# Analyze a single file
metadetective -f report.pdf

# Analyze a directory
metadetective -d ./loot/

# Filter to specific file types only
metadetective -d ./loot/ -t pdf docx xlsx

# Ignore/exclude matching values (regex supported)
metadetective -d ./loot/ -i "admin" "anonymous" "unknown"

# Extract only specific metadata fields
metadetective -d ./loot/ --parse-only "Author" "Creator Tool" "GPS Position"

# Per-file view (all metadata shown per file)
metadetective -d ./loot/ --display all

# Deduplicated cross-file view (default - best for username harvest)
metadetective -d ./loot/ --display singular

# Compact output format
metadetective -d ./loot/ --format concise

# Decorated output format
metadetective -d ./loot/ --format formatted

#Export Options

# Export as HTML (default)
metadetective -d ./loot/ -e

# Export as JSON
metadetective -d ./loot/ -e json

# Export as plain text
metadetective -d ./loot/ -e txt

# Custom output filename suffix
metadetective -d ./loot/ -e json -c pentest-corp

# Custom output directory
metadetective -d ./loot/ -e json -o ~/results/

# Full export: per-file JSON to custom dir
metadetective -d ./loot/ --display all -e json -o ~/results/

#Web Scraping Mode

# Scan target site: list discovered files, no download
metadetective --scraping --scan --url https://target.com/

# Filter by file extensions during scan
metadetective --scraping --scan --url https://target.com/ \
  --extensions pdf docx xlsx pptx

# Download discovered files
metadetective --scraping --url https://target.com/ \
  --download-dir ~/loot/

# Deep crawl: depth 2, 8 threads, 5 req/sec rate limit
metadetective --scraping --url https://target.com/ \
  --download-dir ~/loot/ --depth 2 --threads 8 --rate 5

# Follow links to external domains
metadetective --scraping --url https://target.com/ \
  --download-dir ~/loot/ --follow-extern

#All Flags Reference

Flag Argument Description
-f file [file ...] Analyze one or more specific files
-d directory Analyze all files in a directory
-t ext [ext ...] Filter to specific file types (e.g. pdf docx)
-i pattern [...] Ignore/exclude values matching regex patterns
--parse-only field [...] Extract named metadata fields only
--display all / singular Per-file view vs. deduplicated cross-file view
--format formatted / concise Output style: decorated or compact
-e [html|txt|json] Export format (HTML default)
-c suffix Custom filename suffix for export
-o path Output directory for exported files
--scraping -- Enable web scraping mode
--scan -- List files found on site without downloading
--url https://... Target website URL
--extensions ext [...] Limit scraping to these file types
--download-dir path Save downloaded files here
--depth int Crawl depth level
--threads int Concurrent download threads
--rate float Requests per second limit
--follow-extern -- Follow links to external domains
--user-agent string\|preset Custom UA or preset (chrome-win, firefox-linux, googlebot, stealth...)
--summary -- Show statistical overview of extracted metadata
--timeline -- Display chronological document events
--no-banner -- Suppress ASCII banner (useful for scripting/piping)

#Supported Formats

#File Type Coverage

Category Formats Key Metadata Fields
Documents .pdf .docx .xlsx .pptx .odt .odp .rtf .xls Author, Company, Creator Tool, Template path, Revision number
Structured .csv .xml Embedded properties, generator info
Images .jpg .jpeg .png .tiff .bmp .gif .svg .psd .heic .heif GPS lat/lon, camera make/model, serial number, date/time
Email .eml .msg .pst .ost From/To addresses, mail client, timestamps
Video .mp4 .mov GPS, device, encoder, creation date

#What Metadata Reveals

Metadata Field Found In Red Team Value
Author DOCX, PDF, XLSX Valid AD/domain username
LastModifiedBy DOCX, XLSX Recently active employee
Company Office docs Organization confirmation
Creator Tool / Producer PDF Software stack and version disclosure
Template DOCX Internal file share UNC path
GPS Position JPEG, HEIC, MP4 Physical employee location
GPS Map Link MetaDetective output Clickable Google Maps pin
Camera Model + Serial JPEG Device fingerprinting and correlation
Software PNG, TIFF Toolchain fingerprinting
Hostname / Computer Office, PDF Internal hostname disclosure
Revision Number DOCX Document history depth
Hyperlinks PDF, DOCX Internal URLs, intranet addresses
From / To (email) EML, MSG Confirmed phishing targets

#OSINT Workflow

#Recon Decision Table

Scenario Command Output
Got a domain, want to scan for files metadetective --scraping --scan --url https://target.com/ List of exposed documents
Download all discovered files metadetective --scraping --url https://target.com/ --download-dir ~/loot/ --depth 2 --threads 8 Files saved to ~/loot/
Analyze local docs for usernames metadetective -d ./loot/ --display singular -e json Deduplicated author/creator list
Extract only author fields from Office docs metadetective -d ./loot/ -t docx xlsx pptx --parse-only "Author" "Last Modified By" "Company" Username + org names
Extract GPS from images metadetective -d ./photos/ --parse-only "GPS Position" "GPS Map Link" Lat/lon + Google Maps links
Analyze email archives metadetective -d ./mail/ -t eml msg --parse-only "From" "To" "X-Mailer" Confirmed email addresses + mail client
Software stack fingerprinting metadetective -d ./loot/ -t pdf --parse-only "Producer" "Creator Tool" "Software" PDF generators, Office versions
Full stats + timeline metadetective -d ./loot/ --summary --timeline Document creation/modification timeline
Stealth scraping (custom UA) metadetective --scraping --url https://target.com/ --user-agent stealth --rate 2 Slow crawl with realistic user-agent

#Practical Recon Timeline

# 1. Passive document discovery via site scan
metadetective --scraping --scan --url https://target.com/

# 2. Download all exposed docs
metadetective --scraping --url https://target.com/ \
  --download-dir ~/loot/ --depth 2 --threads 8 --rate 3

# 3. Bulk metadata extraction (deduplicated)
metadetective -d ~/loot/ --display singular -e json

# 4. Parse usernames from JSON output
jq '.unique.Author[]' results.json | sort -u

# 5. Extract GPS from any images found
metadetective -d ~/loot/ --parse-only "GPS Position" "GPS Map Link"

# 6. Identify software stack from PDF Producer/Creator fields
metadetective -d ~/loot/ -t pdf --parse-only "Producer" "Creator Tool"

# 7. Map internal paths from Template and Hyperlinks
metadetective -d ~/loot/ --parse-only "Template" "Hyperlinks"

# 8. Cross-reference usernames against LinkedIn for confirmation
# 9. Use confirmed usernames for password spray / phishing pretexting

#Tool Comparison

#MetaDetective vs ExifTool vs metagoofil vs FOCA

Feature MetaDetective ExifTool metagoofil FOCA
Platform Linux/Mac/Win Linux/Mac/Win Linux/Mac/Win Windows only
All-in-one (crawl + extract + export) Yes No (extract only) No (download only) Partial
Document discovery Direct site crawl No Google/Bing dorks Google/Bing/DDG
Metadata extraction Yes Yes No Yes
GPS extraction + map link Yes (clickable map) Raw coords only No No
Email support (EML/PST/OST) Full support Partial No Limited
Deduplication Built-in (singular) No No Yes
Summary + timeline Yes (--summary --timeline) No No No
Export formats HTML, JSON, TXT JSON, CSV, XML None Internal DB
Rate limiting + stealth UA Yes (--rate + --user-agent) N/A Delay only No
RAW camera formats Use with ExifTool Yes (CR2, NEF...) No No
Metadata removal No Yes No No
Active maintenance Yes Yes Yes Last release 2021

MetaDetective is the only tool that combines web crawling, metadata extraction, deduplication, GPS mapping, and structured export in a single command. For RAW camera formats or metadata removal, pair MetaDetective with ExifTool for full coverage.

#When to Use Which Tool

Scenario Best Tool
Full recon pipeline (crawl + extract + export) MetaDetective --scraping + -e json
Deduplicated username list from loot MetaDetective --display singular
GPS extraction + clickable map link MetaDetective --parse-only "GPS Map Link"
Email archive (.pst/.ost/.eml) analysis MetaDetective -t eml msg
Document timeline + statistics MetaDetective --summary --timeline
Stealth scraping with rate control MetaDetective --rate 2 --user-agent stealth
Google-dork for docs metagoofil + MetaDetective
RAW camera formats ExifTool
Strip metadata mat2
GUI recon (Windows) FOCA (legacy)

#metagoofil + MetaDetective Combo

metagoofil finds documents via Google dorking. MetaDetective does not Google-dork - it crawls the target site directly. Use both for maximum coverage.

# 1. Install metagoofil
pip install metagoofil

# 2. Google-dork for docs (downloads to ./target_files/)
python metagoofil.py -d target.com -t pdf,doc,xls,pptx -n 50 -f

# 3. With delay + proxy to avoid Google 429 blocks
proxychains4 python metagoofil.py -d target.com -t pdf,docx -n 30 -e 3 -f

# 4. Feed metagoofil downloads into MetaDetective
metadetective -d ./target.com/ --display singular -e json --no-banner

# 5. Meanwhile, also crawl the target site directly
metadetective --scraping --url https://target.com/ \
  --download-dir ./target_crawl/ --depth 2 --threads 8

# 6. Analyze crawled files too
metadetective -d ./target_crawl/ --display singular -e json --no-banner

# 7. Compare results - metagoofil may find docs not linked on the site
#    MetaDetective crawl may find docs not indexed by Google

#Automation & Scripting

#Full Recon Script

#!/bin/bash
# Metadata OSINT: scrape target site, extract, report
TARGET="${1:-target.com}"
LOOT="/tmp/meta_osint_${TARGET}"
RESULTS="${LOOT}/results"

mkdir -p "${LOOT}/downloads" "${RESULTS}"

echo "[*] Phase 1: Crawling and downloading files from ${TARGET}..."
metadetective --scraping --url "https://${TARGET}/" \
  --extensions pdf docx xlsx pptx odt \
  --download-dir "${LOOT}/downloads" \
  --depth 3 --threads 8 --rate 3 --user-agent stealth --no-banner

echo "[*] Phase 2: Extracting metadata (deduplicated + JSON export)..."
metadetective -d "${LOOT}/downloads" \
  --display singular -e json -o "${RESULTS}" -c "${TARGET}" --no-banner

echo "[*] Phase 3: Summary statistics + timeline..."
metadetective -d "${LOOT}/downloads" --summary --timeline --no-banner

echo "[*] Phase 4: Parsing intelligence from JSON..."
echo ""
echo "=== USERNAMES ==="
jq -r '.unique.Author[]? // empty' "${RESULTS}/"*"${TARGET}"*.json 2>/dev/null | sort -u

echo ""
echo "=== SOFTWARE VERSIONS ==="
jq -r '.unique["Creator Tool"][]? // empty' "${RESULTS}/"*"${TARGET}"*.json 2>/dev/null | sort -u

echo ""
echo "=== GPS HITS ==="
jq -r '.unique["GPS Position"][]? // empty' "${RESULTS}/"*"${TARGET}"*.json 2>/dev/null

echo ""
echo "=== COMPANIES ==="
jq -r '.unique.Company[]? // empty' "${RESULTS}/"*"${TARGET}"*.json 2>/dev/null | sort -u

echo ""
echo "[+] Done. Results in ${RESULTS}/"
echo "[+] Open HTML report: ${RESULTS}/"*".html"

#jq Pivots on JSON Output

After exporting with -e json, use jq to extract actionable intelligence.

# All unique authors -> potential AD usernames for spray
jq -r '.unique.Author[]' results.json | sort -u

# All unique "Last Modified By" -> recently active employees
jq -r '.unique["Last Modified By"][]' results.json | sort -u

# Combine author + last modified -> full username list
jq -r '(.unique.Author[]?, .unique["Last Modified By"][]?) // empty' results.json | sort -u > usernames.txt

# Software fingerprinting -> identify tech stack
jq -r '(.unique["Creator Tool"][]?, .unique.Producer[]?, .unique.Software[]?) // empty' results.json | sort -u

# GPS positions -> physical locations
jq -r '.unique["GPS Position"][]' results.json

# GPS map links -> clickable Google Maps URLs
jq -r '.unique["GPS Map Link"][]' results.json

# Company names -> confirm org and subsidiaries
jq -r '.unique.Company[]' results.json | sort -u

# Internal paths -> UNC shares, intranet URLs
jq -r '(.unique.Template[]?, .unique.Hyperlinks[]?) // empty' results.json | grep -i '\\\\|//\|intranet\|internal'

# Count per field -> identify richest metadata sources
jq -r '.unique | to_entries[] | "\(.value | length)\t\(.key)"' results.json | sort -rn

# Generate users.txt for password spray (first.last format)
jq -r '.unique.Author[]' results.json | sort -u | \
  awk '{gsub(/ /,"."); print tolower($0)}' > spray_users.txt

#Filtering & Excluding Noise

# Exclude common default/garbage author values
metadetective -d ./loot/ \
  -i "Administrator" "admin" "User" "unknown" "Anonymous" \
     "Microsoft" "Adobe" "root" "Default" "test" "owner"

# Exclude specific software noise
metadetective -d ./loot/ \
  -i "Microsoft Office" "Adobe Acrobat" "LibreOffice" "Google"

# Focus only on GPS-tagged files (images + videos)
metadetective -d ./loot/ -t jpg jpeg heic mp4 \
  --parse-only "GPS Position" "GPS Map Link" "Camera Model Serial Number"

# Only author fields from Office docs
metadetective -d ./loot/ -t docx xlsx pptx \
  --parse-only "Author" "Last Modified By" "Company"

# Only internal paths (template + hyperlinks)
metadetective -d ./loot/ -t docx pdf \
  --parse-only "Template" "Hyperlinks"

# PDF-only software fingerprint
metadetective -d ./loot/ -t pdf \
  --parse-only "Producer" "Creator Tool" \
  --display singular -e json

# Full analysis excluding noise + JSON export
metadetective -d ./loot/ \
  -i "admin" "unknown" "Microsoft" "Adobe" \
  --display singular -e json -o ./results/ --no-banner

#Metadata Cleaning

#Stripping Metadata with mat2

mat2 (Metadata Anonymisation Toolkit v2) is the simplest way to strip metadata before publishing documents. It handles all common formats automatically.

# Install
apt install mat2              # Debian/Ubuntu
pip install mat2              # pip

# Strip metadata from a file (creates .cleaned copy)
mat2 document.pdf
mat2 photo.jpg

# Preview what would be removed (dry run)
mat2 --show document.pdf

# Check if metadata is present
mat2 --check document.pdf

# Batch process all files in a directory
mat2 /path/to/publish/*.pdf
mat2 /path/to/publish/*.docx
mat2 /path/to/publish/*.jpg

# Verify with MetaDetective that metadata is gone
metadetective -f document.cleaned.pdf --no-banner

#High-Risk Fields to Sanitize

Field Risk How MetaDetective finds it
Author / LastModifiedBy Username enumeration --parse-only "Author" "Last Modified By"
Company Organization leak --parse-only "Company"
Template path UNC/intranet path leak --parse-only "Template"
GPS coordinates Physical location --parse-only "GPS Position" "GPS Map Link"
Software / Producer Version disclosure --parse-only "Producer" "Creator Tool"
HostComputer Hostname leak --parse-only "Host Computer"
Revision history Edit trail --parse-only "Revision Number"
Hyperlinks Internal URL leak --parse-only "Hyperlinks"

Use MetaDetective to identify which files contain high-risk metadata, then mat2 to strip it before publishing.

#Also See

#Cyber Aurelien Guidi