← Back to writeups Infrastructure Defense

Scanner Detection & Honeypot Redirection

Identifying internet scanners by IP range and payload signature — then redirecting them transparently to a honeypot

// What is this?
Recognising automated internet probes by their source IP and fingerprint — then redirecting them to a decoy.

Internet scanners (Shodan, Censys, botnets) constantly sweep public IPs for open ports and vulnerable services. By analysing their source IP ranges and probe payloads, you can fingerprint them automatically. Instead of blocking them outright, redirect them transparently to a fake honeypot that looks vulnerable — gathering intelligence on what they're looking for while hiding your real services.

Bash — Scanner Detection
# Current inbound connections
ss -tnp | grep ESTAB | awk '{print $5}'

# Failed SSH attempts
sudo grep "Failed password" /var/log/auth.log | tail -20

# fail2ban status
sudo fail2ban-client status sshd

# Recent login attempts
last -20
who -a

# Listening services (attack surface)
ss -tlnp
If this flags: High volume of failed SSH = brute force. Check fail2ban bans. Listening services you don't recognize are backdoors. Use last for login history.

Internet scanners (Shodan, Censys, Infrawatch, Shadowserver) continuously probe every public IP on every port. For production infrastructure running non-standard services, this creates noise that obscures legitimate connection attempts and exposes service fingerprints. This writeup covers a detection and redirection system that identifies scanner probes, redirects them transparently to a honeypot listener, and alerts with enriched WHOIS context — while allowing legitimate connections through unchanged.

The Problem: You Can't Stop the Scan

Shodan scans the entire IPv4 address space in roughly 5 minutes. Censys completes a full scan in under an hour. These services are commercially operated, have static IP ranges, and do not honor robots.txt equivalents for network services. Firewall rules that block their ranges are effective but brittle — ranges change, and blocking by IP is reactive.

A more useful approach: let scanner probes connect, identify them, serve a response from a honeypot, and log everything — while simultaneously ensuring legitimate connections reach the real service unmodified.

Architecture

Scanner IP (Infrawatch, Shodan, Censys, etc.)
    │
    ▼
iptables PREROUTING REDIRECT
    │  (IP range match → redirect to honeypot port)
    ▼
Honeypot Listener
    │  Sends custom response, logs connection details
    ▼
Discord/Webhook Alert
    │  IP, scanner type, org name (WHOIS), timestamp
    ▼
Connection dropped

────────────────────────────

Legitimate IP (whitelisted)
    │
    ▼
Direct to service (unchanged)
    │
    ▼
Normal operation

Detection Methods

Two methods are used in combination. IP range matching is fast and catches known scanners. Payload signature matching catches unknown scanners that share characteristics with their vendor.

1. IP Range Matching

Each major scanner operates from a fixed or semi-fixed CIDR range. These ranges are publicly documented (Shodan publishes its own IP list; others are identified from scan data and WHOIS records).

ScannerPublished Ranges (sample)Detection Reliability
Shodan66.240.192.0/24, 71.6.135.0/24, 71.6.165.0/24, 185.142.236.0/24High — publishes ranges
Censys162.142.125.0/24, 167.94.138.0/24, 167.94.145.0/24, 167.94.146.0/24High — publishes ranges
Infrawatch5.226.140.0/24, 69.5.169.0/24, 89.37.172.128/27, 194.88.98.0/24Medium — ranges change
Shadowserver74.82.47.0/24, 184.105.139.0/24, 184.105.247.0/24High — nonprofit, documented
BinaryEdge37.19.221.0/24, 143.42.56.0/24Medium
Stretchoid198.96.95.0/24Medium
Palo Alto Networks198.235.24.0/24High — security research

2. Payload Signature Matching

Many scanners send identifiable strings in their initial probe or banner-grab payload. Matching on payload content catches scanners from IP ranges not yet in the blocklist.

# Known payload signatures (partial list)
SCANNER_SIGNATURES = {
    "Censys":      b"Censys",
    "Shodan":       b"masscan",
    "Stretchoid":  b"MGLNDD",     # Stretchoid fingerprint
    "zgrab":        b"zgrab",
    "nmap":         b"Nmap",
}

def identify_scanner(src_ip, payload):
    # Check IP ranges first (faster, no payload parse needed)
    for scanner, ranges in SCANNER_RANGES.items():
        for cidr in ranges:
            if ipaddress.ip_address(src_ip) in ipaddress.ip_network(cidr):
                return scanner
    # Fallback: payload signature match
    for scanner, sig in SCANNER_SIGNATURES.items():
        if sig in payload:
            return scanner
    return None

iptables Redirect Rules

When a scanner IP is identified, iptables PREROUTING REDIRECT transparently redirects all further connections from that IP to a honeypot port. The scanner receives a complete TCP handshake and a custom response — it appears to be a real service. The redirect happens before the packet reaches userspace, so the main service never sees it.

# Add scanner to redirect: map service port to honeypot port
# Real service on :8080 → honeypot on :18080
iptables -t nat -A PREROUTING \
    -s [SCANNER_IP] \
    -p tcp --dport [SERVICE_PORT] \
    -j REDIRECT --to-port [HONEYPOT_PORT]

# Verify rule applied
iptables -t nat -L PREROUTING -n | grep REDIRECT

# Existing TCP connections survive — redirect applies to new connections only
# Use --syn to restrict to SYN packets if needed

Whitelist rules are inserted at higher priority (-I instead of -A) and use ACCEPT to ensure legitimate IPs bypass the redirect. The whitelist check runs before any redirect rule.

Honeypot Listener

The honeypot listens on redirect ports and handles every incoming connection. For each connection: receive the probe payload, identify the scanner type, send a tailored response (a plausible service banner, an error, or a static response), log the full interaction, and alert.

import socket, threading, ipaddress, subprocess, requests

HONEYPOT_RESPONSES = {
    "Shodan":    b"SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6\r\n",
    "Censys":    b"HTTP/1.1 200 OK\r\nServer: nginx/1.24.0\r\n\r\n",
    "default":   b"Connection refused\r\n",
}

def handle_scanner(conn, addr):
    try:
        payload = conn.recv(1024)
        scanner_type = identify_scanner(addr[0], payload)
        response = HONEYPOT_RESPONSES.get(scanner_type, HONEYPOT_RESPONSES["default"])
        conn.send(response)
        whois_info = get_whois(addr[0])
        log_and_alert(addr[0], scanner_type, payload, whois_info)
    finally:
        conn.close()

def get_whois(ip):
    try:
        result = subprocess.run(["whois", ip], capture_output=True, text=True, timeout=5)
        for line in result.stdout.splitlines():
            if "OrgName" in line or "org-name" in line:
                return line.split(":")[1].strip()
    except: pass
    return "Unknown"

Auto-Detection of New Scanners

Known scanner ranges cover most probes, but new scanners and new IP ranges appear continuously. The auto-detector monitors incoming connections and applies heuristics to identify unknown scanners, automatically adding them to the redirect list.

Heuristics for auto-detection:

When the auto-detector identifies a probable scanner, it adds the IP to the redirect list and applies iptables rules immediately — before further probes reach the main service.

Alert Format

Each detected scanner generates a webhook alert with full context for triage. The alert includes the source IP, scanner classification, target port, WHOIS organization name, country, and the first 128 bytes of the probe payload.

# Alert payload (example — all fields populated from live detection)
{
  "scanner_ip":     "[SOURCE_IP]",
  "target_port":    8080,
  "scanner_type":   "Censys",
  "org":            "Censys, Inc.",
  "country":        "US",
  "action":         "redirected to honeypot",
  "probe_payload":  "[first 128 bytes, hex-escaped]",
  "timestamp":      "2026-08-29T14:32:11Z"
}

Operational Notes

What This Defends Against

Service fingerprinting: Scanners mapping exposed services by banner never reach the real service — they receive a controlled honeypot response. Your real service version and configuration stay unknown to scanner databases.

Reconnaissance visibility: Every probe is logged with timestamp, source IP, probe payload, and organization. This data is intelligence: attack surface exposure, which organizations are actively scanning, and whether specific IPs return repeatedly (targeted vs. broad scan).

Log noise reduction: Application-level logs stop being polluted by scanner traffic. Legitimate connection anomalies become visible against a clean baseline.

Limitations

Demo

ICMP packet capture: IP header decode showing scanner probe structure. NFQUEUE intercept classifying by source IP range.

MITRE ATT&CK (Defender): Detect T1595 (Active Scanning), T1592 (Gather Victim Host Information), T1046 (Network Service Discovery)