Analyzing Phishing Emails
An email is a stack of claims — who sent it, where it came from, that its
links are safe — and phishing analysis is checking each claim against evidence
the sender could not forge: the Received chain, the authentication results,
and the true destination of every link and attachment. The From header is a
display, not a fact. Anyone can type any address into it; your job is to find
the evidence that agrees or disagrees.
When to Use
- A user reports a suspicious email and you need a verdict and IOCs
- You have a
.eml or .msg file to analyze offline
- You are handed raw headers and asked whether a message is spoofed
- A message carries a link or attachment that needs safe triage
- A business email compromise, invoice-fraud, or vendor-impersonation case
- Confirming whether a domain or brand was spoofed against your users
When NOT to Use
- You extracted an attachment and need to detonate it — come here first to
safely extract and defang it, then hand the payload to
analyzing-malware
- The phish already succeeded and you are chasing the mailbox/OAuth
compromise in the tenant — use
investigating-m365-entra
- You are building the phishing campaign, not analyzing one — use
performing-social-engineering
- The broader incident the phish kicked off — use
responding-to-incidents
- Analyzing the callback traffic from a detonated payload — use
analyzing-network-traffic
Safe Handling — Do This First
Treat every reported message as live. The failure mode is not misreading a
header; it is clicking a link in a production mail client or double-clicking
an attachment on your own host.
- Never open the message in a live client. Attacker-controlled remote images
fire a read beacon; one click on a link authenticates you to their harvester.
- Work from the raw source only — the
.eml/.msg, not a forwarded copy.
Forwarding rewrites headers and strips the evidence you need.
- Defang every indicator before it touches a report, ticket, or chat:
http → hxxp, . → [.], @ → [at]. So http://evil.com/login
becomes hxxp://evil[.]com/login. Defanging prevents an accidental click
downstream and stops link-preview bots from detonating it for you.
- Extract and detonate only in an isolated VM with no host sharing and
simulated or monitored egress — see
analyzing-malware for the build.
Getting the Raw Message
The visible email is a rendering. You need the source with all headers.
- Outlook/Exchange: save as
.msg, or in OWA use "View message source".
- Gmail: "Show original" → Download Original gives a
.eml.
.msg → readable: msgconvert sample.msg produces a .eml (RFC822).
- Inspect structure:
emldump.py sample.eml lists MIME parts and indices;
emldump.py -s 4 -d sample.eml dumps part 4 (an attachment) without opening
it. A .msg is an OLE compound file — oledump.py (DidierStevens) lists its
streams.
- View full headers: read the top block of the raw file directly, or paste
into Message Header Analyzer (MHA) / Google's
mha / MXToolbox Header
Analyzer for a parsed hop table.
Keep the original file hashed and untouched; work on copies.
The Received Chain
The Received: headers are added by each mail server the message passes
through, newest at the top. Read them bottom-up: the bottom-most
Received is the originating server — the earliest, least-forgeable hop.
Received: from mail.contoso.com (mail.contoso.com [203.0.113.9])
by mx.recipient.com ... ; Tue, 21 Jul 2026 09:14:02 +0000 <- final hop
Received: from smtp.sketchy-vps.ru ([185.220.101.5])
by mail.contoso.com ... ; Tue, 21 Jul 2026 09:13:58 +0000 <- origin
- Trace the originating IP: the bottom hop's
[bracketed IP]. Geolocate
and WHOIS it (whois 185.220.101.5), check reputation, and reconcile it
against the claimed sender. A "From: ceo@contoso.com" that originates on a
Russian VPS is your finding.
- Spot forged hops: attackers prepend fake
Received lines to fabricate a
reputable origin. Only hops added by servers you trust are reliable — trust
breaks at the first server outside your control. A hop that references a
server not present in the next hop's by is invented.
- Timezone and hop-time anomalies: hop timestamps should increase upward by
seconds. Negative deltas, multi-hour jumps, or a mix of implausible
timezones indicate forgery or relay through odd infrastructure.
- Reconcile with the claimed sender: the origin domain, its PTR/rDNS, and
the
From domain should tell one coherent story. They usually do not in a
phish.
Authentication Results
SPF, DKIM, and DMARC are the forgery-resistant checks. The receiving server
records them in Authentication-Results. Read it, and re-verify rather than
trusting a summary.
Authentication-Results: mx.recipient.com;
spf=pass (sender IP is 185.220.101.5) smtp.mailfrom=bounce.sketchy-vps.ru;
dkim=pass header.d=sketchy-vps.ru header.s=selector1;
dmarc=fail (p=reject sp=reject dis=none) header.from=contoso.com
- SPF authenticates the envelope sender (
Return-Path / smtp.mailfrom
/ MAIL FROM), not the visible From. Values: pass (IP is authorized
for the envelope domain), fail (hard -all reject), softfail
(~all, suspicious but delivered), neutral/none (no policy). Check the
domain's record: dig txt contoso.com and read the v=spf1 ... string.
- DKIM is a cryptographic signature over selected headers and the body.
dkim=pass proves the message was signed by the key at d='s selector and
not modified. The load-bearing question is alignment: does header.d=
match the From domain? A valid signature from d=mailer-xyz.com on a
message claiming From: contoso.com is not contoso. Re-verify with
dkimverify < sample.eml (dkimpy) and fetch the key via
dig txt selector1._domainkey.contoso.com.
- DMARC ties SPF/DKIM to the visible
From via alignment and applies the
domain owner's policy. dmarc=pass requires SPF or DKIM to pass AND be
aligned with header.from. Read the policy: dig txt _dmarc.contoso.com
→ v=DMARC1; p=reject; .... p=reject/quarantine with dmarc=fail means
the owner told you to distrust it.
- ARC (
ARC-Seal/ARC-Authentication-Results) preserves upstream auth
results across forwarders that would otherwise break SPF/DKIM. Use it to see
how auth looked before a mailing list or gateway relayed the message.
- Envelope vs header From:
Return-Path/envelope-from is what bounces go to
and what SPF checks; the header From: is what the user sees. Phishers make
them differ — a benign-looking From with a throwaway envelope domain that
happens to pass SPF is the classic pattern.
Display-Name and Lookalike Spoofing
Much phishing passes authentication because it comes from a real mailbox on a
lookalike domain. The auth checks pass for that domain; the deception is
visual.
- Display-name spoofing:
From: "IT Helpdesk" <random@gmail.com>. The name
is a free-text label; read the actual address.
- Cousin / lookalike domains:
cont0so.com, contoso-support.com,
contoso.co. Diff against the real domain character by character.
- Homoglyph / IDN: Unicode characters that render like ASCII (Cyrillic
а
for Latin a). Punycode-encoded domains appear in headers as
xn-- — e.g. xn--cntoso-.... Decode with idn /
python3 -c "print('xn--80ak6aa92e.com'.encode().decode('idna'))" and
compare the rendered form.
- Reply-To mismatch:
From: ceo@contoso.com but
Reply-To: ceo.contoso@gmail.com. The reply silently goes to the attacker —
a hallmark of BEC.
- BEC with no payload: pure text asking for a wire transfer, gift cards, or
W-2 data. No link, no attachment, nothing to sandbox. The signal is entirely
in the headers (Reply-To, origin, auth) and the pretext.
Header Forensics
Message-ID sanity: format is <unique@sending-domain>. The domain
should match the sending infrastructure. A Message-ID domain that disagrees
with the origin, or a malformed/duplicated ID, suggests a spoofing tool.
X-Originating-IP: some webmail stamps the true client IP here — pivot on
it, but note it is client-suppliable and can be forged.
X-Mailer / User-Agent: reveals the sending client. Bulk-phish kits and
scripts (PHPMailer, Python, custom mailers) look nothing like Outlook or
the claimed sender's normal stack.
- Mailer fingerprints: legitimate bulk senders (SendGrid, Amazon SES,
Mailchimp) add characteristic
X- headers and Received paths. Their
presence on a "personal" note from your CEO is a contradiction.
URL Analysis
Every link is a claim about where it goes. Resolve it without visiting it.
- Unwrap redirects and shorteners: expand
bit.ly/t.co with
curl -sI hxxp://bit[.]ly/xyz (read Location:, do not follow) or a
preview service. Chase every hop to the real landing page.
- Decode wrapper rewrites — the real URL is inside the wrapper:
- Microsoft SafeLinks:
https://*.safelinks.protection.outlook.com/?url=<encoded>&...
— URL-decode the url= parameter.
- Proofpoint URLDefense:
https://urldefense.com/v3/__<encoded>__;... —
decode with the published urldefense decoder (v2/v3 schemes differ).
These wrappers hide the destination; always extract the original.
- Quishing (QR-code phishing): the payload is an image, not a link. Extract
the image part (
emldump.py -s N -d), then decode:
zbarimg qr.png or python3 -c "from PIL import Image; import pyzbar.pyzbar as z; print(z.decode(Image.open('qr.png')))". Analyze the
decoded URL like any other.
- Intent — harvest vs delivery: a link to a cloned login page (Microsoft,
DocuSign, a bank) is credential harvesting; a link that downloads a file
is malware delivery. They need different responses.
- Detonate safely: submit the URL to urlscan.io (use unlisted/private
scans for targeted phish so you don't tip the actor) or a sandbox, and pull
the real landing page, screenshot, and served content. Extract the landing
page and any kit files for the IOC set.
Attachment Analysis
Identify and defang before anything executes.
- Hash and identify:
sha256sum att.ext && file att.ext. Extract with
emldump.py -s N -d sample.eml > att.ext — never by double-clicking.
- Common delivery wrappers: HTML smuggling (a
.html that assembles a
payload in-browser via a Blob), ISO/IMG/VHD (mount bypasses MOTW), LNK
shortcuts, OneNote (.one) with embedded scripts, and password-protected
archives (password in the email body defeats gateway scanning).
- Documents/macros:
exiftool att.docx for metadata and authoring
fingerprints; oleid att.xls and olevba --deobf att.xls /
oledump.py att.doc for macros; rtfobj att.rtf for embedded objects.
- Once identified, hand the live payload to
analyzing-malware for
sandboxed detonation, unpacking, and C2 extraction. This skill's job is safe
extraction and triage, not detonation.
Pulling and Packaging IOCs
Extract a clean, defanged indicator set for blocking and hunting:
- Sender infrastructure: originating IP, envelope-from domain,
From/cousin
domains, Reply-To, Message-ID domain, mailer fingerprints.
- URLs: the wrapped and unwrapped forms, final landing page, shortener
chain, and any kit hostnames from urlscan.
- Hashes: SHA-256 of every attachment and of decoded/downloaded payloads.
- Hunting selectors: subject lines, sender display names, and body
fingerprints to search the mail gateway and other mailboxes.
Package these for producing-threat-intelligence when the phish is part of a
tracked campaign, and for reporting-security-findings for the writeup.
Scoping the Campaign
One report is rarely the only recipient. Find the rest before you close.
- M365:
Search-UnifiedAuditLog and Content Search / New-ComplianceSearch
for the subject, sender, and URL across all mailboxes; hard-delete or
quarantine matches via Get-QuarantineMessage / eDiscovery purge.
- Mail gateway (Proofpoint, Mimecast, Defender for O365): search message
trace / Threat Explorer for the sender domain, URL, and attachment hash to
enumerate every recipient and whether anyone clicked or replied.
- If any recipient interacted, the phish may have succeeded — pivot to
investigating-m365-entra for tenant-side hunting (sign-ins, inbox rules,
OAuth grants) and to responding-to-incidents for the broader response.
Rationalizations to Reject
- "SPF passed, so it's legitimate." SPF authenticates the envelope domain,
not the visible
From. A passing SPF on a lookalike or throwaway envelope
domain is exactly what a competent phish shows. Check DMARC alignment.
- "DKIM is valid, so it's from them." A valid signature only proves the
d=
domain signed it. If d= isn't aligned with the From domain, it's signed
by someone else. Alignment is the question, not signature validity.
- "No attachment or link, so it's harmless." BEC and payment-fraud phish
carry neither — the weapon is the pretext and the Reply-To. Read the headers.
- "DMARC failed but it was delivered, so it's fine." Delivery reflects the
receiver's enforcement config, not the message's legitimacy.
dmarc=fail
with p=reject is the sender's domain telling you to distrust it.
- "The From address is our real domain, so it's internal." The
From header
is free text. Without aligned SPF/DKIM and a plausible origin hop, an
internal-looking From means nothing.
- "I'll just click the link to see where it goes." Clicking authenticates you
to a harvester or fires a beacon. Resolve URLs with headers-only requests,
wrapper decoders, and urlscan — never a live browser.
- "The gateway let it through, so it's clean." Gateways miss lookalike
domains, freshly registered infrastructure, HTML smuggling, and password-
protected archives by design. A delivered message is not a vetted one.
ATT&CK Coverage
Generated from secskills-core/ttp-index.json — edit that file, then run
python3 scripts/sync_attack.py --write. Re-verify IDs against the
current ATT&CK release before citing them in a report.
Reconnaissance (TA0043)
- T1598 Phishing for Information — see also
performing-social-engineering
Initial Access (TA0001)
- T1566 Phishing — see also
performing-social-engineering
- T1566.001 Spearphishing Attachment — see also
performing-social-engineering, analyzing-malware
- T1566.002 Spearphishing Link — see also
performing-social-engineering
Detection content for any of these: engineering-detections. Proactive search: hunting-threats. Post-compromise: responding-to-incidents.
References
analyzing-malware — sandboxed detonation and C2 extraction of attachments
investigating-m365-entra — tenant-side hunting when the phish succeeded
performing-social-engineering — building phishing campaigns (offensive)
analyzing-network-traffic — callback traffic from a detonated payload
producing-threat-intelligence — pivoting IOCs into tracked campaigns
reporting-security-findings — writing up the triage and verdict
oletools (olevba, oleid, rtfobj), oledump.py/emldump.py (DidierStevens
suite), msgconvert (Email::Outlook::Message, Perl), and exiftool for
message and attachment parsing
- Message Header Analyzer (MHA) and MXToolbox for parsing the Received chain
and querying SPF/DKIM/DMARC records
- urlscan.io and VirusTotal for URL/file detonation and reputation
- PhishTool for guided end-to-end phishing analysis and reporting
1---2name: analyzing-phishing-emails3description: Triage and forensically analyze reported phishing safely — extract the raw message, read the Received chain, verify SPF/DKIM/DMARC, detect display-name and lookalike spoofing, unwrap redirects and SafeLinks/URLDefense, decode quishing QR codes, triage attachments, and pull IOCs for hunting. Use when handed a reported phishing email, a suspicious .eml or .msg file, a set of email headers to analyze, a malicious attachment or link to triage, or a business email compromise or spoofing case.4---56# Analyzing Phishing Emails78An email is a stack of claims — who sent it, where it came from, that its9links are safe — and phishing analysis is checking each claim against evidence10the sender could not forge: the Received chain, the authentication results,11and the true destination of every link and attachment. The From header is a12display, not a fact. Anyone can type any address into it; your job is to find13the evidence that agrees or disagrees.1415## When to Use1617- A user reports a suspicious email and you need a verdict and IOCs18- You have a `.eml` or `.msg` file to analyze offline19- You are handed raw headers and asked whether a message is spoofed20- A message carries a link or attachment that needs safe triage21- A business email compromise, invoice-fraud, or vendor-impersonation case22- Confirming whether a domain or brand was spoofed against your users2324## When NOT to Use2526- **You extracted an attachment and need to detonate it** — come here first to27 safely extract and defang it, then hand the payload to `analyzing-malware`28- **The phish already succeeded and you are chasing the mailbox/OAuth29 compromise in the tenant** — use `investigating-m365-entra`30- **You are building the phishing campaign, not analyzing one** — use31 `performing-social-engineering`32- **The broader incident the phish kicked off** — use `responding-to-incidents`33- **Analyzing the callback traffic from a detonated payload** — use34 `analyzing-network-traffic`3536## Safe Handling — Do This First3738Treat every reported message as live. The failure mode is not misreading a39header; it is clicking a link in a production mail client or double-clicking40an attachment on your own host.4142- Never open the message in a live client. Attacker-controlled remote images43 fire a read beacon; one click on a link authenticates you to their harvester.44- Work from the raw source only — the `.eml`/`.msg`, not a forwarded copy.45 Forwarding rewrites headers and strips the evidence you need.46- Defang every indicator before it touches a report, ticket, or chat:47 `http` → `hxxp`, `.` → `[.]`, `@` → `[at]`. So `http://evil.com/login`48 becomes `hxxp://evil[.]com/login`. Defanging prevents an accidental click49 downstream and stops link-preview bots from detonating it for you.50- Extract and detonate only in an isolated VM with no host sharing and51 simulated or monitored egress — see `analyzing-malware` for the build.5253## Getting the Raw Message5455The visible email is a rendering. You need the source with all headers.5657- **Outlook/Exchange**: save as `.msg`, or in OWA use "View message source".58- **Gmail**: "Show original" → Download Original gives a `.eml`.59- **`.msg` → readable**: `msgconvert sample.msg` produces a `.eml` (RFC822).60- **Inspect structure**: `emldump.py sample.eml` lists MIME parts and indices;61 `emldump.py -s 4 -d sample.eml` dumps part 4 (an attachment) without opening62 it. A `.msg` is an OLE compound file — `oledump.py` (DidierStevens) lists its63 streams.64- **View full headers**: read the top block of the raw file directly, or paste65 into Message Header Analyzer (MHA) / Google's `mha` / MXToolbox Header66 Analyzer for a parsed hop table.6768Keep the original file hashed and untouched; work on copies.6970## The Received Chain7172The `Received:` headers are added by each mail server the message passes73through, newest at the top. Read them **bottom-up**: the bottom-most74`Received` is the originating server — the earliest, least-forgeable hop.7576```77Received: from mail.contoso.com (mail.contoso.com [203.0.113.9])78 by mx.recipient.com ... ; Tue, 21 Jul 2026 09:14:02 +0000 <- final hop79Received: from smtp.sketchy-vps.ru ([185.220.101.5])80 by mail.contoso.com ... ; Tue, 21 Jul 2026 09:13:58 +0000 <- origin81```8283- **Trace the originating IP**: the bottom hop's `[bracketed IP]`. Geolocate84 and WHOIS it (`whois 185.220.101.5`), check reputation, and reconcile it85 against the claimed sender. A "From: ceo@contoso.com" that originates on a86 Russian VPS is your finding.87- **Spot forged hops**: attackers prepend fake `Received` lines to fabricate a88 reputable origin. Only hops added by servers you trust are reliable — trust89 breaks at the first server outside your control. A hop that references a90 server not present in the next hop's `by` is invented.91- **Timezone and hop-time anomalies**: hop timestamps should increase upward by92 seconds. Negative deltas, multi-hour jumps, or a mix of implausible93 timezones indicate forgery or relay through odd infrastructure.94- **Reconcile with the claimed sender**: the origin domain, its PTR/rDNS, and95 the `From` domain should tell one coherent story. They usually do not in a96 phish.9798## Authentication Results99100SPF, DKIM, and DMARC are the forgery-resistant checks. The receiving server101records them in `Authentication-Results`. Read it, and re-verify rather than102trusting a summary.103104```105Authentication-Results: mx.recipient.com;106 spf=pass (sender IP is 185.220.101.5) smtp.mailfrom=bounce.sketchy-vps.ru;107 dkim=pass header.d=sketchy-vps.ru header.s=selector1;108 dmarc=fail (p=reject sp=reject dis=none) header.from=contoso.com109```110111- **SPF** authenticates the *envelope* sender (`Return-Path` / `smtp.mailfrom`112 / `MAIL FROM`), **not** the visible `From`. Values: `pass` (IP is authorized113 for the envelope domain), `fail` (hard `-all` reject), `softfail`114 (`~all`, suspicious but delivered), `neutral`/`none` (no policy). Check the115 domain's record: `dig txt contoso.com` and read the `v=spf1 ...` string.116- **DKIM** is a cryptographic signature over selected headers and the body.117 `dkim=pass` proves the message was signed by the key at `d=`'s selector and118 not modified. The load-bearing question is **alignment**: does `header.d=`119 match the `From` domain? A valid signature from `d=mailer-xyz.com` on a120 message claiming `From: contoso.com` is not contoso. Re-verify with121 `dkimverify < sample.eml` (dkimpy) and fetch the key via122 `dig txt selector1._domainkey.contoso.com`.123- **DMARC** ties SPF/DKIM to the visible `From` via *alignment* and applies the124 domain owner's *policy*. `dmarc=pass` requires SPF **or** DKIM to pass AND be125 aligned with `header.from`. Read the policy: `dig txt _dmarc.contoso.com`126 → `v=DMARC1; p=reject; ...`. `p=reject`/`quarantine` with `dmarc=fail` means127 the owner told you to distrust it.128- **ARC** (`ARC-Seal`/`ARC-Authentication-Results`) preserves upstream auth129 results across forwarders that would otherwise break SPF/DKIM. Use it to see130 how auth looked before a mailing list or gateway relayed the message.131- **Envelope vs header From**: `Return-Path`/envelope-from is what bounces go to132 and what SPF checks; the header `From:` is what the user sees. Phishers make133 them differ — a benign-looking `From` with a throwaway envelope domain that134 happens to pass SPF is the classic pattern.135136## Display-Name and Lookalike Spoofing137138Much phishing passes authentication because it comes from a *real* mailbox on a139*lookalike* domain. The auth checks pass for that domain; the deception is140visual.141142- **Display-name spoofing**: `From: "IT Helpdesk" <random@gmail.com>`. The name143 is a free-text label; read the actual address.144- **Cousin / lookalike domains**: `cont0so.com`, `contoso-support.com`,145 `contoso.co`. Diff against the real domain character by character.146- **Homoglyph / IDN**: Unicode characters that render like ASCII (Cyrillic `а`147 for Latin `a`). Punycode-encoded domains appear in headers as148 `xn--` — e.g. `xn--cntoso-...`. Decode with `idn` /149 `python3 -c "print('xn--80ak6aa92e.com'.encode().decode('idna'))"` and150 compare the rendered form.151- **Reply-To mismatch**: `From: ceo@contoso.com` but152 `Reply-To: ceo.contoso@gmail.com`. The reply silently goes to the attacker —153 a hallmark of BEC.154- **BEC with no payload**: pure text asking for a wire transfer, gift cards, or155 W-2 data. No link, no attachment, nothing to sandbox. The signal is entirely156 in the headers (Reply-To, origin, auth) and the pretext.157158## Header Forensics159160- **`Message-ID` sanity**: format is `<unique@sending-domain>`. The domain161 should match the sending infrastructure. A `Message-ID` domain that disagrees162 with the origin, or a malformed/duplicated ID, suggests a spoofing tool.163- **`X-Originating-IP`**: some webmail stamps the true client IP here — pivot on164 it, but note it is client-suppliable and can be forged.165- **`X-Mailer` / User-Agent**: reveals the sending client. Bulk-phish kits and166 scripts (`PHPMailer`, `Python`, custom mailers) look nothing like Outlook or167 the claimed sender's normal stack.168- **Mailer fingerprints**: legitimate bulk senders (SendGrid, Amazon SES,169 Mailchimp) add characteristic `X-` headers and `Received` paths. Their170 presence on a "personal" note from your CEO is a contradiction.171172## URL Analysis173174Every link is a claim about where it goes. Resolve it without visiting it.175176- **Unwrap redirects and shorteners**: expand `bit.ly`/`t.co` with177 `curl -sI hxxp://bit[.]ly/xyz` (read `Location:`, do not follow) or a178 preview service. Chase every hop to the real landing page.179- **Decode wrapper rewrites** — the real URL is inside the wrapper:180 - Microsoft **SafeLinks**: `https://*.safelinks.protection.outlook.com/?url=<encoded>&...`181 — URL-decode the `url=` parameter.182 - Proofpoint **URLDefense**: `https://urldefense.com/v3/__<encoded>__;...` —183 decode with the published `urldefense` decoder (v2/v3 schemes differ).184 These wrappers hide the destination; always extract the original.185- **Quishing (QR-code phishing)**: the payload is an image, not a link. Extract186 the image part (`emldump.py -s N -d`), then decode:187 `zbarimg qr.png` or `python3 -c "from PIL import Image; import188 pyzbar.pyzbar as z; print(z.decode(Image.open('qr.png')))"`. Analyze the189 decoded URL like any other.190- **Intent — harvest vs delivery**: a link to a cloned login page (Microsoft,191 DocuSign, a bank) is **credential harvesting**; a link that downloads a file192 is **malware delivery**. They need different responses.193- **Detonate safely**: submit the URL to **urlscan.io** (use unlisted/private194 scans for targeted phish so you don't tip the actor) or a sandbox, and pull195 the real landing page, screenshot, and served content. Extract the landing196 page and any kit files for the IOC set.197198## Attachment Analysis199200Identify and defang before anything executes.201202- **Hash and identify**: `sha256sum att.ext && file att.ext`. Extract with203 `emldump.py -s N -d sample.eml > att.ext` — never by double-clicking.204- **Common delivery wrappers**: HTML smuggling (a `.html` that assembles a205 payload in-browser via a Blob), ISO/IMG/VHD (mount bypasses MOTW), LNK206 shortcuts, OneNote (`.one`) with embedded scripts, and password-protected207 archives (password in the email body defeats gateway scanning).208- **Documents/macros**: `exiftool att.docx` for metadata and authoring209 fingerprints; `oleid att.xls` and `olevba --deobf att.xls` /210 `oledump.py att.doc` for macros; `rtfobj att.rtf` for embedded objects.211- Once identified, **hand the live payload to `analyzing-malware`** for212 sandboxed detonation, unpacking, and C2 extraction. This skill's job is safe213 extraction and triage, not detonation.214215## Pulling and Packaging IOCs216217Extract a clean, defanged indicator set for blocking and hunting:218219- **Sender infrastructure**: originating IP, envelope-from domain, `From`/cousin220 domains, `Reply-To`, `Message-ID` domain, mailer fingerprints.221- **URLs**: the wrapped and unwrapped forms, final landing page, shortener222 chain, and any kit hostnames from urlscan.223- **Hashes**: SHA-256 of every attachment and of decoded/downloaded payloads.224- **Hunting selectors**: subject lines, sender display names, and body225 fingerprints to search the mail gateway and other mailboxes.226227Package these for `producing-threat-intelligence` when the phish is part of a228tracked campaign, and for `reporting-security-findings` for the writeup.229230## Scoping the Campaign231232One report is rarely the only recipient. Find the rest before you close.233234- **M365**: `Search-UnifiedAuditLog` and Content Search / `New-ComplianceSearch`235 for the subject, sender, and URL across all mailboxes; hard-delete or236 quarantine matches via `Get-QuarantineMessage` / eDiscovery purge.237- **Mail gateway** (Proofpoint, Mimecast, Defender for O365): search message238 trace / Threat Explorer for the sender domain, URL, and attachment hash to239 enumerate every recipient and whether anyone clicked or replied.240- If any recipient interacted, the phish may have succeeded — pivot to241 `investigating-m365-entra` for tenant-side hunting (sign-ins, inbox rules,242 OAuth grants) and to `responding-to-incidents` for the broader response.243244## Rationalizations to Reject245246- *"SPF passed, so it's legitimate."* SPF authenticates the envelope domain,247 not the visible `From`. A passing SPF on a lookalike or throwaway envelope248 domain is exactly what a competent phish shows. Check DMARC alignment.249- *"DKIM is valid, so it's from them."* A valid signature only proves the `d=`250 domain signed it. If `d=` isn't aligned with the `From` domain, it's signed251 by someone else. Alignment is the question, not signature validity.252- *"No attachment or link, so it's harmless."* BEC and payment-fraud phish253 carry neither — the weapon is the pretext and the Reply-To. Read the headers.254- *"DMARC failed but it was delivered, so it's fine."* Delivery reflects the255 receiver's enforcement config, not the message's legitimacy. `dmarc=fail`256 with `p=reject` is the sender's domain telling you to distrust it.257- *"The From address is our real domain, so it's internal."* The `From` header258 is free text. Without aligned SPF/DKIM and a plausible origin hop, an259 internal-looking From means nothing.260- *"I'll just click the link to see where it goes."* Clicking authenticates you261 to a harvester or fires a beacon. Resolve URLs with headers-only requests,262 wrapper decoders, and urlscan — never a live browser.263- *"The gateway let it through, so it's clean."* Gateways miss lookalike264 domains, freshly registered infrastructure, HTML smuggling, and password-265 protected archives by design. A delivered message is not a vetted one.266267<!-- attack:start -->268269## ATT&CK Coverage270271_Generated from `secskills-core/ttp-index.json` — edit that file, then run272`python3 scripts/sync_attack.py --write`. Re-verify IDs against the273current ATT&CK release before citing them in a report._274275**Reconnaissance** (TA0043)276277- [T1598](https://attack.mitre.org/techniques/T1598/) Phishing for Information — see also `performing-social-engineering`278279**Initial Access** (TA0001)280281- [T1566](https://attack.mitre.org/techniques/T1566/) Phishing — see also `performing-social-engineering`282- [T1566.001](https://attack.mitre.org/techniques/T1566/001/) Spearphishing Attachment — see also `performing-social-engineering`, `analyzing-malware`283- [T1566.002](https://attack.mitre.org/techniques/T1566/002/) Spearphishing Link — see also `performing-social-engineering`284285Detection content for any of these: `engineering-detections`. Proactive search: `hunting-threats`. Post-compromise: `responding-to-incidents`.286287<!-- attack:end -->288289## References290291- `analyzing-malware` — sandboxed detonation and C2 extraction of attachments292- `investigating-m365-entra` — tenant-side hunting when the phish succeeded293- `performing-social-engineering` — building phishing campaigns (offensive)294- `analyzing-network-traffic` — callback traffic from a detonated payload295- `producing-threat-intelligence` — pivoting IOCs into tracked campaigns296- `reporting-security-findings` — writing up the triage and verdict297- `oletools` (olevba, oleid, rtfobj), `oledump.py`/`emldump.py` (DidierStevens298 suite), `msgconvert` (Email::Outlook::Message, Perl), and `exiftool` for299 message and attachment parsing300- Message Header Analyzer (MHA) and MXToolbox for parsing the Received chain301 and querying SPF/DKIM/DMARC records302- urlscan.io and VirusTotal for URL/file detonation and reputation303- PhishTool for guided end-to-end phishing analysis and reporting