phishing-site-link-identification.md (22783B)
1 --- 2 title: "Phishing Site & Link Identification" 3 description: "1. Golden Rules 2. URL Anatomy — Where to Actually Look 3. Domain Red Flags 4. Homoglyph & Punycode Detection 5. Unwrapping Redirects & Shorteners 6…" 4 category: web 5 tags: ["web", "adcs"] 6 tools: ["OpenSSL"] 7 difficulty: intermediate 8 updated: "2026-08-10" 9 source: "vault:Web/Phishing Site & Link Identification - Cheat Sheet.md" 10 --- 11 # Phishing Site & Link Identification — Cheat Sheet 12 13 ### Defensive triage for suspicious URLs, domains and landing pages 14 15 > Covers: URL anatomy · lookalike domains · punycode/IDN · redirect chains · header and SPF/DKIM/DMARC checks · WHOIS and DNS · certificate transparency · safe fetching and detonation 16 17 --- 18 19 ## Table of Contents 20 21 1. [Golden Rules](#golden-rules) 22 2. [URL Anatomy — Where to Actually Look](#1-url-anatomy--where-to-actually-look) 23 3. [Domain Red Flags](#2-domain-red-flags) 24 4. [Homoglyph & Punycode Detection](#3-homoglyph--punycode-detection) 25 5. [Unwrapping Redirects & Shorteners](#4-unwrapping-redirects--shorteners) 26 6. [Email Header & Auth Triage](#5-email-header--auth-triage) 27 7. [WHOIS & DNS Checks](#6-whois--dns-checks) 28 8. [TLS Certificate & CT Logs](#7-tls-certificate--ct-logs) 29 9. [Safe Fetching of Page Content](#8-safe-fetching-of-page-content) 30 10. [Landing Page Tells](#9-landing-page-tells) 31 11. [Attachment Triage](#10-attachment-triage) 32 12. [Reputation & Sandbox Services](#11-reputation--sandbox-services) 33 13. [Triage Workflow](#12-triage-workflow) 34 14. [Quick Reference Table](#13-quick-reference-table) 35 15. [Reporting & Takedown](#14-reporting--takedown) 36 37 --- 38 39 ## Golden Rules 40 41 > [!warning] Handle every unverified URL as live malware. 42 > - Never open a suspicious link in your daily-driver browser or on a host with credentials on it. Use a disposable VM, and route through a network you do not mind burning. 43 > - Fetching a URL leaks your IP and often a unique token embedded in the link, which confirms to the operator that the target is live. Prefer passive lookups first. 44 > - Judge the **registrable domain**, never the display text, the path, the favicon or the branding. 45 > - HTTPS and a padlock prove nothing. Free DV certificates mean the overwhelming majority of phishing sites are served over TLS. 46 > - If a page asks for credentials, MFA codes or a card number, navigate to the service yourself from a known-good bookmark instead. 47 48 --- 49 50 ## 1. URL Anatomy — Where to Actually Look 51 52 ``` 53 https://accounts.google.com.verify-login.ru:8443/signin?token=abc#/ 54 └─┬─┘ └──────────────┬──────────────────────┘└─┬┘└──┬─┘└───┬───┘ 55 scheme host (read RIGHT to LEFT) port path query 56 ``` 57 58 The only part that matters for identity is the **registrable domain**, the last two labels before the public suffix. Read the host from right to left, stopping at the first `/`. 59 60 | URL | Registrable domain | Verdict | 61 |---|---|---| 62 | `https://accounts.google.com/signin` | `google.com` | Legitimate | 63 | `https://accounts.google.com.verify-login.ru/` | `verify-login.ru` | Phish — brand is a subdomain | 64 | `https://google.com.evil.co/` | `evil.co` | Phish | 65 | `https://secure-google.com/` | `secure-google.com` | Phish — hyphenated lookalike | 66 | `https://google.com@evil.co/` | `evil.co` | Phish — everything before `@` is userinfo | 67 | `https://sites.google.com/view/login-x` | `google.com` | Legitimate host, abused hosting | 68 69 Extract the host programmatically rather than trusting your eyes: 70 71 ```bash 72 # Pull scheme, host, path out of a URL without fetching it 73 print -r 'https://accounts.google.com.verify-login.ru/signin' | \ 74 python3 -c 'import sys,urllib.parse as u; p=u.urlparse(sys.stdin.read().strip()); print("host:",p.hostname,"\nport:",p.port,"\npath:",p.path,"\nuser:",p.username)' 75 ``` 76 77 ```bash 78 # Registrable domain (eTLD+1) using the public suffix list 79 uv venv .venv && source .venv/bin/activate 80 uv pip install tldextract 81 python3 -c 'import tldextract,sys; e=tldextract.extract(sys.argv[1]); print(e.registered_domain)' \ 82 'https://accounts.google.com.verify-login.ru/signin' 83 ``` 84 85 > [!tip] Common obfuscations 86 > - `@` userinfo trick: browser goes to whatever follows the `@`. 87 > - Decimal, octal or hex IPs: `http://2130706433/` is `127.0.0.1`. 88 > - Percent-encoding of the host or path to hide keywords. 89 > - Very long paths padding the real domain off the end of a mobile URL bar. 90 > - Data URIs and `blob:` URLs rendering a login form with no remote host at all. 91 92 --- 93 94 ## 2. Domain Red Flags 95 96 | Signal | Why it matters | How to check | 97 |---|---|---| 98 | Registered in the last 30 days | Phishing infra is disposable and short-lived | `whois` creation date | 99 | Brand name as a subdomain or in the path | Legitimate brands own their apex | Read host right to left | 100 | Hyphenated brand combos (`paypal-secure-login`) | Cheap way to look plausible | Visual | 101 | Unusual TLD for the brand (`.zip`, `.mov`, `.top`, `.cf`, `.xyz`) | Cheap or free registration | Visual | 102 | Free hosting or dev platform subdomains | Abused for zero-cost hosting with valid TLS | Check apex against known SaaS | 103 | Privacy-shielded WHOIS on a "corporate" login page | Real brands do not hide registrant data | `whois` | 104 | Wildcard DNS answering every subdomain | Per-victim subdomains | `dig random.$domain` | 105 | Hosting ASN mismatched with the brand | Bulletproof or cheap VPS ranges | `whois <ip>` | 106 | Open directory listing or `/.git` exposed | Sloppy kit deployment | Manual, in a VM | 107 108 Legitimate-but-abused hosting worth recognising: `*.web.app`, `*.firebaseapp.com`, `*.pages.dev`, `*.workers.dev`, `*.r2.dev`, `*.blob.core.windows.net`, `*.s3.amazonaws.com`, `*.weeblysite.com`, `*.glitch.me`, `sites.google.com/view/...`, `*.notion.site`, IPFS gateways. The apex is genuine, so reputation feeds often miss them. 109 110 --- 111 112 ## 3. Homoglyph & Punycode Detection 113 114 Internationalised domains let attackers register visually identical names. Browsers show punycode as `xn--` only in some cases, so decode explicitly. 115 116 ```bash 117 # Decode punycode to the real Unicode label 118 python3 -c 'print("xn--80ak6aa92e".encode().decode("idna"))' # -> аррӏе (Cyrillic) 119 120 # Encode a suspect Unicode host to see its punycode form 121 python3 -c 'print("аррӏе.com".encode("idna").decode())' 122 ``` 123 124 ```bash 125 # Flag any non-ASCII characters in a host, and name the script of each 126 python3 - <<'PY' 127 import unicodedata 128 host = "аррӏе.com" 129 for ch in host: 130 if ord(ch) > 127: 131 print(f"{ch!r} U+{ord(ch):04X} {unicodedata.name(ch)}") 132 PY 133 ``` 134 135 Mixed-script hosts (Latin plus Cyrillic or Greek in one label) are almost always hostile. Classic swaps to watch for: 136 137 | Looks like | Actually | Codepoint | 138 |---|---|---| 139 | `a` | Cyrillic а | U+0430 | 140 | `e` | Cyrillic е | U+0435 | 141 | `o` | Cyrillic о | U+043E | 142 | `p` | Cyrillic р | U+0440 | 143 | `i` / `l` | Cyrillic ӏ, Turkish ı | U+04CF, U+0131 | 144 | `rn` | reads as `m` at small sizes | ASCII only | 145 | `vv` | reads as `w` | ASCII only | 146 | `1` / `l` / `I` | font-dependent confusion | ASCII only | 147 148 Generate and check typosquats around a brand you protect: 149 150 ```bash 151 # dnstwist enumerates permutations and resolves the live ones 152 uv pip install dnstwist 153 dnstwist --registered --mx --format cli example.com 154 ``` 155 156 --- 157 158 ## 4. Unwrapping Redirects & Shorteners 159 160 Resolve the chain without executing anything. Prefer `HEAD` and never follow blindly into a download. 161 162 ```bash 163 # Show every hop, headers only, no body, no auto-follow of unsafe schemes 164 curl -sIL --max-redirs 10 --max-time 15 -A 'Mozilla/5.0' 'https://short.link/abc' \ 165 | grep -Ei '^(HTTP/|location:)' 166 ``` 167 168 ```bash 169 # One hop at a time, so you can bail out 170 curl -sI 'https://short.link/abc' | grep -i '^location:' 171 ``` 172 173 Many shorteners expose a preview or API that avoids touching attacker infra at all: 174 175 | Service | Preview method | 176 |---|---| 177 | bit.ly | append `+` to the URL | 178 | tinyurl.com | `https://preview.tinyurl.com/<code>` | 179 | ow.ly, buff.ly | Bitly-family, `+` often works | 180 | t.co | `curl -sI` returns `location` without rendering | 181 182 Unwrap corporate link-rewriting so you see the real destination: 183 184 ```bash 185 # Proofpoint URLDefense v3, Microsoft Safe Links, Barracuda etc. all URL-encode the original 186 python3 -c 'import sys,urllib.parse as u; q=u.parse_qs(u.urlparse(sys.argv[1]).query); print(q.get("url",[""])[0])' \ 187 'https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fevil.co%2Flogin&data=...' 188 ``` 189 190 > [!warning] Every link in a phish is usually unique per recipient. Fetching it tells the operator your address is live and may burn the sample before analysis. 191 192 --- 193 194 ## 5. Email Header & Auth Triage 195 196 Get the **original** headers, not a forward. In Gmail use "Show original", in Outlook "View source", and save the `.eml` intact. 197 198 What to read, in order: 199 200 1. `From:` display name versus the actual address in angle brackets. 201 2. `Return-Path:` / envelope sender. A mismatch with `From:` is normal for mailing lists but suspicious for a bank. 202 3. `Reply-To:` pointing somewhere unrelated is a strong lure signal. 203 4. `Authentication-Results:` for SPF, DKIM and DMARC verdicts. 204 5. Earliest `Received:` hop, which shows the true origin before the receiving infra. 205 6. `Message-ID` domain matching the sending domain. 206 207 ```bash 208 # Pull the auth verdicts and the sender fields out of a saved .eml 209 grep -Ei '^(authentication-results|received-spf|dkim-signature|from|reply-to|return-path|message-id):' sample.eml 210 ``` 211 212 ```bash 213 # Parse an .eml properly, including nested parts and URLs in the body 214 python3 - <<'PY' 215 import email, re 216 from email import policy 217 m = email.message_from_file(open("sample.eml"), policy=policy.default) 218 for h in ("From","Reply-To","Return-Path","Subject","Date","Authentication-Results","Message-ID"): 219 print(f"{h}: {m.get(h)}") 220 body = "".join(p.get_content() for p in m.walk() if p.get_content_type() in ("text/plain","text/html")) 221 for url in sorted(set(re.findall(r'https?://[^\s"\'<>)]+', body))): 222 print("URL:", url) 223 PY 224 ``` 225 226 Interpreting the verdicts: 227 228 | Result | Meaning | Weight | 229 |---|---|---| 230 | `spf=fail` + `dkim=fail` + `dmarc=fail` | Spoofed sending domain | Strong | 231 | `spf=pass` on an attacker-owned lookalike domain | Auth passes for *their* domain, proves nothing about the brand | Neutral, common | 232 | `dkim=pass` with `d=` not matching the `From:` domain | Unaligned DKIM, DMARC will not pass on it | Suspicious | 233 | `dmarc=pass` | Aligned and authenticated for the `From:` domain | Reassuring, not conclusive if the account is compromised | 234 235 ```bash 236 # Check what the claimed domain publishes 237 dig +short TXT example.com | grep -i spf 238 dig +short TXT _dmarc.example.com 239 dig +short TXT selector1._domainkey.example.com 240 ``` 241 242 > [!note] Business email compromise sends from a genuinely owned, fully authenticated mailbox. Auth passing is not innocence. Weight the request itself: payment redirection, urgency, secrecy, out-of-band contact. 243 244 --- 245 246 ## 6. WHOIS & DNS Checks 247 248 ```bash 249 # Registration age is the single highest-signal indicator 250 whois evil-login.co | grep -Ei 'creation|created|registered|registrar|registrant|name server' 251 ``` 252 253 ```bash 254 # Resolution and infrastructure 255 dig +short A evil-login.co 256 dig +short NS evil-login.co 257 dig +short MX evil-login.co # MX present = capable of receiving replies 258 dig +short TXT evil-login.co 259 260 # Wildcard test: does a random subdomain resolve? Per-victim subdomains are a kit tell 261 dig +short "$(openssl rand -hex 6).evil-login.co" 262 263 # Who owns the hosting 264 whois "$(dig +short A evil-login.co | head -1)" | grep -Ei 'orgname|netname|country|origin' 265 ``` 266 267 ```bash 268 # Passive DNS style pivot: what else is on that IP (use a service, do not scan) 269 # See section 11 for tooling. Shared cheap hosting will show hundreds of unrelated domains. 270 ``` 271 272 Age heuristic worth internalising: a "Microsoft account security" page on a domain created 4 days ago with a privacy-shielded registrant and a Let's Encrypt certificate issued the same day is phishing until proven otherwise. 273 274 --- 275 276 ## 7. TLS Certificate & CT Logs 277 278 ```bash 279 # Inspect the presented certificate without loading the page 280 echo | openssl s_client -connect evil-login.co:443 -servername evil-login.co 2>/dev/null \ 281 | openssl x509 -noout -subject -issuer -dates -ext subjectAltName 282 ``` 283 284 What to read: 285 286 | Field | Phishing tell | 287 |---|---| 288 | `notBefore` | Issued hours or days ago | 289 | Issuer | Free DV CA on a page impersonating a bank | 290 | Subject | `CN` is the lookalike domain, no organisation details | 291 | SAN list | Dozens of unrelated brand-ish hostnames on one cert | 292 293 Certificate Transparency is a free, passive early-warning source for lookalikes of a domain you own: 294 295 ```bash 296 # All certs ever issued for a domain and its subdomains, from CT logs 297 curl -s 'https://crt.sh/?q=%25.example.com&output=json' \ 298 | python3 -c 'import sys,json; [print(r["name_value"].replace("\n",","), r["not_before"]) for r in json.load(sys.stdin)]' \ 299 | sort -u | head -50 300 ``` 301 302 Search CT for brand permutations (`example-secure`, `examp1e`, `example-login`) to catch infrastructure before the campaign launches. 303 304 --- 305 306 ## 8. Safe Fetching of Page Content 307 308 Passive first. If you must fetch, do it from an isolated VM or a cloud sandbox, never your host. 309 310 ```bash 311 # Headers only, no body executed, short timeout, no cookies stored 312 curl -sI --max-time 10 -A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' 'https://evil-login.co/' 313 ``` 314 315 ```bash 316 # Fetch the raw HTML to a file for offline inspection, do not open it in a browser 317 curl -s --max-time 15 -A 'Mozilla/5.0' 'https://evil-login.co/' -o page.html 318 file page.html && wc -c page.html 319 ``` 320 321 ```bash 322 # Extract form targets, external scripts and iframes from the saved HTML 323 python3 - <<'PY' 324 import re 325 h = open("page.html", encoding="utf-8", errors="replace").read() 326 for label, pat in [("FORM ACTION", r'<form[^>]*action=["\']([^"\']+)'), 327 ("SCRIPT SRC", r'<script[^>]*src=["\']([^"\']+)'), 328 ("IFRAME SRC", r'<iframe[^>]*src=["\']([^"\']+)'), 329 ("INPUT NAME", r'<input[^>]*name=["\']([^"\']+)')]: 330 for m in sorted(set(re.findall(pat, h, re.I))): 331 print(f"{label}: {m}") 332 PY 333 ``` 334 335 > [!tip] The form `action` is the payoff. A login page whose form posts to an unrelated domain, a raw IP, a `.php` on cheap hosting, or a Telegram bot API endpoint is conclusive. 336 337 Server-side cloaking is standard, so a plain `curl` often returns a benign decoy. Attacker kits filter on User-Agent, `Referer`, geolocation, ASN (blocking known security vendors) and sometimes require the unique token from the original link. Getting a harmless page back does not clear the URL. 338 339 --- 340 341 ## 9. Landing Page Tells 342 343 Observed in an isolated VM, or from saved HTML. 344 345 - Form posts to a different domain than the one in the address bar. 346 - Credentials submitted, then a redirect to the real site's genuine login page, so the victim assumes a mistyped password. 347 - Password field with autocomplete disabled and no "forgot password" or account-creation flow that actually works. 348 - Requests for data the real service would never ask for together: password plus MFA code plus card number plus mother's maiden name. 349 - MFA relay kits (Evilginx, EvilProxy, Tycoon) proxy the real site live, so the page is pixel-perfect and the TLS is valid. The **domain** is your only reliable tell. 350 - Right-click, view-source or devtools disabled via JavaScript. 351 - Blocked or broken links for everything except the login form. 352 - Base64 or heavily obfuscated inline JavaScript that assembles the form at runtime. 353 - The brand logo hotlinked from the genuine CDN while everything else is local. 354 - Fake browser chrome drawn in HTML, a "browser in the browser" popup simulating an OAuth window. Try to drag it outside the page, a real window can leave, a fake one cannot. 355 - QR codes in the email body ("quishing") to move the click onto an unmanaged mobile device. Decode offline before scanning: 356 357 ```bash 358 uv pip install "qreader" opencv-python-headless 359 python3 -c 'import cv2; d=cv2.QRCodeDetector(); print(d.detectAndDecode(cv2.imread("qr.png"))[0])' 360 # or 361 zbarimg --quiet --raw qr.png 362 ``` 363 364 --- 365 366 ## 10. Attachment Triage 367 368 Static inspection only, in a VM, never double-click. 369 370 ```bash 371 file suspicious.* 372 sha256sum suspicious.* # hash first, then look it up rather than uploading 373 ``` 374 375 ```bash 376 # Office documents: check for macros and embedded objects 377 uv pip install oletools 378 olevba -a suspicious.docm 379 oleid suspicious.doc 380 ``` 381 382 ```bash 383 # PDFs: look for JavaScript, auto-actions and embedded launches 384 uv pip install pdfid pdf-parser 385 pdfid.py suspicious.pdf # /JS /JavaScript /OpenAction /Launch /EmbeddedFile counts 386 ``` 387 388 ```bash 389 # Archives: list contents without extracting, watch for double extensions and LNK/ISO/IMG 390 unzip -l suspicious.zip 391 7z l suspicious.iso 392 ``` 393 394 High-risk containers used to defeat mark-of-the-web: `.iso`, `.img`, `.vhd`, `.7z`, password-protected `.zip` with the password in the email body, `.lnk`, `.chm`, `.one`, `.svg` with embedded script, `.html` smuggling attachments that rebuild a payload client-side. 395 396 > [!warning] Hash first and search the hash. Uploading a targeted sample to a public multi-scanner makes it public and tips off the operator. 397 398 --- 399 400 ## 11. Reputation & Sandbox Services 401 402 | Service | Use | Notes | 403 |---|---|---| 404 | urlscan.io | Renders a URL, screenshots, DOM, request chain | **Set scan to private** for targeted phish. Public scans are searchable by anyone, including the attacker | 405 | VirusTotal | URL, domain, IP and file reputation | Search by hash before uploading. Uploads are shared with vendors | 406 | Hybrid Analysis / Joe Sandbox / ANY.RUN | Full detonation | Free tiers make results public | 407 | crt.sh | Certificate transparency search | Passive, free, no attacker contact | 408 | Shodan / Censys | Host and cert fingerprinting, pivot on kit artefacts | Passive | 409 | PhishTank / OpenPhish | Community phish feeds | Good for known campaigns, weak on fresh ones | 410 | Google Safe Browsing / Microsoft Defender SmartScreen | Browser-level blocklists | Lag of hours to days on new infra | 411 | Have I Been Pwned | Assess exposure after a credential submission | Post-incident | 412 413 Absence of detections means nothing on a domain registered this morning. Reputation feeds are lagging indicators. Registration age plus form target plus domain reading beat any single verdict. 414 415 --- 416 417 ## 12. Triage Workflow 418 419 ``` 420 1. PRESERVE Save the original .eml and the raw URL. Do not click anything. 421 2. PARSE Extract host, registrable domain, and every URL in the body. 422 3. READ DOMAIN Right to left. Decode punycode. Check for mixed scripts. 423 4. AGE IT whois creation date. Under ~30 days is a strong signal on its own. 424 5. AUTH SPF / DKIM / DMARC alignment against the claimed From: domain. 425 6. INFRA dig A/NS/MX, ASN owner, wildcard test, cert notBefore and issuer. 426 7. REPUTATION Hash and domain lookups. Passive sources first. 427 8. UNWRAP Resolve redirect chain with curl -sIL from an isolated host. 428 9. DETONATE Only if needed, in a VM or private urlscan. Note cloaking. 429 10. VERDICT Weight registration age + form target + domain reading above all else. 430 11. RESPOND Report, block, hunt for other recipients, rotate any exposed credentials. 431 ``` 432 433 If a credential was submitted, treat it as compromised immediately: change the password from a different device, revoke active sessions and refresh tokens (MFA relay kits steal the session cookie, so a password change alone is insufficient), re-enrol MFA, and check mailbox rules and OAuth app grants for attacker persistence. 434 435 --- 436 437 ## 13. Quick Reference Table 438 439 | Check | Command | 440 |---|---| 441 | Extract host from URL | `python3 -c 'import sys,urllib.parse as u;print(u.urlparse(sys.argv).hostname)' "$URL"` | 442 | Registrable domain | `python3 -c 'import tldextract,sys;print(tldextract.extract(sys.argv).registered_domain)' "$URL"` | 443 | Decode punycode | `python3 -c 'print("xn--...".encode().decode("idna"))'` | 444 | Redirect chain | `curl -sIL --max-redirs 10 "$URL" \| grep -Ei '^(HTTP/\|location:)'` | 445 | Domain age | `whois "$DOM" \| grep -Ei 'creation\|created'` | 446 | DNS records | `dig +short A "$DOM"; dig +short NS "$DOM"; dig +short MX "$DOM"` | 447 | Wildcard DNS test | `dig +short "$(openssl rand -hex 6).$DOM"` | 448 | Hosting owner | `whois "$(dig +short A "$DOM" \| head -1)" \| grep -Ei 'orgname\|netname'` | 449 | Cert details | `echo \| openssl s_client -connect "$DOM":443 -servername "$DOM" 2>/dev/null \| openssl x509 -noout -subject -issuer -dates` | 450 | CT log history | `curl -s "https://crt.sh/?q=%25.$DOM&output=json" \| jq -r '.[].name_value' \| sort -u` | 451 | SPF / DMARC published | `dig +short TXT "$DOM" \| grep -i spf; dig +short TXT "_dmarc.$DOM"` | 452 | Email auth verdicts | `grep -Ei '^(authentication-results\|received-spf\|from\|reply-to\|return-path):' sample.eml` | 453 | Save page HTML | `curl -s --max-time 15 -A 'Mozilla/5.0' "$URL" -o page.html` | 454 | Form targets | `grep -oEi '<form[^>]*action="[^"]+"' page.html` | 455 | Typosquat sweep | `dnstwist --registered --mx example.com` | 456 | File type + hash | `file f; sha256sum f` | 457 | Macro check | `olevba -a f.docm` | 458 | PDF actions | `pdfid.py f.pdf` | 459 | Decode QR | `zbarimg --quiet --raw qr.png` | 460 461 --- 462 463 ## 14. Reporting & Takedown 464 465 | Where | How | 466 |---|---| 467 | UK, general public | Forward the email to `report@phishing.gov.uk` (NCSC SERS). Suspicious texts to `7726` | 468 | UK, financial loss | Action Fraud, `actionfraud.police.uk` or 0300 123 2040. In Scotland, report to Police Scotland on 101 | 469 | Google Safe Browsing | `safebrowsing.google.com/safebrowsing/report_phish/` | 470 | Microsoft | `microsoft.com/wdsi/support/report-unsafe-site`, or the Report Phishing add-in | 471 | APWG | `reportphishing@apwg.org` | 472 | Hosting provider | `abuse@` for the ASN owner found via `whois <ip>` | 473 | Registrar | Abuse contact from `whois <domain>` | 474 | CDN in front of the site | Cloudflare and similar have their own abuse forms, they will pass to origin | 475 | Impersonated brand | Most banks and large SaaS publish a phishing reporting address | 476 477 Include the full URL, the original headers, timestamps with timezone, and the file hashes. Do not include live credentials. 478 479 --- 480 481 ## Related Notes 482 483 - Hashing cheat sheet 484 - pcap-credential-extraction-cheatsheet 485 - Forensics Cheatsheet 486 - GitHubDeviceCodePhishing 487 488 ## External References 489 490 - [NCSC — Phishing attacks: defending your organisation](https://www.ncsc.gov.uk/guidance/phishing) 491 - [RFC 7489 — DMARC](https://datatracker.ietf.org/doc/html/rfc7489) 492 - [Public Suffix List](https://publicsuffix.org/) 493 - [crt.sh — Certificate Transparency search](https://crt.sh/) 494 - [urlscan.io](https://urlscan.io/) 495 - [dnstwist](https://github.com/elceef/dnstwist) 496 - [oletools](https://github.com/decalage2/oletools)