Chapter 68

Phishing Infrastructure

Phishing attacks generate network events before, during, and after the click: SMTP delivery events (inbound email), DNS resolution of the phishing domain, HTTP/TLS connections to the phishing site, and credential submission (HTTP POST). Each phase is observable from network telemetry. Detecting phishing infrastructure proactively — before users click — is possible by analyzing newly registered domains, freshly issued certificates, and lookalike domain patterns in DNS logs.

Scenario

An employee receives a phishing email purporting to be from IT: "Your Microsoft 365 password expires in 24 hours." The link goes to microsоft-login.com (note: Cyrillic 'о'). Zeek's DNS log shows the employee's workstation resolving this domain at 09:14 AM. The SSL log shows a TLS connection to the same IP with a Let's Encrypt certificate issued 3 days ago. An http.log entry shows a POST to /login.php 90 seconds later — credential submission confirmed.

Phishing Network Evidence Chain

  Phishing Attack Network Evidence Chain
  ═══════════════════════════════════════════════════════════════════

  Step 1 — Email delivery (SMTP logs):
  └── smtp.log or email gateway logs:
        From: help@microsоft-login.com (lookalike domain)
        Reply-To: attacker@gmail.com (mismatch → phishing indicator)
        Received: from 185.x.x.x (bulletproof host)
        No DKIM signature / DMARC fail

  Step 2 — User clicks link (DNS + TLS):
  └── dns.log: victim_workstation → microsоft-login.com → 185.1.2.3
  └── ssl.log: TLS to 185.1.2.3:443
        SNI = microsоft-login.com
        Issuer = Let's Encrypt (automatically issued to any domain)
        Issued 3 days ago (newly registered, short validity period)
        JA3 of browser (normal, not C2)

  Step 3 — Credential submission (HTTP):
  └── http.log:
        POST /login.php HTTP/1.1
        Host: microsоft-login.com
        Content-Length: 87 (small POST = credentials)
        Response: 302 Redirect (to real microsoft.com after theft)

  Step 4 — Post-compromise (if AiTM):
  └── After credential capture, session cookies also harvested
  └── Attacker logs into M365 from their IP (not visible in internal traffic)
  └── Only Microsoft Entra/audit logs would show this

  Proactive detection (before user clicks):
  └── Newly registered lookalike domains in DNS passive data
  └── Fresh TLS certificate for lookalike domain (cert transparency)
  └── SMTP delivery from domain with no MX history

Phishing Detection Queries

bashphishing-detection.sh
#!/bin/bash
LOG_DIR="${1:-/opt/zeek/logs/current}"

echo "=== Step 1: Find DNS queries to lookalike domains ==="
# Lookalike patterns: homoglyphs, typosquats, brand+login.com, etc.
BRAND_KEYWORDS="microsoft|office365|onedrive|paypal|chase|wellsfargo|amazon|apple"
awk 'NR>8 && !/^#/' "$LOG_DIR/dns.log" | \
  awk -F'\t' '$10 == "1" {print $9}' | \  # A records only
  sort -u | \
  python3 -c "
import sys, re

# Load brand keywords
brands = 'microsoft|office365|onedrive|paypal|chase|wellsfargo|amazon|apple'
brand_re = re.compile(brands, re.IGNORECASE)

# Known-legitimate domains (very incomplete — use a full allowlist in production)
LEGIT = {
    'microsoft.com', 'live.com', 'office.com', 'microsoftonline.com',
    'paypal.com', 'chase.com', 'amazon.com', 'apple.com',
}

for domain in sys.stdin:
    domain = domain.strip()
    if not domain: continue
    # Skip if exactly a known-good domain or subdomain of one
    if any(domain == l or domain.endswith('.'+l) for l in LEGIT):
        continue
    # Alert if it contains a brand keyword but isn't the legit domain
    if brand_re.search(domain):
        print(f'LOOKALIKE: {domain}')
" | head -30

echo ""
echo "=== Step 2: TLS to fresh Let's Encrypt cert (newly phishing infra) ==="
awk 'NR>8 && !/^#/' "$LOG_DIR/ssl.log" | \
  awk -F'\t' '$12 ~ /Let.s Encrypt/ || $12 ~ /letsencrypt/ {print $1"\t"$3"\t"$5"\t"$8"\t"$13"\t"$14}' | \
  head -20

echo ""
echo "=== Step 3: HTTP POST from internal hosts to external on port 443 (cred submission) ==="
awk 'NR>8 && !/^#/' "$LOG_DIR/http.log" 2>/dev/null | \
  awk -F'\t' '
    $7 == "POST" &&
    $5 !~ /^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/ &&
    $9+0 < 1000 {  # small POST body = likely credentials
      print $1"\t"$3"\t"$5"\t"$6"\t"$7
    }' | head -20

echo ""
echo "=== SMTP: email from external domain with Reply-To mismatch ==="
awk 'NR>8 && !/^#/' "$LOG_DIR/smtp.log" 2>/dev/null | \
  awk -F'\t' '
    NF > 10 {
      from = $7; replyto = $8; rcpt = $9
      # Simple heuristic: From domain != Reply-To domain
      split(from, a, "@"); split(replyto, b, "@")
      if (a[2] != "" && b[2] != "" && a[2] != b[2])
        print "FROM_REPLYTO_MISMATCH from=" from " replyto=" replyto
    }' | head -10
Mental model: phishing is a credential transport problem — the network is the evidence

When an employee submits credentials to a phishing page, the credentials travel over the network twice: once in the HTTP POST to the phishing server (observable as a small outbound POST to an unusual external destination), and once when the attacker uses those credentials from their infrastructure (visible in authentication logs, but not in your internal network). The network forensics value in a phishing investigation is reconstructing the credential submission event — when it happened, which workstation, which phishing site — to determine the scope of credential exposure and prioritize password resets. The post-click traffic (DNS resolution + TLS connection + HTTP POST) is typically observable in Zeek logs, and the combination of the three log types gives you a complete picture of which accounts were likely compromised, even before any fraudulent activity occurs with those credentials.

Q & A

Q: How do Adversary-in-the-Middle (AiTM) phishing attacks differ from traditional phishing in network traffic?

AiTM phishing (used by tools like Evilginx, Modlishka) acts as a transparent proxy between the victim and the legitimate site. The victim's traffic goes: browser → phishing proxy → real microsoft.com. From the network perspective inside the victim's organization: (1) The DNS query resolves a lookalike domain (same as traditional phishing). (2) The TLS connection goes to the phishing proxy, not Microsoft — same indicators as before: Let's Encrypt cert, recently issued, lookalike domain in SNI. (3) The HTTP traffic: unlike traditional phishing (which serves a fake login page), AiTM relays the real Microsoft login page content — so the HTTP response looks legitimate. (4) What AiTM adds: the attacker intercepts the session cookie after successful authentication. The victim successfully logs into their real M365 account. The network observable difference is subtle: the POST to the proxy is redirected to the real Microsoft, so the session follows through — you might see a 302 redirect chain that terminates at microsoft.com. (5) Post-compromise detection: the attacker uses the stolen session cookie from a different IP. Observable in Azure AD/Entra sign-in logs (not internal network): same user session from two different IPs simultaneously. AiTM makes network-only detection harder — you need combined SMTP + DNS + TLS + authentication log analysis.