Skip to content

Instantly share code, notes, and snippets.

@hyperair
Created May 21, 2015 09:02
Show Gist options
  • Select an option

  • Save hyperair/01a4f58d50a09e4ba0a6 to your computer and use it in GitHub Desktop.

Select an option

Save hyperair/01a4f58d50a09e4ba0a6 to your computer and use it in GitHub Desktop.
#!/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