Email Forensics Deep Reference
Email Forensics Deep Reference
[MODE: BLUE] | CIPHER Training Module | Email Header Analysis, BEC Investigation, Phishing Forensics
Table of Contents
- Email Header Anatomy
- Received Header Chain Analysis
- Authentication Result Analysis
- Common Header Manipulation Techniques
- Attachment Analysis Methodology
- URL Analysis in Emails
- BEC Investigation Playbook
- Microsoft 365 Email Forensics
- Google Workspace Email Forensics
- Email as Evidence
- Tools Reference
1. Email Header Anatomy
1.1 How Email Headers Work
Email headers are metadata lines prepended to a message as it traverses the mail delivery chain. Each Mail Transfer Agent (MTA) adds headers. Headers are read bottom-to-top — the bottom-most Received: header is the originating hop; the top-most is the final delivery server.
Key RFC: RFC 5322 (Internet Message Format), RFC 5321 (SMTP).
1.2 Core Header Fields (RFC 5322bis / IANA Registry)
Envelope and Routing Headers
| Header | Purpose | Trace Header | RFC |
|---|---|---|---|
Received |
Records each MTA hop with timestamp, IP, protocol | Yes | RFC 5322 |
Return-Path |
Envelope sender (MAIL FROM), set by final delivery MTA | Yes | RFC 5322 |
Delivered-To |
Final recipient mailbox (added by delivery agent) | — | RFC 9228 |
Envelope-To |
Envelope recipient (non-standard, some MTAs) | — | — |
Originator Headers
| Header | Purpose | RFC |
|---|---|---|
From |
Author address displayed to recipient (RFC 5322 address) | RFC 6854 |
Sender |
Actual sending entity when different from From |
RFC 6854 |
Reply-To |
Preferred reply address | RFC 5322 |
Date |
Message composition timestamp (RFC 2822 format) | RFC 5322 |
Message-ID |
Globally unique message identifier (<local@domain>) |
RFC 5322 |
Destination Headers
| Header | Purpose | RFC |
|---|---|---|
To |
Primary recipient(s) | RFC 5322 |
Cc |
Carbon copy recipient(s) | RFC 5322 |
Bcc |
Blind carbon copy (stripped before delivery) | RFC 5322 |
Content and MIME Headers
| Header | Purpose | RFC |
|---|---|---|
Subject |
Message subject line | RFC 5322 |
MIME-Version |
MIME version (always 1.0) |
RFC 2045 |
Content-Type |
Media type and parameters (charset, boundary) | RFC 2045 |
Content-Transfer-Encoding |
Encoding (base64, quoted-printable, 7bit, 8bit) | RFC 2045 |
Content-Disposition |
Inline or attachment; filename parameter | RFC 2183 |
Content-ID |
Identifies MIME part for inline references (cid:) |
RFC 2045 |
Content-Description |
Human-readable description of MIME part | RFC 2045 |
Thread and Reference Headers
| Header | Purpose | RFC |
|---|---|---|
In-Reply-To |
Message-ID of parent message | RFC 5322 |
References |
Ordered list of Message-IDs in thread chain | RFC 5322 |
Keywords |
Message keywords/tags | RFC 5322 |
Comments |
Free-form comments | RFC 5322 |
Authentication Headers
| Header | Purpose | RFC |
|---|---|---|
Authentication-Results |
SPF/DKIM/DMARC/ARC results from receiving MTA | RFC 8601 |
Received-SPF |
SPF check result from receiving MTA | RFC 7208 |
DKIM-Signature |
DKIM cryptographic signature | RFC 6376 |
ARC-Authentication-Results |
ARC chain authentication results | RFC 8617 |
ARC-Message-Signature |
ARC message-level signature | RFC 8617 |
ARC-Seal |
ARC chain validation seal | RFC 8617 |
Mailing List Headers
| Header | Purpose | RFC |
|---|---|---|
List-ID |
Mailing list identifier | RFC 2919 |
List-Unsubscribe |
Unsubscribe URL or mailto | RFC 2369 |
List-Unsubscribe-Post |
One-click unsubscribe via POST | RFC 8058 |
List-Archive |
List archive URL | RFC 2369 |
List-Help |
List help URL | RFC 2369 |
List-Post |
Posting address | RFC 2369 |
List-Subscribe |
Subscribe URL or mailto | RFC 2369 |
List-Owner |
List owner contact | RFC 2369 |
Notification and Delivery Headers
| Header | Purpose | RFC |
|---|---|---|
Disposition-Notification-To |
Request read receipt | RFC 3798 |
Disposition-Notification-Options |
Options for disposition notifications | RFC 3798 |
Original-Recipient |
Original envelope recipient | RFC 3798 |
Auto-Submitted |
Indicates auto-generated message (auto-generated, auto-replied) |
RFC 3834 |
Resent Headers (Forwarding/Redistribution)
| Header | Purpose | RFC |
|---|---|---|
Resent-From |
Address of entity resending | RFC 6854 |
Resent-Sender |
Actual resending agent | RFC 6854 |
Resent-To |
New recipient(s) | RFC 5322 |
Resent-Cc |
New CC recipient(s) | RFC 5322 |
Resent-Bcc |
New BCC recipient(s) | RFC 5322 |
Resent-Date |
Date of resending | RFC 5322 |
Resent-Message-ID |
New Message-ID for resent copy | RFC 5322 |
Priority and Handling Headers
| Header | Purpose | Notes |
|---|---|---|
Importance |
Message importance (low, normal, high) |
X.400 origin |
Priority |
Message priority (non-urgent, normal, urgent) |
X.400 origin |
Sensitivity |
Sensitivity (personal, private, company-confidential) |
X.400 origin |
MT-Priority |
SMTP priority level | RFC 6758 |
Expires |
Suggested expiration date | X.400 origin |
TLS and Transport Security
| Header | Purpose | RFC |
|---|---|---|
TLS-Required |
Require TLS for delivery (No to downgrade) |
RFC 8689 |
TLS-Report-Domain |
Domain for TLS-RPT reporting | RFC 8460 |
TLS-Report-Submitter |
Entity submitting TLS report | RFC 8460 |
Common Non-Standard (X-) Headers
| Header | Purpose | Source |
|---|---|---|
X-Mailer / X-MimeOLE |
Sending client identifier | Client-specific |
X-Originating-IP |
Sender's IP (webmail) | Webmail providers |
X-Forwarded-To / X-Forwarded-For |
Forwarding chain info | Mail forwarders |
X-Spam-Status / X-Spam-Score |
Spam filter verdict | SpamAssassin etc. |
X-MS-Exchange-Organization-* |
Exchange-specific routing/policy | Microsoft Exchange |
X-Google-DKIM-Signature |
Google's internal DKIM signature | Gmail |
X-Gm-Message-State |
Gmail internal message state | Gmail |
X-MS-Has-Attach |
Exchange attachment indicator | Microsoft |
X-MS-TNEF-Correlator |
TNEF content correlation | Microsoft |
X-Auto-Response-Suppress |
Suppress OOF/auto-reply types | Microsoft |
X-Priority |
Legacy priority (1=highest, 5=lowest) | Legacy clients |
1.3 Header Ordering and Significance
[Top of headers — added last by receiving MTA]
Received: by final-mta.example.com ... ← Final hop (your MTA)
Authentication-Results: ... ← YOUR MTA's auth verdict
Received: by relay2.example.net ... ← Intermediate relay
Received: by relay1.example.net ... ← Intermediate relay
Received: by origin-mta.sender.com ... ← Sender's outbound MTA
[Bottom of headers — original message headers]
DKIM-Signature: ... ← Sender's DKIM sig
From: sender@sender.com
To: recipient@example.com
Subject: ...
Date: ...
Message-ID: ...
MIME-Version: 1.0
Content-Type: ...
Critical forensic principle: Only headers added by YOUR infrastructure (top of chain) are trustworthy. Everything below could be forged by the sender.
2. Received Header Chain Analysis
2.1 Received Header Syntax
Received: from <sending-host> (<reverse-dns> [<IP>])
by <receiving-host> (<software>)
with <protocol> id <message-id>
for <recipient>;
<timestamp (RFC 2822)>
Example:
Received: from mail-sor-f41.google.com (mail-sor-f41.google.com [209.85.220.41])
by mx.example.com (Postfix)
with ESMTPS id A1B2C3D4E5
for <user@example.com>;
Fri, 14 Mar 2026 10:23:45 +0000 (UTC)
2.2 Parsing Each Received Hop
For each Received: header, extract:
| Field | What to Examine |
|---|---|
from <hostname> |
HELO/EHLO identity claimed by sending server |
(<reverse-dns> [<IP>]) |
Actual rDNS and IP of connecting server — this is verified by the receiving MTA |
by <hostname> |
The server that received and logged this hop |
with <protocol> |
Protocol: SMTP, ESMTP, ESMTPS (TLS), ESMTPSA (TLS+Auth), HTTP (webmail), LMTP |
id <msg-id> |
Queue/session ID on the receiving server |
for <recipient> |
Envelope recipient at this hop |
| Timestamp | When this hop occurred |
2.3 Trace Analysis Procedure
STEP 1: Number hops bottom-to-top (Hop 1 = origination)
STEP 2: For each hop, record:
- Claimed HELO name vs actual rDNS vs IP
- Timestamp and time zone
- Protocol (ESMTPS = encrypted, ESMTP = cleartext)
STEP 3: Calculate delay between consecutive hops
- Normal: < 5 seconds between hops
- Suspicious: > 30 seconds (processing delay, greylisting, or queuing)
- Very suspicious: negative time delta (clock skew or forged timestamps)
STEP 4: Identify trust boundary
- Your organization's MTA is the trust boundary
- Headers below the trust boundary could be attacker-controlled
STEP 5: Verify IP geolocation and ASN for each external hop
STEP 6: Cross-reference originating IP against threat intelligence
2.4 Red Flags in Received Headers
| Indicator | Significance |
|---|---|
| HELO name doesn't match rDNS | Misconfigured or intentionally deceptive sender |
| IP resolves to residential ISP or VPN/proxy | Likely compromised host or anonymized sender |
Missing Received headers |
Headers stripped (some services do this legitimately; also attacker technique) |
| Inconsistent timestamp ordering | Possible header injection or forged headers |
with HTTP or with HTTPREST at origin |
Sent via webmail interface |
with ESMTPSA |
Authenticated SMTP submission (legitimate user or compromised credentials) |
| Unusual number of hops (>6) | May indicate open relays, forwarding chains, or obfuscation |
| Internal-looking hostnames in external email | Header injection to simulate internal routing |
2.5 Identifying the True Originating IP
1. Find the LOWEST Received header (bottom of chain)
2. If from a known webmail service (Gmail, Outlook, Yahoo):
- The originating IP is the webmail server, NOT the user's IP
- Check X-Originating-IP header (if present) for user IP
- Gmail removed X-Originating-IP in 2013 for privacy
3. If from an on-premise mail server:
- The first external hop (first hop outside sender's infrastructure) reveals the sender's network
4. Validate: does the IP belong to the domain's published SPF/MX records?
2.6 Received Header Parsing with Command Line
# Extract all Received headers from an EML file
grep -i "^Received:" email.eml
# Extract with continuation lines (multi-line headers)
grep -P "^Received:|^\s+" email.eml | grep -B1 "^\s+" | tr '\n' ' ' | sed 's/Received:/\nReceived:/g'
# Extract IPs from Received headers
grep -oP '\[(\d{1,3}\.){3}\d{1,3}\]' email.eml | tr -d '[]' | sort -u
# Extract timestamps from Received headers
grep -i "^Received:" email.eml | grep -oP ';\s*.*$' | sed 's/^;\s*//'
# Quick originating IP identification
formail -x Received < email.eml | tail -1 | grep -oP '\[(\d{1,3}\.){3}\d{1,3}\]'
3. Authentication Result Analysis
3.1 SPF (Sender Policy Framework)
Purpose: Validates that the sending IP is authorized to send for the envelope sender domain (MAIL FROM).
DNS Record: TXT record on sender domain.
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all
SPF Result Values (RFC 7208):
| Result | Meaning | Forensic Significance |
|---|---|---|
pass |
IP authorized by domain's SPF | Legitimate or attacker using authorized infrastructure |
fail (-all) |
IP explicitly NOT authorized | Strong indicator of spoofing (if DMARC enforces) |
softfail (~all) |
IP not authorized, treat as suspicious | Common — many domains use ~all instead of -all |
neutral (?all) |
Domain makes no assertion | No useful signal |
none |
No SPF record published | Domain has no SPF protection |
temperror |
Temporary DNS failure | Retry; not conclusive |
permerror |
SPF record syntax error | Broken SPF — investigate |
SPF Header Example:
Received-SPF: pass (google.com: domain of user@example.com designates 192.0.2.1 as permitted sender)
client-ip=192.0.2.1;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of user@example.com designates 192.0.2.1 as permitted sender)
smtp.mailfrom=user@example.com
SPF Forensic Checks:
# Query SPF record
dig +short TXT example.com | grep "v=spf1"
# Resolve includes recursively
# Use dmarcian or mxtoolbox SPF survey for full expansion
# Check if sending IP falls within SPF ranges
# Compare client-ip in Received-SPF against published ranges
SPF Limitations [CONFIRMED]:
- SPF checks MAIL FROM (envelope sender), NOT the
From:header displayed to users - SPF breaks on forwarding (forwarding server IP is not in original domain's SPF)
- SPF has a 10-DNS-lookup limit — exceeding it causes
permerror - Attackers can pass SPF by using their own domain in MAIL FROM while spoofing the display
From:
3.2 DKIM (DomainKeys Identified Mail)
Purpose: Cryptographic signature proving message integrity and authenticating the signing domain.
DNS Record: Public key at <selector>._domainkey.<domain> TXT record.
DKIM-Signature Header Fields:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=selector1;
h=from:to:subject:date:message-id:content-type:mime-version;
bh=<body-hash>;
b=<signature>;
| Tag | Meaning |
|---|---|
v |
Version (always 1) |
a |
Algorithm (rsa-sha256 standard; rsa-sha1 weak/deprecated) |
c |
Canonicalization (header/body): simple or relaxed |
d |
Signing domain — this is the authenticated identity |
s |
Selector (identifies which key to query in DNS) |
h |
Signed header fields (order matters) |
bh |
Body hash (Base64) |
b |
Signature (Base64) |
t |
Signature timestamp (Unix epoch) |
x |
Signature expiration (Unix epoch) |
l |
Body length limit (dangerous — allows appending unsigned content) |
i |
Agent or user identifier (optional, must be subdomain of d) |
q |
Query method (always dns/txt) |
DKIM Result Values:
| Result | Meaning |
|---|---|
pass |
Signature valid, message integrity confirmed |
fail |
Signature invalid — message modified in transit or forged signature |
none |
No DKIM signature present |
neutral |
Signature present but cannot be verified |
temperror |
Temporary failure (DNS timeout) |
permerror |
Permanent failure (missing key, bad format) |
policy |
Signature not acceptable per local policy |
DKIM Forensic Checks:
# Query DKIM public key
dig +short TXT selector1._domainkey.example.com
# Verify DKIM signature with opendkim
opendkim-testkey -d example.com -s selector1 -vvv
# Check signature with Python dkimpy
pip install dkimpy
dkimverify < message.eml
# Check which headers are signed (h= tag)
# CRITICAL: If "from" is not in h= tag, the From header is not authenticated
DKIM Forensic Red Flags:
l=tag present: attacker can append content after the signed body lengtha=rsa-sha1: weak algorithm, vulnerable to collision attacksh=does not includefrom: signature doesn't protect sender identity- Signature
d=domain doesn't matchFrom:domain: third-party signature (may be legitimate relay or suspicious) x=expired: signature no longer valid (may be legitimate for old messages)- Key length < 1024 bits: potentially forgeable [CONFIRMED]
3.3 DMARC (Domain-based Message Authentication, Reporting, and Conformance)
Purpose: Links SPF and DKIM to the From: header domain. Tells receivers what to do when authentication fails.
DNS Record: _dmarc.example.com TXT "v=DMARC1; p=reject; ..."
DMARC Record Tags:
| Tag | Purpose | Values |
|---|---|---|
v |
Version | DMARC1 |
p |
Policy for domain | none (monitor), quarantine, reject |
sp |
Policy for subdomains | Same as p |
rua |
Aggregate report recipients | mailto:dmarc-agg@example.com |
ruf |
Forensic/failure report recipients | mailto:dmarc-fail@example.com |
adkim |
DKIM alignment mode | r (relaxed) or s (strict) |
aspf |
SPF alignment mode | r (relaxed) or s (strict) |
pct |
Percentage of messages to apply policy | 0-100 |
fo |
Failure reporting options | 0 (all fail), 1 (any fail), d (DKIM fail), s (SPF fail) |
ri |
Aggregate report interval (seconds) | Default 86400 (24h) |
DMARC Alignment:
DMARC PASS requires EITHER:
1. SPF pass AND SPF domain aligns with From: domain
- Relaxed: organizational domain match (sub.example.com aligns with example.com)
- Strict: exact domain match
OR
2. DKIM pass AND DKIM d= domain aligns with From: domain
- Relaxed: organizational domain match
- Strict: exact domain match
DMARC Forensic Checks:
# Query DMARC record
dig +short TXT _dmarc.example.com
# Check Authentication-Results for DMARC verdict
grep -i "dmarc=" email_headers.txt
# Common Authentication-Results DMARC line:
# dmarc=pass (p=reject dis=none) header.from=example.com
# dmarc=fail (p=none dis=none) header.from=example.com
DMARC Result Interpretation:
| Result | p= |
Action | Forensic Meaning |
|---|---|---|---|
pass |
any | Delivered | Sender authenticated — but could be compromised account |
fail |
none |
Delivered (monitoring) | Domain owner knows it fails but isn't enforcing yet |
fail |
quarantine |
Spam/junk | Message failed auth, quarantined |
fail |
reject |
Bounced | Message rejected — you may not even see it in logs |
3.4 ARC (Authenticated Received Chain)
Purpose: Preserves authentication results across indirect mail flows (forwarding, mailing lists) where SPF/DKIM break.
ARC Headers (RFC 8617, experimental):
ARC-Seal: i=1; a=rsa-sha256; cv=none; d=forwarder.com; s=arc-key; b=<sig>
ARC-Message-Signature: i=1; a=rsa-sha256; d=forwarder.com; s=arc-key; h=from:to:subject; bh=<hash>; b=<sig>
ARC-Authentication-Results: i=1; mx.forwarder.com;
dkim=pass header.d=original-sender.com;
spf=fail smtp.mailfrom=original-sender.com;
dmarc=fail header.from=original-sender.com
| Tag | Meaning |
|---|---|
i= |
Instance number (increments with each forwarder in chain) |
cv= |
Chain validation: none (first), pass, fail |
d= / s= |
Signing domain and selector of the forwarder |
ARC Forensic Significance:
- ARC
cv=passwithdmarc=failin ARC-Authentication-Results suggests legitimate forwarding - ARC
cv=failindicates the chain is broken — treat with suspicion - ARC is trusted based on the receiver's trust of the ARC signer (forwarder)
- Microsoft 365 and Gmail both honor ARC from trusted forwarders
3.5 Authentication-Results Header Deep Dive
Full example with all mechanisms:
Authentication-Results: mx.example.com;
spf=pass (sender SPF authorized) smtp.mailfrom=user@sender.com;
dkim=pass (2048-bit key) header.d=sender.com header.s=sel1 header.b=abc123;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=sender.com;
compauth=pass reason=100
Microsoft-specific compauth (Composite Authentication):
| Reason Code | Meaning |
|---|---|
000 |
Message failed explicit authentication (compauth=fail) |
001 |
Message failed implicit authentication |
1xx |
Message passed authentication |
2xx |
Soft-passed (sender authentication ambiguous) |
3xx |
Authentication not checked |
4xx/9xx |
Bypassed by policy/override |
4. Common Header Manipulation Techniques
4.1 Display Name Spoofing
The simplest and most common technique. No authentication fails because only the display name is faked.
From: "CEO John Smith" <attacker@evil.com>
- SPF: pass (for evil.com)
- DKIM: pass (signed by evil.com)
- DMARC: pass (for evil.com)
- Detection: Display name matches known internal contact, but domain doesn't
Variant — Unicode/Homoglyph Display Name:
From: "CEO J\u043ehn Smith" <attacker@evil.com>
Uses Cyrillic "o" (U+043E) instead of Latin "o" — visually identical.
4.2 Cousin/Lookalike Domain Spoofing
Attacker registers a domain visually similar to target.
From: ceo@exarnple.com ← "rn" looks like "m"
From: ceo@example.co ← TLD variation
From: ceo@examp1e.com ← "1" instead of "l"
From: ceo@example-corp.com ← Added suffix
- All authentication passes for the lookalike domain
- Detection: Domain similarity analysis, lookalike domain monitoring, Microsoft Defender impersonation protection
4.3 Reply-To Manipulation
Legitimate-looking From: but Reply-To: goes to attacker.
From: ceo@company.com
Reply-To: ceo.company@gmail.com
- If SPF/DKIM/DMARC are not enforced for company.com, the From may pass
- Detection: Check Reply-To against From domain; flag free email providers in Reply-To for business emails
4.4 Direct From: Header Spoofing
Attacker sends with a forged From: header from a server they control.
MAIL FROM: <attacker@evil.com> ← Envelope sender (checked by SPF)
From: ceo@company.com ← Display header (checked by DMARC alignment)
- SPF: pass for evil.com (envelope sender)
- DKIM: pass for evil.com (if they sign)
- DMARC: fail for company.com (if company.com has DMARC) — SPF domain (evil.com) doesn't align with From domain (company.com)
- Detection: DMARC enforcement is the primary defense
4.5 Null Sender / Empty MAIL FROM
MAIL FROM: <>
From: ceo@company.com
- SPF checks the HELO identity when MAIL FROM is null
- DMARC may still catch this if company.com publishes DMARC
- Used legitimately for DSN/bounce messages
4.6 Received Header Injection
Attacker adds fake Received: headers to make the message appear to originate from a different source.
Received: from internal-mail.company.com (internal-mail.company.com [10.0.0.5])
by fake-hop.company.com with ESMTP; Fri, 14 Mar 2026 10:00:00 +0000
- Detection: Headers below YOUR MTA's Received header are untrusted
- Look for internal RFC 1918 IPs appearing before the trust boundary
- Check for timestamp inconsistencies
4.7 Header Field Injection via SMTP
Exploiting SMTP DATA command to inject arbitrary headers:
Subject: Urgent Payment\r\nFrom: ceo@company.com\r\nReceived: from trusted.server.com
- Modern MTAs sanitize this, but legacy systems may be vulnerable
- Detection: Look for duplicate
From:headers; look for headers with unusual placement
4.8 Compromised Email Account
Hardest to detect — legitimate credentials, passes all authentication.
SPF: pass
DKIM: pass (signed by legitimate domain)
DMARC: pass
- Detection: Behavioral analysis required
- Unusual login location/time (Unified Audit Log)
- Inbox rules created to hide responses (forwarding rules, delete rules)
- Unusual recipients or unusual attachment types
- Message content analysis (urgency, wire transfer requests)
4.9 Via/Through Legitimate Services
Attacker uses legitimate email service (SendGrid, Mailchimp, AWS SES) to send phishing.
- SPF passes because the service is authorized
- DKIM may pass if the service signs with their domain
- Detection: Check
X-Mailer,X-SG-EID(SendGrid), service-specific headers; verify if the domain owner actually uses that service
5. Attachment Analysis Methodology
5.1 Triage Workflow
┌──────────────────┐
│ Extract Email │
│ Attachments │
└────────┬─────────┘
│
┌────────▼─────────┐
│ Hash Files │
│ (MD5/SHA256) │
└────────┬─────────┘
│
┌────────────┼────────────┐
│ │ │
┌────────▼───┐ ┌─────▼──────┐ ┌───▼────────────┐
│ VT/MalBazaar│ │ File Type │ │ Sandbox Submit │
│ Hash Lookup │ │ Analysis │ │ (ANY.RUN, etc) │
└────────┬───┘ └─────┬──────┘ └───┬────────────┘
│ │ │
└────────────┼────────────┘
│
┌────────▼─────────┐
│ Static Analysis │
│ (oletools, YARA) │
└────────┬─────────┘
│
┌────────▼─────────┐
│ Dynamic Analysis │
│ (Sandbox review) │
└──────────────────┘
5.2 Extracting Attachments
# Using munpack (from mpack package)
munpack -t email.eml
# Using Python email library
python3 -c "
import email, sys, os
with open('email.eml', 'rb') as f:
msg = email.message_from_binary_file(f)
for part in msg.walk():
fn = part.get_filename()
if fn:
with open(fn, 'wb') as out:
out.write(part.get_payload(decode=True))
print(f'Extracted: {fn}')
"
# Using emlanalyzer (from eml_analyzer)
# Web UI at localhost:8000 after Docker deployment
# Hash extracted files
sha256sum extracted_file.*
md5sum extracted_file.*
5.3 Office Document Analysis with oletools
oletools (https://github.com/decalage2/oletools) is the standard toolkit for Office document malware analysis. Install: pip install -U oletools[full]
oleid — Quick Triage
# Identify suspicious indicators
oleid suspicious_doc.docx
# Output includes risk levels for:
# - VBA Macros
# - XLM Macros
# - External Relationships
# - ObjectPool
# - Flash objects
olevba — VBA Macro Extraction and Analysis
# Extract and analyze VBA macros
olevba suspicious_doc.docm
# Decode obfuscated strings
olevba --decode suspicious_doc.docm
# Output in JSON for automated processing
olevba --json suspicious_doc.docm
# Key indicators in output:
# AutoExec — macro runs automatically (AutoOpen, Document_Open, Workbook_Open)
# Suspicious — Shell, WScript, PowerShell, CreateObject, download patterns
# IOC — URLs, IPs, filenames
# Hex Strings — obfuscated content
# Base64 — encoded payloads
# Dridex — specific obfuscation patterns
mraptor (MacroRaptor) — Malicious Macro Detection
# Quick malicious macro classification
mraptor suspicious_doc.docm
# Results: SUSPICIOUS or not
# Checks for: Auto-execution + Write to file/registry + Execute external commands
msodde — DDE/DDEAUTO Detection
# Extract DDE links (common infection vector, no macros needed)
msodde suspicious_doc.docx
# Also works on RTF and CSV files
msodde suspicious.rtf
rtfobj — RTF Embedded Object Extraction
# Extract embedded objects from RTF
rtfobj suspicious.rtf
# Extracts OLE objects, packages, embedded executables
# Common in exploit docs (CVE-2017-11882, CVE-2017-0199)
oleobj — OLE Embedded Object Extraction
# Extract embedded objects from OLE files
oleobj suspicious.doc
# Look for embedded PE files, scripts, or secondary documents
pyxswf — Flash/SWF Detection
# Detect embedded Flash objects
pyxswf suspicious.xls
# Legacy attack vector, still found in older malware
5.4 YARA Rules for Email Attachments
rule Suspicious_Office_Macro {
meta:
description = "Detects Office documents with suspicious VBA patterns"
author = "CIPHER"
date = "2026-03-14"
strings:
$auto1 = "AutoOpen" ascii nocase
$auto2 = "Document_Open" ascii nocase
$auto3 = "Workbook_Open" ascii nocase
$sus1 = "Shell" ascii nocase
$sus2 = "WScript" ascii nocase
$sus3 = "PowerShell" ascii nocase
$sus4 = "CreateObject" ascii nocase
$sus5 = "URLDownloadToFile" ascii nocase
$sus6 = "XMLHTTP" ascii nocase
$sus7 = "Environ" ascii nocase
condition:
(uint32(0) == 0xe011cfd0 or // OLE
uint32(0) == 0x04034b50) // ZIP (OOXML)
and any of ($auto*) and any of ($sus*)
}
rule Email_Attachment_Executable_In_Archive {
meta:
description = "Detects executables hidden in archive attachments"
strings:
$mz = { 4D 5A }
$pe = "PE\x00\x00"
condition:
(uint32(0) == 0x04034b50 or // ZIP
uint16(0) == 0x8b1f) // GZIP
and $mz and $pe
}
rule HTML_Smuggling_Email_Attachment {
meta:
description = "Detects HTML smuggling in email attachments"
strings:
$blob = "new Blob" ascii
$atob = "atob(" ascii
$download = "download" ascii
$b64 = /[A-Za-z0-9+\/]{100,}={0,2}/ ascii
condition:
filesize < 500KB and
all of them
}
5.5 Common Malicious Attachment Types
| Extension | Threat | Analysis Tool |
|---|---|---|
.docm, .xlsm, .pptm |
VBA macros | olevba, mraptor |
.doc, .xls (OLE) |
VBA macros, DDE, exploits | olevba, msodde, oleobj |
.docx, .xlsx (OOXML) |
DDE, external templates, remote OLE | msodde, zipdump |
.rtf |
Embedded OLE, exploits (CVE-2017-11882) | rtfobj |
.html, .htm |
HTML smuggling, credential phishing | Browser analysis, strings |
.iso, .img, .vhd |
MoTW bypass, embedded executables | Mount + static analysis |
.lnk |
Shortcut pointing to malicious command | LECmd, exiftool |
.one |
OneNote with embedded scripts | onenote-analyzer |
.pdf |
JavaScript, embedded files, phishing URLs | pdf-parser, pdfid |
.zip, .7z, .rar |
Password-protected archives with malware | Unarchive + analyze contents |
.js, .vbs, .wsf |
Script downloaders | Static analysis, sandbox |
6. URL Analysis in Emails
6.1 URL Extraction
# Extract URLs from EML file
grep -oP 'https?://[^\s"<>]+' email.eml | sort -u
# Extract URLs from HTML body (decode base64 first if needed)
python3 -c "
import email, re
from html import unescape
with open('email.eml', 'rb') as f:
msg = email.message_from_binary_file(f)
for part in msg.walk():
ct = part.get_content_type()
if ct in ('text/html', 'text/plain'):
body = part.get_payload(decode=True).decode('utf-8', errors='ignore')
body = unescape(body)
urls = re.findall(r'https?://[^\s\"<>\)]+', body)
for url in set(urls):
print(url)
"
# Extract href targets from HTML (catches obfuscated display text)
python3 -c "
from html.parser import HTMLParser
import email
class LinkExtractor(HTMLParser):
def handle_starttag(self, tag, attrs):
if tag == 'a':
for name, val in attrs:
if name == 'href' and val:
print(val)
with open('email.eml', 'rb') as f:
msg = email.message_from_binary_file(f)
for part in msg.walk():
if part.get_content_type() == 'text/html':
body = part.get_payload(decode=True).decode('utf-8', errors='ignore')
LinkExtractor().feed(body)
"
6.2 URL Analysis Checklist
□ Compare displayed text vs actual href (link text says "bank.com", href goes to "evil.com")
□ Check for URL shorteners (bit.ly, tinyurl, t.co) — expand before analysis
□ Check for tracking redirects (e.g., safelinks.protection.outlook.com, urldefense.proofpoint.com)
□ Decode percent-encoded characters (%20, %2F, etc.)
□ Check for punycode/IDN homograph domains (xn-- prefix)
□ Check for data: URIs (data:text/html;base64,...)
□ Look for @ in URL (user:pass@host — browser ignores before @)
□ Check domain age (whois) — newly registered domains are suspicious
□ Check against URL reputation services (VirusTotal, urlscan.io, PhishTank)
□ Check for IP-based URLs (http://192.168.1.1/payload)
□ Check for open redirects on legitimate domains
□ Identify credential harvesting pages (login forms, OAuth phishing)
6.3 URL Reputation and Intelligence
# urlscan.io submission
curl -X POST "https://urlscan.io/api/v1/scan/" \
-H "API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://suspicious-url.com", "visibility": "unlisted"}'
# VirusTotal URL scan
curl -X POST "https://www.virustotal.com/api/v3/urls" \
-H "x-apikey: YOUR_KEY" \
--form "url=https://suspicious-url.com"
# PhishTank check
curl "https://checkurl.phishtank.com/checkurl/" \
-d "url=https://suspicious-url.com&format=json&app_key=YOUR_KEY"
# Google Safe Browsing API
curl -X POST "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"threatInfo": {
"threatTypes": ["MALWARE", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE"],
"platformTypes": ["ANY_PLATFORM"],
"threatEntryTypes": ["URL"],
"threatEntries": [{"url": "https://suspicious-url.com"}]
}
}'
# Expand shortened URL without following
curl -sI "https://bit.ly/xxxxx" | grep -i "location:"
6.4 Common URL Obfuscation Techniques
| Technique | Example | Detection |
|---|---|---|
| URL encoding | %68%74%74%70 for http |
Decode percent-encoding |
| IP address (decimal) | http://3232235777/ (192.168.1.1) |
Convert decimal to dotted |
| IP address (hex) | http://0xC0A80101/ |
Convert hex to dotted |
| IP address (octal) | http://0300.0250.0001.0001/ |
Convert octal to dotted |
| Punycode/IDN | xn--exmple-cua.com |
Decode with idn --decode |
| URL shortener chain | bit.ly -> tinyurl -> evil.com |
Recursive expansion |
| Open redirect abuse | google.com/url?q=evil.com |
Check redirect parameter |
| Data URI | data:text/html;base64,PHN... |
Base64 decode |
| JavaScript redirect | javascript:window.location=... |
Deobfuscate JS |
| Credential in URL | http://legit.com@evil.com/ |
Parse actual destination host |
| Zero-width characters | example.com (ZWSP) |
Check for U+200B, U+200C, U+200D |
7. BEC Investigation Playbook
7.1 BEC Attack Taxonomy (MITRE ATT&CK)
| Technique ID | Technique | BEC Application |
|---|---|---|
| T1566.001 | Spearphishing Attachment | Malware delivery to gain access |
| T1566.002 | Spearphishing Link | Credential harvesting |
| T1534 | Internal Spearphishing | Compromised account sends internal phishing |
| T1114.002 | Remote Email Collection | Attacker reads victim's mailbox |
| T1078 | Valid Accounts | Using compromised credentials |
| T1098.005 | Device Registration | Registering attacker device for MFA |
| T1564.008 | Email Hiding Rules | Inbox rules to hide evidence |
| T1036 | Masquerading | Impersonating executives/vendors |
7.2 BEC Investigation Phases
Phase 1: Initial Triage (0-30 minutes)
□ Identify the suspicious email(s) — save original EML/MSG files
□ Determine BEC variant:
- CEO Fraud: executive impersonation requesting wire transfer
- Invoice Fraud: vendor impersonation with modified banking details
- Account Compromise: legitimate account used for internal phishing
- Attorney Impersonation: legal pressure + urgency
- Payroll Diversion: HR request to change direct deposit
- Data Theft: request for employee W-2/tax data or customer PII
□ Check if financial transaction has occurred
- If yes: IMMEDIATELY contact bank for recall/hold
- Wire recall window is typically 24-72 hours
□ Assess scope: how many users received the email?
□ Identify the attack vector (spoofed external, compromised internal, lookalike domain)
Phase 2: Email Forensics (30 minutes - 2 hours)
HEADER ANALYSIS:
□ Parse full email headers (bottom to top)
□ Extract originating IP and geolocate
□ Verify SPF/DKIM/DMARC results
□ Check Authentication-Results for compauth (M365)
□ Identify actual sending infrastructure
□ Check for Reply-To manipulation
□ Look for header anomalies (mismatched timezones, unusual X-headers)
CONTENT ANALYSIS:
□ Identify social engineering indicators:
- Urgency language ("immediately", "today", "critical")
- Authority pressure ("CEO", "Board", "Legal")
- Secrecy ("confidential", "don't discuss with anyone")
- Financial action requests (wire, ACH, gift cards, cryptocurrency)
- Changed banking details for known vendor
□ Extract and analyze all URLs (Section 6)
□ Extract and analyze all attachments (Section 5)
□ Check for brand impersonation in HTML/images
INFRASTRUCTURE ANALYSIS:
□ WHOIS on sending domain — registration date, registrar, registrant
□ DNS records for sending domain (MX, SPF, DKIM, DMARC)
□ Passive DNS on sending IP
□ Check sending IP against threat intelligence feeds
□ If lookalike domain: document character substitutions
□ Certificate Transparency logs for lookalike domains (crt.sh)
Phase 3: Account Compromise Assessment (if internal account suspected)
MICROSOFT 365:
□ Unified Audit Log search (Section 8)
□ Sign-in logs: unusual IPs, locations, devices, user agents
□ Check for inbox rules created (T1564.008):
- Search-UnifiedAuditLog -Operations "New-InboxRule","Set-InboxRule"
- Look for rules forwarding to external addresses
- Look for rules deleting/moving messages matching keywords
□ Check for email forwarding configured:
- Get-Mailbox -Identity user | FL ForwardingAddress,ForwardingSMTPAddress
- Get-InboxRule -Mailbox user | where {$_.ForwardTo -or $_.RedirectTo}
□ Check for OAuth app consent (consent phishing):
- Search-UnifiedAuditLog -Operations "Consent to application"
□ Check for MFA changes/additions
□ Check for mail sent from the compromised account
□ Check Mailbox Audit Log for MailItemsAccessed
GOOGLE WORKSPACE:
□ Admin Console > Reports > User Audit
□ Check login activity for suspicious sessions
□ Check for email forwarding and delegation
□ Check for app passwords created
□ Review OAuth token grants
□ Check filter/label rules for evidence hiding
Phase 4: Containment
IMMEDIATE ACTIONS:
□ Reset compromised account password
□ Revoke all active sessions and refresh tokens
□ Revoke suspicious OAuth app consents
□ Remove malicious inbox rules and forwarding
□ Enable MFA if not already enabled (or reset MFA)
□ Block attacker IPs/domains at email gateway
□ Block lookalike domains in DNS/firewall
□ Quarantine/delete malicious emails from all mailboxes
- M365: Search-Mailbox -SearchQuery "subject:..." -DeleteContent
- Or use Threat Explorer / Email Entity in Defender portal
NOTIFICATION:
□ Notify affected users (what to look for, what NOT to do)
□ Notify finance/accounting if wire transfer requested
□ Notify legal if PII/regulated data exposed
□ Notify law enforcement (IC3.gov for US, Action Fraud for UK)
□ Consider regulatory notification (GDPR Art. 33: 72-hour window)
Phase 5: Scope Assessment and Evidence Collection
EVIDENCE PRESERVATION:
□ Export original malicious email(s) as EML
□ Screenshot email as displayed to user
□ Export relevant audit logs (retain for investigation period)
□ Document timeline of events
□ Preserve email headers in original format (no reformatting)
□ If financial fraud: preserve all wire transfer instructions,
invoices, and communication chain
SCOPE ASSESSMENT:
□ Search all mailboxes for similar phishing emails
- By sender domain/address
- By subject line patterns
- By URL/attachment hash
□ Check if other accounts interacted with the email
□ Check if credentials were entered on phishing page
□ Review email gateway logs for related traffic
□ Check if data was exfiltrated
Phase 6: Remediation and Hardening
□ Implement/enforce DMARC p=reject for organizational domains
□ Enable anti-impersonation policies (M365 Defender)
□ Add external email warning banner
□ Review and tighten inbox rule creation permissions
□ Implement conditional access policies (block legacy auth, require MFA)
□ Deploy anti-phishing training for affected users
□ Add lookalike domains to block lists
□ Review financial approval workflows (dual authorization for wire transfers)
□ Update email gateway rules based on IOCs
□ Submit IOCs to threat intelligence sharing platforms (MISP, ISACs)
7.3 BEC IOC Collection Template
SENDER INFORMATION:
Display Name:
From Address:
Reply-To Address:
Envelope Sender (MAIL FROM):
Sending IP:
Sending IP Geolocation:
Sending IP ASN:
User-Agent / X-Mailer:
DOMAIN INTELLIGENCE:
Sending Domain:
Domain Registration Date:
Domain Registrar:
Domain Registrant (if available):
MX Records:
SPF Record:
DMARC Record:
SSL Certificate (if phishing site):
EMAIL IDENTIFIERS:
Message-ID:
Subject:
Date/Time (UTC):
Authentication Results (SPF/DKIM/DMARC):
PAYLOAD:
URLs (defanged):
Attachment Filenames:
Attachment Hashes (SHA256):
Attachment File Types:
INFRASTRUCTURE:
Phishing Page URL:
Phishing Page IP:
Phishing Page Hosting Provider:
C2 Domains (if malware):
C2 IPs (if malware):
FINANCIAL:
Beneficiary Name:
Beneficiary Bank:
Account Number:
Routing/SWIFT/IBAN:
Requested Amount:
Cryptocurrency Wallet (if applicable):
8. Microsoft 365 Email Forensics
8.1 Unified Audit Log (UAL) — Email-Related Events
Prerequisite: Audit logging must be enabled (on by default since 2019, but verify).
# Connect to Exchange Online PowerShell
Connect-ExchangeOnline -UserPrincipalName admin@company.com
# Verify audit logging is enabled
Get-AdminAuditLogConfig | FL UnifiedAuditLogIngestionEnabled
# Enable if disabled
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true
Key UAL Operations for Email Investigations
# Search for mailbox login activity
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "MailboxLogin" -UserIds "user@company.com" -ResultSize 5000
# Search for inbox rule creation/modification
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "New-InboxRule","Set-InboxRule","Enable-InboxRule" `
-UserIds "user@company.com"
# Search for email forwarding changes
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "Set-Mailbox" -UserIds "user@company.com" `
| Where-Object { $_.AuditData -like "*Forward*" }
# Search for mail items accessed (requires E5 or Audit Premium)
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "MailItemsAccessed" -UserIds "user@company.com" -ResultSize 5000
# Search for email send events
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "Send","SendAs","SendOnBehalf" -UserIds "user@company.com"
# Search for OAuth consent grants
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "Consent to application" -UserIds "user@company.com"
# Search for delegate access changes
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-Operations "Add-MailboxPermission","Add-RecipientPermission" `
-UserIds "user@company.com"
# Export results for analysis
Search-UnifiedAuditLog -StartDate "2026-03-01" -EndDate "2026-03-14" `
-UserIds "user@company.com" -ResultSize 5000 `
| Export-Csv -Path "audit_log_export.csv" -NoTypeInformation
| Operation | What It Captures |
|---|---|
MailboxLogin |
Mailbox access (IP, client, user agent) |
MailItemsAccessed |
Individual mail items read (E5/Audit Premium) |
New-InboxRule |
Inbox rule creation |
Set-InboxRule |
Inbox rule modification |
UpdateInboxRules |
Client-side rule changes (Outlook) |
Set-Mailbox |
Mailbox property changes (forwarding, delegation) |
Send / SendAs / SendOnBehalf |
Email sending |
MoveToDeletedItems / SoftDelete / HardDelete |
Email deletion |
Consent to application |
OAuth app consent |
Add-MailboxPermission |
Delegate access granted |
8.2 Message Trace
# Basic message trace (last 10 days)
Get-MessageTrace -SenderAddress "attacker@evil.com" `
-StartDate "2026-03-04" -EndDate "2026-03-14"
# Trace by recipient
Get-MessageTrace -RecipientAddress "victim@company.com" `
-StartDate "2026-03-04" -EndDate "2026-03-14"
# Trace by Message-ID
Get-MessageTrace -MessageId "<message-id@domain.com>" `
-StartDate "2026-03-04" -EndDate "2026-03-14"
# Detailed message trace (for messages older than 10 days, up to 90 days)
Start-HistoricalSearch -ReportTitle "BEC Investigation" `
-StartDate "2026-01-01" -EndDate "2026-03-14" `
-ReportType MessageTrace `
-SenderAddress "attacker@evil.com"
# Get detailed trace for specific message
Get-MessageTraceDetail -MessageTraceId <trace-id> -RecipientAddress "victim@company.com"
8.3 Microsoft Defender for Office 365
Threat Explorer Queries
# Access: security.microsoft.com > Email & collaboration > Explorer
# Search by sender
Sender: attacker@evil.com
Date: Last 30 days
# Search by subject
Subject: "Urgent Wire Transfer"
# Search phishing verdicts
Detection technology: URL detonation, File detonation, Impersonation domain
Delivery action: Delivered
# URL clicks tracking
View: URL clicks
Filter by user or URL
# Campaign view
View: Campaigns
Automated clustering of related phishing
Email Entity Investigation
# In Defender portal, investigate specific email:
# 1. Get Message-ID from headers
# 2. Explorer > search by Message-ID
# 3. Click email to open Email Entity page
#
# Email Entity shows:
# - Full headers
# - Authentication results
# - Delivery details (action, location, original delivery location)
# - URLs and their detonation results
# - Attachments and their detonation results
# - Impersonation detection details
# - Related alerts and incidents
8.4 Searching and Purging Malicious Emails
# Search all mailboxes for malicious email (New Compliance Search)
New-ComplianceSearch -Name "BEC_Purge_2026_03" `
-ExchangeLocation All `
-ContentMatchQuery 'from:attacker@evil.com AND subject:"Urgent Payment"'
# Start the search
Start-ComplianceSearch -Identity "BEC_Purge_2026_03"
# Preview results
Get-ComplianceSearch -Identity "BEC_Purge_2026_03" | FL Items,Size
# Purge (soft delete — recoverable)
New-ComplianceSearchAction -SearchName "BEC_Purge_2026_03" -Purge -PurgeType SoftDelete
# Purge (hard delete — permanent, requires approval)
New-ComplianceSearchAction -SearchName "BEC_Purge_2026_03" -Purge -PurgeType HardDelete
8.5 Checking for Persistence (Compromised Account)
# Check inbox rules
Get-InboxRule -Mailbox "victim@company.com" | FL Name,Description,Enabled,
ForwardTo,ForwardAsAttachmentTo,RedirectTo,DeleteMessage,MoveToFolder
# Check mailbox forwarding
Get-Mailbox -Identity "victim@company.com" | FL ForwardingAddress,
ForwardingSMTPAddress,DeliverToMailboxAndForward
# Check mailbox delegates
Get-MailboxPermission -Identity "victim@company.com" |
Where-Object { $_.IsInherited -eq $false -and $_.User -ne "NT AUTHORITY\SELF" }
# Check send-as permissions
Get-RecipientPermission -Identity "victim@company.com"
# Check transport rules (org-wide)
Get-TransportRule | FL Name,State,From,SentTo,RedirectMessageTo
# Check mail flow connectors (org-wide)
Get-InboundConnector | FL Name,Enabled,SenderDomains
Get-OutboundConnector | FL Name,Enabled,RecipientDomains
# Check OAuth app permissions (via Graph API)
# GET https://graph.microsoft.com/v1.0/users/{id}/oauth2PermissionGrants
# GET https://graph.microsoft.com/v1.0/servicePrincipals/{id}/appRoleAssignments
# Check registered devices/auth methods
# Azure AD Portal > Users > user > Authentication methods
# Azure AD Portal > Users > user > Devices
8.6 Microsoft 365 Anti-Phishing Features
Based on Microsoft Defender for Office 365 [CONFIRMED]:
EOP (All Cloud Mailboxes):
- Spoof intelligence: Detects spoofed senders from internal and external domains; manual allow/block
- Anti-phishing policies: SPF/DKIM/DMARC enforcement, unauthenticated sender indicators in Outlook
- DMARC policy honoring: Respects
p=quarantineandp=rejectpolicies - Implicit email authentication: Sender reputation, history, behavioral analysis beyond SPF/DKIM/DMARC
- Tenant Allow/Block List: Manual spoofed sender allow/block entries
Defender for Office 365 (E5/P2):
- Impersonation protection: Protects specific users and domains from impersonation (display name + domain similarity)
- Mailbox intelligence: Learns user communication patterns, flags anomalous senders
- Campaign Views: ML-based clustering of coordinated phishing campaigns
- Attack simulation training: Simulated phishing for user training
- Safe Links: Real-time URL detonation and rewriting
- Safe Attachments: Sandbox detonation of attachments
- Automated Investigation and Response (AIR): Automated threat investigation and remediation
9. Google Workspace Email Forensics
9.1 Admin Console Investigation Tools
# Access: admin.google.com > Security > Investigation Tool
# (Requires Enterprise/Education Plus license)
# Search by sender
Data source: Gmail log events
Condition: Sender is attacker@evil.com
Date range: Last 30 days
# Search by message ID
Data source: Gmail log events
Condition: Message ID is <message-id@domain>
# Search by subject
Data source: Gmail log events
Condition: Subject contains "Wire Transfer"
9.2 Gmail Log Events (Admin Console > Reports)
Key log fields:
| Field | Purpose |
|---|---|
actor.email |
User whose mailbox is affected |
event.name |
Action type (receive, send, view) |
source_ip |
IP address of action |
message_id |
RFC 5322 Message-ID |
subject |
Email subject |
is_spam |
Spam classification |
destination |
Delivery destination |
smtp_reply_code |
Delivery status |
9.3 Google Workspace Security Investigation
# Login audit events
Admin Console > Reports > Audit and investigation > User log events
Key fields to review:
- Login type (normal, suspicious, via app password)
- IP address and geolocation
- Device information
- Login challenge issued (MFA)
# Email audit
Admin Console > Reports > Audit and investigation > Gmail log events
# Check for forwarding rules
Admin Console > Apps > Google Workspace > Gmail > Routing
Per-user: Admin Console > Directory > Users > user > Gmail settings
# Check for OAuth tokens
Admin Console > Security > API controls > App access control
Per-user: Admin Console > Directory > Users > user > Security > Connected apps
9.4 Google Vault (eDiscovery and Preservation)
# Preserve mailbox for investigation
Google Vault > Matters > Create Matter
> Add Hold > Gmail > Specific users
> Date range + search terms
# Search and export
Google Vault > Matters > [matter] > Search
> Service: Mail
> Search: from:attacker@evil.com OR subject:"wire transfer"
> Export: MBOX format (includes full headers)
# Export includes:
# - Original messages in MBOX format
# - Metadata CSV
# - Full email headers preserved
9.5 Google Workspace Email Deletion/Quarantine
# Delete emails from user mailboxes (Investigation Tool)
Admin Console > Security > Investigation Tool
> Search for malicious emails
> Select messages
> Action: Delete messages
# Bulk actions via GAM (Google Apps Manager CLI)
# Delete specific message
gam user victim@company.com delete message query "from:attacker@evil.com subject:wire"
# Search across org
gam all users print messages query "from:attacker@evil.com" | tee search_results.csv
9.6 Checking for Persistence (Compromised Account — Google)
# Check email forwarding
Admin Console > Directory > Users > [user] > User information > Email forwarding
# Check email delegates
Admin Console > Directory > Users > [user] > Email delegation
# Check via GAM
gam user victim@company.com show forwards
gam user victim@company.com show delegates
gam user victim@company.com show filters
# Check for suspicious filters (auto-delete, auto-archive, auto-forward)
# Filters that match keywords like "invoice", "payment", "security" and
# skip inbox / mark as read / auto-archive are classic BEC persistence
# Revoke OAuth tokens
gam user victim@company.com deprovision
# Revoke app passwords
gam user victim@company.com update isenforcedin2sv true
# Force sign-out of all sessions
gam user victim@company.com signout
10. Email as Evidence
10.1 Legal Admissibility Considerations
Email evidence must meet standards for authenticity, integrity, and chain of custody to be admissible. Key frameworks:
| Jurisdiction | Standard | Key Requirement |
|---|---|---|
| US Federal | FRE 901(b)(4) | Distinctive characteristics, content, context |
| US Federal | FRE 902(14) | Self-authentication for certified electronic records |
| EU | eIDAS Regulation | Electronic documents admissible, weight varies |
| UK | Civil Evidence Act 1995 | Hearsay admissible with notice |
| General | ISO/IEC 27037 | Guidelines for digital evidence identification, collection, acquisition |
10.2 Evidence Preservation Protocol
STEP 1: DOCUMENT THE SCENE
□ Screenshot the email as displayed to the user (full screen including headers)
□ Record date/time of preservation
□ Record who is performing preservation
□ Record the system/client used for viewing
STEP 2: PRESERVE ORIGINAL FORMAT
□ Export as EML (plaintext with full headers) — PREFERRED
□ Export as MSG (Outlook proprietary format) — acceptable
□ Do NOT rely on PDF printouts alone (headers may be incomplete)
□ Do NOT forward the email (modifies headers, adds forwarding artifacts)
Outlook:
- File > Save As > Outlook Message Format (.msg)
- Or drag email to desktop (creates .msg)
- For EML: File > Save As > Text Only, then manually save raw source
Gmail:
- Open email > Three dots > Show original > Download Original (.eml)
Thunderbird:
- File > Save As > File (.eml)
M365 (Admin):
- Compliance Search > Export results
- eDiscovery > Export (PST format)
STEP 3: GENERATE CRYPTOGRAPHIC HASH
□ SHA-256 hash of the EML/MSG file immediately after export
□ Record hash value in evidence log
□ Hash BEFORE any analysis tools touch the file
sha256sum evidence_email.eml > evidence_email.sha256
STEP 4: PRESERVE HEADERS SEPARATELY
□ Extract full headers to separate text file
□ Hash the header file
□ Headers are the most forensically valuable component
STEP 5: CHAIN OF CUSTODY LOG
□ Date/time of each action
□ Who performed the action
□ What action was taken
□ Hash verification at each transfer
10.3 Evidence Integrity Verification
# Generate evidence hashes
sha256sum evidence_email.eml > evidence.sha256
sha256sum evidence_email.msg >> evidence.sha256
# Verify on subsequent access
sha256sum -c evidence.sha256
# Sign evidence hash file with GPG
gpg --detach-sign --armor evidence.sha256
# Verify signature
gpg --verify evidence.sha256.asc evidence.sha256
# Timestamp proof (RFC 3161 timestamp)
openssl ts -query -data evidence_email.eml -no_nonce -sha256 -out evidence.tsq
# Submit to timestamp authority
curl -H "Content-Type: application/timestamp-query" \
--data-binary @evidence.tsq \
https://freetsa.org/tsr > evidence.tsr
10.4 Email Header Authentication as Evidence
When presenting email evidence, the authentication results provide corroboration:
AUTHENTICATION EVIDENCE HIERARCHY:
1. DKIM signature verification (strongest)
- Proves: message body and signed headers were not modified after signing
- Limitation: does not prove who sent it, only which domain signed it
- Verification: re-verify DKIM signature against the domain's public key
(note: key may be rotated; record current key at time of investigation)
2. SPF verification
- Proves: sending IP was authorized by the domain owner
- Limitation: only covers MAIL FROM, may not match display From
3. DMARC alignment
- Proves: SPF or DKIM domain aligns with the From: header domain
- Provides strongest assurance of sender identity
4. Received headers (from your MTA)
- Proves: which server delivered the message and when
- Only headers added by YOUR infrastructure are trustworthy
5. Server-side logs (strongest corroboration)
- SMTP transaction logs on receiving MTA
- Message trace / audit logs from email platform
- These are independent records controlled by your organization
10.5 Common Evidence Challenges
| Challenge | Mitigation |
|---|---|
| "Email was fabricated" | DKIM signature verification + server logs + message trace |
| "Headers were modified" | Original EML with hash + DKIM verification |
| "Timestamp is wrong" | Cross-reference with MTA logs and multiple Received headers |
| "Someone else had access" | Login audit logs + MFA records + IP correlation |
| "I didn't send that email" | Audit log (MailItemsAccessed, Send) + IP address + device correlation |
| "Forwarded email altered" | Compare Message-ID and content hash with original |
11. Tools Reference
11.1 Email Analysis Tools
| Tool | Purpose | Install / Access |
|---|---|---|
| eml_analyzer | Web-based EML analysis: headers, IOCs, attachments, SpamAssassin | Docker: docker-compose up (github.com/ninoseki/eml_analyzer) |
| oletools | Office document malware analysis suite | pip install -U oletools[full] (github.com/decalage2/oletools) |
| MXToolbox Header Analyzer | Online email header parsing and hop analysis | mxtoolbox.com/EmailHeaders.aspx |
| Google Admin Toolbox | Email header analysis | toolbox.googleapps.com/apps/messageheader |
| msgconvert | Convert MSG to EML format | apt install libemail-outlook-message-perl |
| munpack | Extract MIME attachments | apt install mpack |
| dkimpy | DKIM signature verification | pip install dkimpy |
| spfquery | SPF record validation | apt install spfquery |
| SpamAssassin | Email spam/phishing scoring | apt install spamassassin |
| PhishTool | Commercial phishing analysis platform | phishtool.com |
11.2 Attachment and Payload Analysis Tools
| Tool | Purpose | Install |
|---|---|---|
| olevba | VBA macro extraction and analysis | Part of oletools |
| mraptor | Malicious macro detection | Part of oletools |
| msodde | DDE/DDEAUTO link detection | Part of oletools |
| rtfobj | RTF embedded object extraction | Part of oletools |
| oleobj | OLE embedded object extraction | Part of oletools |
| oleid | OLE file triage and risk assessment | Part of oletools |
| pdfid | PDF structure analysis | pip install pdfid |
| pdf-parser | PDF object and stream analysis | pip install pdf-parser |
| YARA | Pattern-matching for malware classification | apt install yara |
| exiftool | Metadata extraction from files | apt install exiftool |
| file / libmagic | File type identification | Built into most Linux distros |
| CyberChef | Data decoding and transformation | gchq.github.io/CyberChef |
11.3 URL and Domain Intelligence Tools
| Tool | Purpose | Access |
|---|---|---|
| urlscan.io | URL scanning and screenshot capture | urlscan.io (API available) |
| VirusTotal | Multi-engine URL/file scanning | virustotal.com (API available) |
| PhishTank | Community phishing URL database | phishtank.org |
| URLhaus | Malware URL database | urlhaus.abuse.ch |
| whois | Domain registration lookup | whois domain.com |
| crt.sh | Certificate Transparency log search | crt.sh |
| dnstwist | Domain permutation and lookalike detection | pip install dnstwist |
| Shodan | IP and host intelligence | shodan.io |
| SecurityTrails | Historical DNS and WHOIS | securitytrails.com |
| RiskIQ / PassiveTotal | Passive DNS and threat infrastructure | community.riskiq.com |
11.4 Command-Line Quick Reference
# === HEADER ANALYSIS ===
# View raw headers
formail -X "" < email.eml | head -100
# Extract specific header
formail -x "Authentication-Results" < email.eml
# Parse Received chain
grep -i "^Received:" email.eml
# Extract all IPs from headers
grep -oP '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' email.eml | sort -u
# === AUTHENTICATION CHECKS ===
# Verify DKIM
dkimverify < email.eml
# Check SPF
dig +short TXT example.com | grep "v=spf1"
# Check DMARC
dig +short TXT _dmarc.example.com
# Check DKIM selector
dig +short TXT selector._domainkey.example.com
# Check MX records
dig +short MX example.com
# === ATTACHMENT HANDLING ===
# Extract attachments
munpack email.eml
# Hash all extracted files
find . -maxdepth 1 -type f -newer email.eml -exec sha256sum {} \;
# Quick triage Office file
oleid suspicious.docx
# Extract macros
olevba suspicious.docm
# Check for DDE
msodde suspicious.docx
# === URL ANALYSIS ===
# Extract URLs
grep -oP 'https?://[^\s"<>]+' email.eml | sort -u
# Check domain age
whois suspicious-domain.com | grep -i "creation"
# Generate domain permutations for lookalike detection
dnstwist example.com
# Expand shortened URL
curl -sIL "https://bit.ly/xxx" 2>&1 | grep -i "^location:"
# === REPUTATION CHECKS ===
# Check IP reputation (AbuseIPDB)
curl -s "https://api.abuseipdb.com/api/v2/check?ipAddress=1.2.3.4" \
-H "Key: YOUR_KEY" -H "Accept: application/json"
# Check domain on VirusTotal
curl -s "https://www.virustotal.com/api/v3/domains/suspicious.com" \
-H "x-apikey: YOUR_KEY"
# === M365 POWERSHELL ===
# Quick compromised account check
Connect-ExchangeOnline
Get-InboxRule -Mailbox user@company.com | FL Name,ForwardTo,RedirectTo,DeleteMessage
Get-Mailbox user@company.com | FL ForwardingAddress,ForwardingSMTPAddress
Search-UnifiedAuditLog -UserIds user@company.com -Operations "New-InboxRule" -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date)
Appendix A: Email Authentication Decision Tree
┌─────────────────────┐
│ Received Email │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Check SPF │
│ (MAIL FROM domain) │
└──────────┬──────────┘
┌────────┼────────┐
pass fail none
│ │ │
┌─▼──────▼─────────▼─┐
│ Check DKIM │
│ (d= domain) │
└──────────┬──────────┘
┌────────┼────────┐
pass fail none
│ │ │
┌─▼──────▼─────────▼──┐
│ Check DMARC │
│ Alignment │
│ (From: vs SPF/DKIM) │
└──────────┬────────────┘
┌────────┼────────┐
pass fail none
│ │ │
│ ┌─▼────┐ │
│ │Policy│ │
│ │p=? │ │
│ └─┬────┘ │
│ ┌───┼───┐ │
│ none quar rej │
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
DELIVER JUNK REJECT DELIVER
(monitor) (no policy)
Appendix B: Phishing Indicators Scoring Matrix
Use this scoring matrix to quickly assess phishing likelihood:
| Indicator | Points | Notes |
|---|---|---|
| SPF fail | +3 | Sender IP not authorized |
| DKIM fail | +3 | Message modified or forged sig |
| DMARC fail | +4 | Strongest authentication failure |
| Display name spoofs known contact | +3 | Compare against GAL/directory |
| Reply-To differs from From | +2 | Classic BEC indicator |
| Reply-To uses free email service | +3 | Business email from Gmail/Yahoo |
| Domain registered < 30 days | +4 | Newly registered for campaign |
| Lookalike domain (edit distance <= 2) | +4 | Typosquatting/homoglyph |
| Urgency language | +2 | "Immediately", "ASAP", "today" |
| Financial action requested | +3 | Wire, gift card, crypto, payment |
| Request for secrecy | +2 | "Don't tell anyone", "confidential" |
| Unusual sending time for sender | +1 | 3 AM from sender normally in US EST |
| Embedded URLs to non-org domains | +2 | Links not matching sender domain |
| URL uses IP address instead of domain | +3 | IP-based URLs almost always malicious |
| Attachment with macros | +3 | .docm, .xlsm, or OLE with VBA |
| Password-protected archive attachment | +3 | Bypasses scanning |
| HTML smuggling attachment | +4 | Advanced delivery technique |
| First-time sender | +1 | No prior communication history |
| Geolocation mismatch (IP vs claimed sender) | +2 | Sender claims US, IP in Nigeria |
| Missing or minimal SMTP TLS | +1 | with ESMTP instead of ESMTPS |
Scoring: 0-3 Low | 4-7 Medium | 8-12 High | 13+ Critical
CIPHER Training Module — Email Forensics Deep Reference Generated: 2026-03-14 Sources: IANA Message Headers Registry (RFC 5322bis), Microsoft Defender for Office 365 documentation, oletools (decalage2), eml_analyzer (ninoseki), MXToolbox, RFC 5322, RFC 7208, RFC 6376, RFC 7489, RFC 8601, RFC 8617