├── .gitattributes ├── .gitignore ├── README.md ├── iptables └── local.rules /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must end with two \r 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Snort-DNS 2 | ========= 3 | 4 | Snort rules to detect local malware, phishing, and adult content by inspecting DNS responses from OpenDNS 5 | 6 | I use OpenDNS Family Shield as my domain name service. It's an effective way of minimizing one popular avenue of infection and phishing attacks. DNS is bit like a phone book: it translates human-friendly website names into computer-friendly network addresses. OpenDNS takes advantage of this to provide a layer of protection: for most websites, it will tell my computer the real network address, but for domains known to host malware, phishing attacks, or adult content, OpenDNS instead gives the network address of a page with a warning message. 7 | 8 | This project takes advantage of this fact. The local.rules file contains a set of Snort rules that identify DNS responses (packets from udp port 53 destined for a device on the local network), then inspects the payload. If the payload includes one of OpenDNS' blocked content landing pages, the rule will fire an alert. 9 | 10 | For more details on how this works, and suggested improvements, see https://securityforrealpeople.com/snort-dns 11 | 12 | 1. The alert tells me the IP address of the offending computer or device, but not the domain name that was requested. I have Snort configured to store each packet that triggered an alert, and can use tcpdump to analyse the packets - but that's a bit of a pain. Do any readers know of a way to include payload fields from a DNS packet in the alert message? 13 | 14 | 2. I've identified 4 specific "warning page" DNS responses, but OpenDNS owns far more addresses that they may use for other conditions now or in the future. At a minimum, OpenDNS owns the ranges 67.215.64.0/19 and 204.194.232.0/21 -- all told, about 10,000 addresses. * Note: OpenDNS recently changed the landing pages for blocked content; the new IP addresses are documented at https://support.opendns.com/entries/69715954-What-are-the-OpenDNS-Block-Page-IP-Addresses- * Snort supports matching IP ranges in CIDR notation for the source and destination, but my approach currently does a binary match in the payload. Do any readers have an example of a Snort rule that parses DNS packets into their component fields? 15 | 16 | As a side note, I have added an **iptables** file to this folder; it contains sample rules to permit DNS traffic only to a preferred destination, and deny any DNS lookups elsewhere. Update the command line with your private network address and your preferred DNS server, then run it on the WiFi router serving as your gateway to ensure DNS-manipulating malware cannot send your browser somewhere the user did not intend. 17 | -------------------------------------------------------------------------------- /iptables: -------------------------------------------------------------------------------- 1 | # All rules use -C to check for existing rule, then -A only if the rule does not already exist. Avoids duplicating the same rule. 2 | # mirror all traffic to snort 3 | # replace s.s.s.s with IP address of your snort listener 4 | iptables -t mangle -C POSTROUTING -j ROUTE --tee --gw s.s.s.s || iptables -t mangle -A POSTROUTING -j ROUTE --tee --gw s.s.s.s 5 | 6 | # allow DNS to/from all for test boxes only, else to OpenDNS only 7 | # The below order is important as it inserts the allow rules to be processed before the deny rule 8 | # replace x.x.x.x/24 with your private network range 9 | # replace y.y.y.y with your router's default gateway or internal DNS server 10 | # replace z.z.z.z with one or more hosts for which to allow other DNS destinations 11 | iptables -C FORWARD -p udp --dport 53 -j DROP || iptables -I FORWARD -p udp --dport 53 -j DROP 12 | iptables -C FORWARD -d 208.67.220.0/22 -p udp --dport 53 -j ACCEPT || iptables -I FORWARD -d 208.67.220.0/22 -p udp --dport 53 -j ACCEPT 13 | iptables -C FORWARD -s x.x.x.x/24 -d y.y.y.y -p udp --dport 53 -j ACCEPT || iptables -I FORWARD -s x.x.x.x/24 -d y.y.y.y -p udp --dport 53 -j ACCEPT 14 | iptables -C FORWARD -s z.z.z.z -p udp --dport 53 -j ACCEPT || iptables -I FORWARD -s z.z.z.z -p udp --dport 53 -j ACCEPT 15 | -------------------------------------------------------------------------------- /local.rules: -------------------------------------------------------------------------------- 1 | # $Id: local.rules,v 1.11 2004/07/23 20:15:44 bmc Exp $ 2 | # ---------------- 3 | # LOCAL RULES 4 | # ---------------- 5 | # This file intentionally does not come with signatures. Put your local 6 | # additions here. 7 | 8 | var DNS_IPS [208.67.222.222,208.67.220.220,208.67.222.123] 9 | 10 | # Permit alternate DNS from my research box, then alert on DNS queries from anything else 11 | pass udp x.x.x.x any <> any 53 (msg:"Allow alternate DNS from test box"; sid:10000001; rev:001;) 12 | alert udp $HOME_NET any -> ![$HOME_NET,$DNS_IPS] 53 (msg:"DNS request not to OpenDNS"; sid:10000002; rev:001;) 13 | 14 | # Alert on DNS request for known phishing: OpenDNS response is |92 70 3D 6C| = 146.112.61.108 15 | alert udp any 53 -> $HOME_NET any (msg:"DNS request for phish"; sid:10000003; rev:001; content:"|92 70 3D 6C|";) 16 | 17 | # Alert on DNS request for blocked content: OpenDNS response is |92 70 3D 6A| = 146.112.61.106 18 | alert udp any 53 -> $HOME_NET any (msg:"DNS request for blocked content"; sid:10000004; rev:001; content:"|43 D7 41 82|";) 19 | 20 | # Alert on DNS request for known malware: OpenDNS responses are |92 70 3D 69| = 146.112.61.105; |92 70 3D 6B| = 146.112.61.107 21 | alert udp any 53 -> $HOME_NET any (msg:"DNS request for botnet content"; sid:10000005; rev:001; content:"|92 70 3D 69|";) 22 | alert udp any 53 -> $HOME_NET any (msg:"DNS request for malicious content"; sid:10000006; rev:001; content:"|92 70 3D 6B|";) 23 | 24 | # Log any other DNS packets in tcpdump format while testing 25 | log udp any 53 <> $HOME_NET any (sid:10000007; rev:001;) 26 | --------------------------------------------------------------------------------