Created
May 21, 2015 09:02
-
-
Save hyperair/01a4f58d50a09e4ba0a6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/python3 | |
| import argparse | |
| import re | |
| import requests | |
| import sys | |
| ip_regex = re.compile(r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}' | |
| '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)') | |
| domain_regex = re.compile(r'(?:\*\.)?([A-Za-z0-9][-A-Za-z0-9]{0,253}[A-Za-z0-9]+' | |
| '(?:\\.[A-Za-z0-9][-A-Za-z0-9]{0,253}[A-Za-z0-9]+)+)') | |
| templates = { | |
| 'cisco': { | |
| 'ip': "alert ip any any <> {ip} any (msg:\"Traffic to known bad IP {ip})\"; {ref} sid:{sid}; rev:0;)\n", | |
| 'domain': "alert udp any any -> any 53 (msg:\"Suspicious DNS lookup for {domainname}\"; {ref} content:\"|01 00 00 01 00 00 00 00 00 00|\"; depth: 10; offset: 2; content:\"{dnslookup}\"; nocase; distance:0; sid:{sid}; rev:0;)\n", | |
| }, | |
| 'snort': { | |
| 'ip': '''signatures {sid} 0 | |
| alert-severity high | |
| sig-fidelity-rating 100 | |
| sig-description | |
| sig-name Traffic to known bad IP - {ip} | |
| sig-string-info {ref} | |
| exit | |
| engine atomic-ip | |
| event-action produce-alert|produce-verbose-alert|log-attacker-packets | |
| fragment-status any | |
| specify-l4-protocol no | |
| specify-ip-addr-options yes | |
| ip-addr-options ip-addr | |
| specify-src-ip-addr yes | |
| src-ip-addr 0.0.0.0-255.255.255.255 | |
| exit | |
| specify-dst-ip-addr yes | |
| dst-ip-addr {ip} | |
| exit | |
| exit | |
| exit | |
| exit | |
| event-counter | |
| event-count 1 | |
| exit | |
| status | |
| enabled true | |
| retired false | |
| exit | |
| exit | |
| ''', | |
| 'domain': '''signatures {sid} 0 | |
| sig-description | |
| sig-name Suspicious DNS lookup for {domainname} | |
| sig-string-info {ref} | |
| no sig-comment | |
| exit | |
| engine string-udp | |
| regex-string \\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00.*{dnslookup} | |
| service-ports 53 | |
| specify-exact-match-offset yes | |
| exact-match-offset 2 | |
| exit | |
| exit | |
| status | |
| enabled true | |
| retired false | |
| exit | |
| exit | |
| ''' | |
| }, | |
| } | |
| def parse_arguments(): | |
| parser = argparse.ArgumentParser() | |
| input_group = parser.add_mutually_exclusive_group() | |
| input_group.add_argument( | |
| '--file', | |
| metavar='LOCAL_FILE', | |
| help=('A file stored locally that contains a list of malicious ' | |
| 'domains, IP addresses and/or URLs. If omitted then it assumed ' | |
| 'that a URL is provided.')) | |
| input_group.add_argument( | |
| '--url', | |
| default=('https://zeustracker.abuse.ch/blocklist.php?' | |
| 'download=domainblocklist'), | |
| help=('A URL that contains a list of malicious domains, IP addresses ' | |
| 'or URLs. The default is ' | |
| 'https://zeustracker.abuse.ch/blocklist.php?download=' | |
| 'domainblocklist.')) | |
| parser.add_argument( | |
| '--csv', | |
| metavar='FIELD_NUM', | |
| type=int, | |
| help=('The field number (indexing from 0) that contains the ' | |
| 'information of interest. If omitted then the file is treated ' | |
| 'as a simple list.')) | |
| parser.add_argument( | |
| '--sid', | |
| default=9000000, | |
| help=('The SID that will be applied to the first rule. Every ' | |
| 'subsequent rule will increment the SID value. The default is ' | |
| '9000000 for Snort and 60000 for Cisco.')) | |
| parser.add_argument( | |
| '--ids', | |
| default='snort', | |
| type=lambda s: s.lower(), # we want it lowercase | |
| choices=('cisco', 'snort')) | |
| return parser.parse_args() | |
| def get_lines(args): | |
| if args.file: | |
| with open(args.file) as f: | |
| lines = f.read().splitlines() | |
| ref = '' | |
| else: | |
| try: | |
| content = requests.get(args.url).text | |
| except: | |
| sys.stderr.write("Couldn't get {0}\n".format(args.url)) | |
| raise | |
| lines = re.split(r'\r?\n', content) | |
| ref = 'reference:url,{0}'.format(args.url) | |
| return ref, lines | |
| def main(): | |
| args = parse_arguments() | |
| sid = args.sid | |
| if args.ids == 'cisco' and sid == 9000000: | |
| sid = 60000 | |
| ref, lines = get_lines(args) | |
| line_templates = templates[args.ids] | |
| for line in lines: | |
| if args.csv is not None: | |
| fields = line.split(',', args.csv + 1) | |
| fields.replace('"', '') | |
| # check for IP address match | |
| match = ip_regex.search(line) | |
| if match is not None: | |
| ip = match.group(0) | |
| print(line_templates['ip'].format(**locals())) | |
| sid += 1 | |
| continue | |
| # else check for domain match | |
| match = domain_regex.search(line) | |
| if match is not None: | |
| domainname = match.group(0) | |
| domains = domainname.split('.') | |
| dnslookup = ''.join( | |
| '|%.2x|%s' % (len(domain), domain) | |
| for domain in domains | |
| ) | |
| print(line_templates['domain'].format(**locals())) | |
| sid += 1 | |
| continue | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment