ids_rules.txt
IDS/IPS Rules for Port Scan Detection
- detection
- text
- 343 lines
Run security tools only on systems you own or have written permission to test.
Source
# IDS/IPS Rules for Port Scan Detection# Location: 01-network-security/port-scanning/detection/ids_rules.txt## These rules can be used with Snort, Suricata, or other IDS/IPS systems# to detect various types of port scanning activities. ===============================================================================# SNORT RULES=============================================================================== # 1. TCP Connect Scan Detection------------------------------------------------------------------------------ # Detect multiple connection attempts to different portsalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN TCP Connect scan"; \ flow:stateless; detection_filter:track by_src, count 50, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000001; rev:1;) # Detect SYN scan (half-open)alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN SYN scan"; \ flags:S; flow:stateless; detection_filter:track by_src, count 30, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000002; rev:1;) # Detect FIN scanalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN FIN scan"; \ flags:F; flow:stateless; detection_filter:track by_src, count 20, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000003; rev:1;) # Detect NULL scanalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN NULL scan"; \ flags:0; flow:stateless; detection_filter:track by_src, count 20, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000004; rev:1;) # Detect XMAS scan (FIN+PSH+URG)alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN XMAS scan"; \ flags:FPU; flow:stateless; detection_filter:track by_src, count 20, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000005; rev:1;) # Detect ACK scan (firewall mapping)alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN ACK scan"; \ flags:A; flow:stateless; detection_filter:track by_src, count 50, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000006; rev:1;) # 2. UDP Scan Detection------------------------------------------------------------------------------ # Detect UDP port scanningalert udp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN UDP scan"; \ detection_filter:track by_src, count 20, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000007; rev:1;) # Detect UDP scan via ICMP unreachable responsesalert icmp $HOME_NET any -> $EXTERNAL_NET any (msg:"PORT-SCAN UDP scan response"; \ icode:3; itype:3; detection_filter:track by_dst, count 10, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000008; rev:1;) # 3. Advanced Scan Detection------------------------------------------------------------------------------ # Detect sequential port scanningalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Sequential port scan"; \ flow:stateless; threshold:type both, track by_src, count 20, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000009; rev:1;) # Detect port sweep (same port on multiple hosts)alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (msg:"PORT-SCAN HTTP port sweep"; \ flags:S; threshold:type both, track by_src, count 10, seconds 5; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000010; rev:1;) # Detect fragmented scan packetsalert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Fragmented scan"; \ fragbits:M; detection_filter:track by_src, count 20, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000011; rev:1;) # 4. Service-Specific Scan Detection------------------------------------------------------------------------------ # SSH port scanningalert tcp $EXTERNAL_NET any -> $HOME_NET 22 (msg:"PORT-SCAN SSH port scan"; \ flags:S; threshold:type both, track by_src, count 10, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000012; rev:1;) # Web server scanningalert tcp $EXTERNAL_NET any -> $HOME_NET [80,443] (msg:"PORT-SCAN Web server scan"; \ flags:S; threshold:type both, track by_src, count 20, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000013; rev:1;) # Database scanningalert tcp $EXTERNAL_NET any -> $HOME_NET [3306,5432,1433] (msg:"PORT-SCAN Database scan"; \ flags:S; threshold:type both, track by_src, count 5, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000014; rev:1;) # Mail server scanningalert tcp $EXTERNAL_NET any -> $HOME_NET [25,110,143,993,995] (msg:"PORT-SCAN Mail server scan"; \ flags:S; threshold:type both, track by_src, count 10, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000015; rev:1;) # FTP scanningalert tcp $EXTERNAL_NET any -> $HOME_NET [20,21] (msg:"PORT-SCAN FTP scan"; \ flags:S; threshold:type both, track by_src, count 5, seconds 10; \ reference:url,www.snort.org/rules/port-scan; \ classtype:attempted-recon; sid:1000016; rev:1;) # 5. Nmap Detection Signatures------------------------------------------------------------------------------ # Detect Nmap TCP scanalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Nmap TCP scan"; \ content:"Nmap"; depth:4; http_header; \ reference:url,nmap.org; classtype:attempted-recon; sid:1000017; rev:1;) # Detect Nmap OS fingerprintingalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Nmap OS fingerprint"; \ flags:SF; seq:123456789; window:1024; \ reference:url,nmap.org; classtype:attempted-recon; sid:1000018; rev:1;) # Detect Nmap idle scan (zombie scan)alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Nmap idle scan"; \ ip_id:0; fragbits:M; detection_filter:track by_src, count 10, seconds 5; \ reference:url,nmap.org; classtype:attempted-recon; sid:1000019; rev:1;) # 6. Masscan Detection------------------------------------------------------------------------------ # Detect Masscan high-speed scanningalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Masscan detected"; \ flow:stateless; threshold:type both, track by_src, count 100, seconds 1; \ reference:url,github.com/robertdavidgraham/masscan; \ classtype:attempted-recon; sid:1000020; rev:1;) # 7. Zmap Detection------------------------------------------------------------------------------ # Detect Zmap internet-wide scanningalert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Zmap detected"; \ ttl:<64; threshold:type both, track by_src, count 1000, seconds 1; \ reference:url,zmap.io; classtype:attempted-recon; sid:1000021; rev:1;) ===============================================================================# SURICATA RULES (Enhanced)=============================================================================== # 1. Rate-based detection using flowbit------------------------------------------------------------------------------ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Rate-based detection"; \ flow:stateless; flags:S; \ flowbits:set,scan.scanner; \ detection_filter:track by_src, count 100, seconds 10; \ classtype:attempted-recon; sid:2000001; rev:1;) # 2. Portscan detection using threshold------------------------------------------------------------------------------ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Portscan threshold"; \ flags:S; threshold:type threshold, track by_src, count 50, seconds 10; \ classtype:attempted-recon; sid:2000002; rev:1;) # 3. Distributed portscan detection------------------------------------------------------------------------------ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PORT-SCAN Distributed portscan"; \ flags:S; threshold:type both, track by_dst, count 100, seconds 10; \ classtype:attempted-recon; sid:2000003; rev:1;) ===============================================================================# FAIL2BAN CONFIGURATION=============================================================================== # /etc/fail2ban/jail.local [port-scan]enabled = trueport = allfilter = port-scanlogpath = /var/log/syslog /var/log/auth.log /var/log/nginx/access.logmaxretry = 20bantime = 3600findtime = 60action = iptables[name=port-scan, port=all, protocol=tcp] # Custom filter for port scan detection# /etc/fail2ban/filter.d/port-scan.conf [Definition]failregex = ^.*Possible port scan from <HOST>.*$ ^.*Scan detected from <HOST>.*$ ^.*Connection attempt from <HOST> to port \d+.*$ ^.*<HOST>.*connected to \d+ different ports.*$ignoreregex = ===============================================================================# OSSEC RULES=============================================================================== <!-- /var/ossec/rules/local_rules.xml --> <group name="port-scan,"> <!-- Port scan detection --> <rule id="100001" level="7"> <if_sid>5710</if_sid> <match>^Possible port scan</match> <description>Possible port scan detected</description> <group>recon,port_scan,</group> </rule> <!-- Multiple connection attempts --> <rule id="100002" level="8"> <if_sid>5712</if_sid> <match>multiple connection attempts</match> <description>Multiple connection attempts from same source</description> <group>recon,port_scan,</group> </rule> <!-- SYN scan detection --> <rule id="100003" level="9"> <if_sid>5715</if_sid> <match>SYN scan</match> <description>SYN scan detected</description> <group>recon,port_scan,</group> </rule></group> ===============================================================================# CUSTOM PYTHON DETECTION SCRIPT (for integration)=============================================================================== # save as: port_scan_honeypot.py """import socketimport threadingfrom collections import defaultdictimport time class PortHoneypot: def __init__(self, ports=[22,80,443,3306,5432]): self.ports = ports self.scanners = defaultdict(int) def start_honeypot(self): for port in self.ports: thread = threading.Thread(target=self.listen_port, args=(port,)) thread.daemon = True thread.start() def listen_port(self, port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('0.0.0.0', port)) sock.listen(5) while True: client, addr = sock.accept() self.scanners[addr[0]] += 1 client.close() if self.scanners[addr[0]] > 10: print(f"Port scan detected from {addr[0]}") # Alert IDS/IPS here honeypot = PortHoneypot()honeypot.start_honeypot()""" ===============================================================================# ELASTICSEARCH / KIBANA DETECTION=============================================================================== # Elasticsearch query for port scan detection"""{ "query": { "bool": { "must": [ { "term": { "network.protocol": "tcp" } }, { "range": { "@timestamp": { "gte": "now-1m" } } } ] } }, "aggs": { "scanners": { "terms": { "field": "source.ip", "size": 100 }, "aggs": { "unique_ports": { "cardinality": { "field": "destination.port" } } } } }}""" ===============================================================================# IMPORTANT NOTES=============================================================================== 1. **TUNING** - Adjust thresholds based on normal network traffic - Whitelist trusted scanners (monitoring tools) - Consider time of day variations 2. **FALSE POSITIVES** - legitimate services (NTP, DNS) may trigger alerts - CDN services appear as multiple connections - Load balancers show as single IP to many ports 3. **RESPONSE ACTIONS** - Log all scan attempts - Rate limit suspicious IPs - Block persistent scanners - Notify security team 4. **COMPLIANCE** - PCI DSS requirement 11.4 - ISO 27001 A.12.6.1 - NIST SP 800-53 5. **INTEGRATION** - Feed alerts to SIEM - Correlate with other events - Automate response where appropriate ===============================================================================# END OF RULES===============================================================================