Analyzing M-SEARCH SSDP Flood: UPnP Discovery or Malware Activity?


2 views

The M-SEARCH packets you're seeing are part of the Simple Service Discovery Protocol (SSDP), which is used by Universal Plug and Play (UPnP) devices to discover each other on a local network. The key characteristics:

Destination IP: 239.255.255.250 (SSDP multicast address)
Destination Port: 1900
Protocol: HTTPU (HTTP over UDP)
Request Format: M-SEARCH * HTTP/1.1
Headers: MX, HOST, MAN, ST

While SSDP discovery is legitimate, the frequency you're observing (18-20 packets/sec) warrants investigation. Normal scenarios include:

  • New device joining the network
  • Network service scanning for UPnP devices
  • Media servers discovering renderers

Suspicious indicators would be:

// Example of suspicious pattern (pseudo-code)
while(true) {
    send_msearch("WANIPConnection:1");
    send_msearch("WANPPPConnection:1");
    sleep(50); // Continuous scanning
}

The Downadup/Conficker worm hypothesis is worth considering. Here's how to differentiate:

// Typical Conficker SSDP scan pattern
const char* targets[] = {
    "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
    "upnp:rootdevice",
    "urn:schemas-upnp-org:service:WANIPConnection:1",
    "urn:schemas-upnp-org:service:WANPPPConnection:1"
};

for(int i=0; i<4; i++) {
    send_ssdp_query(targets[i]);
}

Your case shows only WANIP/WANPPP queries, making Conficker less likely but not impossible - newer variants may have modified their scanning patterns.

At 20 packets/second, this generates:

Packets: 20 pps × 140 bytes = 2.8 KB/s
Bandwidth: Negligible for modern networks
Potential issues:
- Multicast traffic flooding (if switches don't filter properly)
- Increased CPU usage on UPnP devices
- Possible precursor to NAT tunneling attempts

For Linux-based detection using tcpdump:

#!/bin/bash
# Monitor SSDP traffic
tcpdump -i eth0 -nn -s 0 'udp port 1900' | grep "M-SEARCH" |
awk '{print $1,$3,$5,$6,$7,$8,$9,$10}'

Windows PowerShell equivalent:

Get-NetUDPEndpoint -LocalPort 1900 | 
Where-Object {$_.OwningProcess -ne ""} | 
ForEach-Object {Get-Process -Id $_.OwningProcess}

If you want to investigate further, here's how to check UPnP device responses:

import socket

def upnp_discover():
    M_SEARCH = """M-SEARCH * HTTP/1.1\r
HOST: 239.255.255.250:1900\r
MAN: "ssdp:discover"\r
MX: 3\r
ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n\r\n"""

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(5)
    sock.sendto(M_SEARCH.encode(), ('239.255.255.250', 1900))
    
    try:
        while True:
            data, addr = sock.recvfrom(1024)
            print(f"Response from {addr}:")
            print(data.decode())
    except socket.timeout:
        pass

When monitoring my apartment network via Wireshark, I observed sustained bursts of SSDP M-SEARCH requests (18-20 packets/sec) originating from another device. These UDP packets targeted port 1900 with the following characteristics:

M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: "ssdp:discover"
MX: 3
ST: urn:schemas-upnp-org:service:WANIPConnection:1

The observed behavior could stem from multiple sources:

  • Legitimate UPnP Devices: Smart TVs, game consoles, or IoT devices searching for routers/NAT services
  • Windows Services: Network discovery components in Windows OS
  • Malicious Activity: Potential worm propagation attempts (e.g., Downadup/Conficker)

To distinguish between normal and malicious traffic, I created a Python detection script:

from scapy.all import *

def detect_ssdp_abuse(pcap_file):
    pcap = rdpcap(pcap_file)
    sources = {}
    
    for pkt in pcap:
        if pkt.haslayer(UDP) and pkt.dport == 1900:
            if pkt.haslayer(Raw) and b'M-SEARCH' in pkt.load:
                src = pkt[IP].src
                st_field = re.search(b'ST: (.+?)\\r\\n', pkt.load)
                st = st_field.group(1).decode() if st_field else None
                
                if src not in sources:
                    sources[src] = {'count':0, 'STs':set()}
                sources[src]['count'] += 1
                if st: sources[src]['STs'].add(st)
    
    for src, data in sources.items():
        if data['count'] > 15:  # Threshold for excessive requests
            print(f"[!] Potential SSDP abuse from {src}")
            print(f"    Requests: {data['count']}, ST types: {data['STs']}")

detect_ssdp_abuse('network_capture.pcap')

The WANIPConnection:1 service type specifically targets NAT gateway devices, which could indicate:

  • UPnP-enabled applications trying to establish port mappings
  • Malware attempting NAT traversal for C2 communication
  • Network scanners probing for vulnerable routers

For developers encountering this issue:

# Linux iptables rule to limit SSDP requests
iptables -A INPUT -p udp --dport 1900 -m string --algo bm --string "M-SEARCH" \
         -m recent --set --name SSDP
iptables -A INPUT -p udp --dport 1900 -m string --algo bm --string "M-SEARCH" \
         -m recent --update --seconds 60 --hitcount 10 --name SSDP -j DROP

# Windows PowerShell command to disable SSDP service
Stop-Service -Name SSDPSRV -Force
Set-Service -Name SSDPSRV -StartupType Disabled

When investigating similar traffic:

  1. Correlate source MAC addresses with ARP tables
  2. Check for multiple ST types in rapid succession
  3. Monitor for subsequent NAT-PMP or PCP traffic
  4. Verify if responses contain LOCATION headers pointing to malicious URLs