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.4verified: 2026-07-265---67# Analyzing Phishing Emails89An email is a stack of claims — who sent it, where it came from, that its10links are safe — and phishing analysis is checking each claim against evidence11the sender could not forge: the Received chain, the authentication results,12and the true destination of every link and attachment. The From header is a13display, not a fact. Anyone can type any address into it; your job is to find14the evidence that agrees or disagrees.1516## When to Use1718- A user reports a suspicious email and you need a verdict and IOCs19- You have a `.eml` or `.msg` file to analyze offline20- You are handed raw headers and asked whether a message is spoofed21- A message carries a link or attachment that needs safe triage22- A business email compromise, invoice-fraud, or vendor-impersonation case23- Confirming whether a domain or brand was spoofed against your users2425## When NOT to Use2627- **You extracted an attachment and need to detonate it** — come here first to28 safely extract and defang it, then hand the payload to `analyzing-malware`29- **The phish already succeeded and you are chasing the mailbox/OAuth30 compromise in the tenant** — use `investigating-m365-entra`31- **You are building the phishing campaign, not analyzing one** — use32 `performing-social-engineering`33- **The broader incident the phish kicked off** — use `responding-to-incidents`34- **Analyzing the callback traffic from a detonated payload** — use35 `analyzing-network-traffic`3637## Safe Handling — Do This First3839Treat every reported message as live. The failure mode is not misreading a40header; it is clicking a link in a production mail client or double-clicking41an attachment on your own host.4243- Never open the message in a live client. Attacker-controlled remote images44 fire a read beacon; one click on a link authenticates you to their harvester.45- Work from the raw source only — the `.eml`/`.msg`, not a forwarded copy.46 Forwarding rewrites headers and strips the evidence you need.47- Defang every indicator before it touches a report, ticket, or chat:48 `http` → `hxxp`, `.` → `[.]`, `@` → `[at]`. So `http://evil.com/login`49 becomes `hxxp://evil[.]com/login`. Defanging prevents an accidental click50 downstream and stops link-preview bots from detonating it for you.51- Extract and detonate only in an isolated VM with no host sharing and52 simulated or monitored egress — see `analyzing-malware` for the build.5354## Getting the Raw Message5556The visible email is a rendering. You need the source with all headers.5758- **Outlook/Exchange**: save as `.msg`, or in OWA use "View message source".59- **Gmail**: "Show original" → Download Original gives a `.eml`.60- **`.msg` → readable**: `msgconvert sample.msg` produces a `.eml` (RFC822).61- **Inspect structure**: `emldump.py sample.eml` lists MIME parts and indices;62 `emldump.py -s 4 -d sample.eml` dumps part 4 (an attachment) without opening63 it. A `.msg` is an OLE compound file — `oledump.py` (DidierStevens) lists its64 streams.65- **View full headers**: read the top block of the raw file directly, or paste66 into Message Header Analyzer (MHA) / Google's `mha` / MXToolbox Header67 Analyzer for a parsed hop table.6869Keep the original file hashed and untouched; work on copies.7071## The Received Chain7273The `Received:` headers are added by each mail server the message passes74through, newest at the top. Read them **bottom-up**: the bottom-most75`Received` is the originating server — the earliest, least-forgeable hop.7677```78Received: from mail.contoso.com (mail.contoso.com [203.0.113.9])79 by mx.recipient.com ... ; Tue, 21 Jul 2026 09:14:02 +0000 <- final hop80Received: from smtp.sketchy-vps.ru ([185.220.101.5])81 by mail.contoso.com ... ; Tue, 21 Jul 2026 09:13:58 +0000 <- origin82```8384- **Trace the originating IP**: the bottom hop's `[bracketed IP]`. Geolocate85 and WHOIS it (`whois 185.220.101.5`), check reputation, and reconcile it86 against the claimed sender. A "From: ceo@contoso.com" that originates on a87 Russian VPS is your finding.88- **Spot forged hops**: attackers prepend fake `Received` lines to fabricate a89 reputable origin. Only hops added by servers you trust are reliable — trust90 breaks at the first server outside your control. A hop that references a91 server not present in the next hop's `by` is invented.92- **Timezone and hop-time anomalies**: hop timestamps should increase upward by93 seconds. Negative deltas, multi-hour jumps, or a mix of implausible94 timezones indicate forgery or relay through odd infrastructure.95- **Reconcile with the claimed sender**: the origin domain, its PTR/rDNS, and96 the `From` domain should tell one coherent story. They usually do not in a97 phish.9899## Authentication Results100101SPF, DKIM, and DMARC are the forgery-resistant checks. The receiving server102records them in `Authentication-Results`. Read it, and re-verify rather than103trusting a summary.104105```106Authentication-Results: mx.recipient.com;107 spf=pass (sender IP is 185.220.101.5) smtp.mailfrom=bounce.sketchy-vps.ru;108 dkim=pass header.d=sketchy-vps.ru header.s=selector1;109 dmarc=fail (p=reject sp=reject dis=none) header.from=contoso.com110```111112- **SPF** authenticates the *envelope* sender (`Return-Path` / `smtp.mailfrom`113 / `MAIL FROM`), **not** the visible `From`. Values: `pass` (IP is authorized114 for the envelope domain), `fail` (hard `-all` reject), `softfail`115 (`~all`, suspicious but delivered), `neutral`/`none` (no policy). Check the116 domain's record: `dig txt contoso.com` and read the `v=spf1 ...` string.117- **DKIM** is a cryptographic signature over selected headers and the body.118 `dkim=pass` proves the message was signed by the key at `d=`'s selector and119 not modified. The load-bearing question is **alignment**: does `header.d=`120 match the `From` domain? A valid signature from `d=mailer-xyz.com` on a121 message claiming `From: contoso.com` is not contoso. Re-verify with122 `dkimverify < sample.eml` (dkimpy) and fetch the key via123 `dig txt selector1._domainkey.contoso.com`.124- **DMARC** ties SPF/DKIM to the visible `From` via *alignment* and applies the125 domain owner's *policy*. `dmarc=pass` requires SPF **or** DKIM to pass AND be126 aligned with `header.from`. Read the policy: `dig txt _dmarc.contoso.com`127 → `v=DMARC1; p=reject; ...`. `p=reject`/`quarantine` with `dmarc=fail` means128 the owner told you to distrust it.129- **ARC** (`ARC-Seal`/`ARC-Authentication-Results`) preserves upstream auth130 results across forwarders that would otherwise break SPF/DKIM. Use it to see131 how auth looked before a mailing list or gateway relayed the message.132- **Envelope vs header From**: `Return-Path`/envelope-from is what bounces go to133 and what SPF checks; the header `From:` is what the user sees. Phishers make134 them differ — a benign-looking `From` with a throwaway envelope domain that135 happens to pass SPF is the classic pattern.136137## Display-Name and Lookalike Spoofing138139Much phishing passes authentication because it comes from a *real* mailbox on a140*lookalike* domain. The auth checks pass for that domain; the deception is141visual.142143- **Display-name spoofing**: `From: "IT Helpdesk" <random@gmail.com>`. The name144 is a free-text label; read the actual address.145- **Cousin / lookalike domains**: `cont0so.com`, `contoso-support.com`,146 `contoso.co`. Diff against the real domain character by character.147- **Homoglyph / IDN**: Unicode characters that render like ASCII (Cyrillic `а`148 for Latin `a`). Punycode-encoded domains appear in headers as149 `xn--` — e.g. `xn--cntoso-...`. Decode with `idn` /150 `python3 -c "print('xn--80ak6aa92e.com'.encode().decode('idna'))"` and151 compare the rendered form.152- **Reply-To mismatch**: `From: ceo@contoso.com` but153 `Reply-To: ceo.contoso@gmail.com`. The reply silently goes to the attacker —154 a hallmark of BEC.155- **BEC with no payload**: pure text asking for a wire transfer, gift cards, or156 W-2 data. No link, no attachment, nothing to sandbox. The signal is entirely157 in the headers (Reply-To, origin, auth) and the pretext.158159## Header Forensics160161- **`Message-ID` sanity**: format is `<unique@sending-domain>`. The domain162 should match the sending infrastructure. A `Message-ID` domain that disagrees163 with the origin, or a malformed/duplicated ID, suggests a spoofing tool.164- **`X-Originating-IP`**: some webmail stamps the true client IP here — pivot on165 it, but note it is client-suppliable and can be forged.166- **`X-Mailer` / User-Agent**: reveals the sending client. Bulk-phish kits and167 scripts (`PHPMailer`, `Python`, custom mailers) look nothing like Outlook or168 the claimed sender's normal stack.169- **Mailer fingerprints**: legitimate bulk senders (SendGrid, Amazon SES,170 Mailchimp) add characteristic `X-` headers and `Received` paths. Their171 presence on a "personal" note from your CEO is a contradiction.172173## URL Analysis174175Every link is a claim about where it goes. Resolve it without visiting it.176177- **Unwrap redirects and shorteners**: expand `bit.ly`/`t.co` with178 `curl -sI hxxp://bit[.]ly/xyz` (read `Location:`, do not follow) or a179 preview service. Chase every hop to the real landing page.180- **Decode wrapper rewrites** — the real URL is inside the wrapper:181 - Microsoft **SafeLinks**: `https://*.safelinks.protection.outlook.com/?url=<encoded>&...`182 — URL-decode the `url=` parameter.183 - Proofpoint **URLDefense**: `https://urldefense.com/v3/__<encoded>__;...` —184 decode with the published `urldefense` decoder (v2/v3 schemes differ).185 These wrappers hide the destination; always extract the original.186- **Quishing (QR-code phishing)**: the payload is an image, not a link. Extract187 the image part (`emldump.py -s N -d`), then decode:188 `zbarimg qr.png` or `python3 -c "from PIL import Image; import189 pyzbar.pyzbar as z; print(z.decode(Image.open('qr.png')))"`. Analyze the190 decoded URL like any other.191- **Intent — harvest vs delivery**: a link to a cloned login page (Microsoft,192 DocuSign, a bank) is **credential harvesting**; a link that downloads a file193 is **malware delivery**. They need different responses.194- **Detonate safely**: submit the URL to **urlscan.io** (use unlisted/private195 scans for targeted phish so you don't tip the actor) or a sandbox, and pull196 the real landing page, screenshot, and served content. Extract the landing197 page and any kit files for the IOC set.198199## Attachment Analysis200201Identify and defang before anything executes.202203- **Hash and identify**: `sha256sum att.ext && file att.ext`. Extract with204 `emldump.py -s N -d sample.eml > att.ext` — never by double-clicking.205- **Common delivery wrappers**: HTML smuggling (a `.html` that assembles a206 payload in-browser via a Blob), ISO/IMG/VHD (mount bypasses MOTW), LNK207 shortcuts, OneNote (`.one`) with embedded scripts, and password-protected208 archives (password in the email body defeats gateway scanning).209- **Documents/macros**: `exiftool att.docx` for metadata and authoring210 fingerprints; `oleid att.xls` and `olevba --deobf att.xls` /211 `oledump.py att.doc` for macros; `rtfobj att.rtf` for embedded objects.212- Once identified, **hand the live payload to `analyzing-malware`** for213 sandboxed detonation, unpacking, and C2 extraction. This skill's job is safe214 extraction and triage, not detonation.215216## Pulling and Packaging IOCs217218Extract a clean, defanged indicator set for blocking and hunting:219220- **Sender infrastructure**: originating IP, envelope-from domain, `From`/cousin221 domains, `Reply-To`, `Message-ID` domain, mailer fingerprints.222- **URLs**: the wrapped and unwrapped forms, final landing page, shortener223 chain, and any kit hostnames from urlscan.224- **Hashes**: SHA-256 of every attachment and of decoded/downloaded payloads.225- **Hunting selectors**: subject lines, sender display names, and body226 fingerprints to search the mail gateway and other mailboxes.227228Package these for `producing-threat-intelligence` when the phish is part of a229tracked campaign, and for `reporting-security-findings` for the writeup.230231## Scoping the Campaign232233One report is rarely the only recipient. Find the rest before you close.234235- **M365**: `Search-UnifiedAuditLog` and Content Search / `New-ComplianceSearch`236 for the subject, sender, and URL across all mailboxes; hard-delete or237 quarantine matches via `Get-QuarantineMessage` / eDiscovery purge.238- **Mail gateway** (Proofpoint, Mimecast, Defender for O365): search message239 trace / Threat Explorer for the sender domain, URL, and attachment hash to240 enumerate every recipient and whether anyone clicked or replied.241- If any recipient interacted, the phish may have succeeded — pivot to242 `investigating-m365-entra` for tenant-side hunting (sign-ins, inbox rules,243 OAuth grants) and to `responding-to-incidents` for the broader response.244245## Rationalizations to Reject246247- *"SPF passed, so it's legitimate."* SPF authenticates the envelope domain,248 not the visible `From`. A passing SPF on a lookalike or throwaway envelope249 domain is exactly what a competent phish shows. Check DMARC alignment.250- *"DKIM is valid, so it's from them."* A valid signature only proves the `d=`251 domain signed it. If `d=` isn't aligned with the `From` domain, it's signed252 by someone else. Alignment is the question, not signature validity.253- *"No attachment or link, so it's harmless."* BEC and payment-fraud phish254 carry neither — the weapon is the pretext and the Reply-To. Read the headers.255- *"DMARC failed but it was delivered, so it's fine."* Delivery reflects the256 receiver's enforcement config, not the message's legitimacy. `dmarc=fail`257 with `p=reject` is the sender's domain telling you to distrust it.258- *"The From address is our real domain, so it's internal."* The `From` header259 is free text. Without aligned SPF/DKIM and a plausible origin hop, an260 internal-looking From means nothing.261- *"I'll just click the link to see where it goes."* Clicking authenticates you262 to a harvester or fires a beacon. Resolve URLs with headers-only requests,263 wrapper decoders, and urlscan — never a live browser.264- *"The gateway let it through, so it's clean."* Gateways miss lookalike265 domains, freshly registered infrastructure, HTML smuggling, and password-266 protected archives by design. A delivered message is not a vetted one.267268<!-- attack:start -->269270## ATT&CK Coverage271272_Generated from `secskills-core/ttp-index.json` — edit that file, then run273`python3 scripts/sync_attack.py --write`. Re-verify IDs against the274current ATT&CK release before citing them in a report._275276**Reconnaissance** (TA0043)277278- [T1598](https://attack.mitre.org/techniques/T1598/) Phishing for Information — see also `performing-social-engineering`279280**Initial Access** (TA0001)281282- [T1566](https://attack.mitre.org/techniques/T1566/) Phishing — see also `performing-social-engineering`283- [T1566.001](https://attack.mitre.org/techniques/T1566/001/) Spearphishing Attachment — see also `performing-social-engineering`, `analyzing-malware`284- [T1566.002](https://attack.mitre.org/techniques/T1566/002/) Spearphishing Link — see also `performing-social-engineering`285286Detection content for any of these: `engineering-detections`. Proactive search: `hunting-threats`. Post-compromise: `responding-to-incidents`.287288<!-- attack:end -->289290## References291292- `analyzing-malware` — sandboxed detonation and C2 extraction of attachments293- `investigating-m365-entra` — tenant-side hunting when the phish succeeded294- `performing-social-engineering` — building phishing campaigns (offensive)295- `analyzing-network-traffic` — callback traffic from a detonated payload296- `producing-threat-intelligence` — pivoting IOCs into tracked campaigns297- `reporting-security-findings` — writing up the triage and verdict298- `oletools` (olevba, oleid, rtfobj), `oledump.py`/`emldump.py` (DidierStevens299 suite), `msgconvert` (Email::Outlook::Message, Perl), and `exiftool` for300 message and attachment parsing301- Message Header Analyzer (MHA) and MXToolbox for parsing the Received chain302 and querying SPF/DKIM/DMARC records303- urlscan.io and VirusTotal for URL/file detonation and reputation304- PhishTool for guided end-to-end phishing analysis and reporting