# Version 1.0
##Imports##
#Argparse for fancy cli args
#textwrap for a fancy help/description output
#datetime for "created_at" timestamp metadata

import argparse
import datetime
import re
import textwrap

#Initialize argparse and print the big description and help usage block if -h or --help is used

parser = argparse.ArgumentParser(
    formatter_class=argparse.RawDescriptionHelpFormatter,
    description=textwrap.dedent('''
                    dns2suri.py
                Brought to you by:
                    @da_667
                With Special Thanks from:
                    @botnet_hunter
                     @3XPlo1T2
                ---------------------
Generates suricata DNS rules from a list of domains.
Usage: dns2suri.py [-w] -i <infile> -o <outfile> -s 1000000
Infile format:
www.evil.com
Outfile format:
alert dns $HOME_NET any -> $EXTERNAL_NET any (msg:"Suspicious DNS Lookup (www.evil.com)"; dns.query; content:"www.evil.com"; nocase; bsize:12; classtype:misc-activity; sid:1000000; rev:1; metadata: created_at 2022_22_02, deployment Perimeter;)
'''))

#Infile, outfile, and sid arguments via ArgParse are all required.

parser.add_argument('-i', dest="infile", required=True,
                    help="The name of the file containing a list of Domains, One domain per line.")
parser.add_argument('-o', dest="outfile", required=True, help="The name of the file to output your suricata rules to.")
parser.add_argument('-s', dest="sid", type=int, required=True,
                    help="The suricata sid to start numbering incrementally at. This number should be between 1000000-1999999")
parser.add_argument('-w', dest="www", required=False, action='store_true', help="Remove the 'www' subdomain from domains that have it. This will apply the \"dotprefix;\" AND \"endswith;\" modifiers to all domains beginning with \"www\"")
args = parser.parse_args()

#This is a small check to ensure -s is set to a valid value between 1000000-1999999 - the local rules range according to https://sidallocation.org/

if args.sid < 1000000:
    print ("The Value for sid (-s) is less than 1000000.")
    exit()
elif args.sid > 1999999:
    print ("The Value for sid (-s) is greater than 1999999.")
    exit()

#use datetime to establish the current year, month, and date for the created_at rule metadata
now = datetime.date.today()
ts_createdat = now.strftime("%Y_%m_%d")

#fout is the file we will be outputting our rules to.
#f is the file we will read a list of domains from.
#This script iterates through each line (via for line loop).
#If the line is empty or contains an octothorpe (#) ignore it.
#If there is deadspace on the line that could cause problems with the suricata rule, strip it out.
#For the msg portion of the rule, use the re module to insert a space in front of each period for the domain, in order to "sanitize" the message the alert produces to not cause more false positives on accident.
#If the user invoked the -w option, strip out the 'www' portion of the domain they specified. 
#We generate one of two types of rules, depending on if the first character of the domain begins with a period (.)
#The first type of rule utilizes dotprefix and endswith to hunt for any subdomains of the domain specified.
#The second type of rule does an exact content match, and uses bsize to ensure that ONLY that domain matches the rule.

with open(args.outfile, 'w') as fout:
    with open(args.infile, 'r') as f:
        for line in f:
            if line.strip():
                domain = line.strip()
                if domain.startswith('#'):
                    continue
                if args.www == True: 
                    domain = re.sub('^www', '', domain, flags=re.IGNORECASE)
                msg = re.sub('\.', '.', domain)
                if domain.startswith('.'):
                    rule = ("alert dns $HOME_NET any -> $EXTERNAL_NET any (msg:\"Suspicious DNS Lookup (%s)\"; dns.query; dotprefix; content:\"%s\"; nocase; endswith; classtype:misc-activity; sid:%s; rev:1; metadata: created_at %s, deployment Perimeter;)" % (msg, domain, args.sid, ts_createdat))
                else:
                    rule = ("alert dns $HOME_NET any -> $EXTERNAL_NET any (msg:\"Suspicious DNS Lookup (%s)\"; dns.query; content:\"%s\"; nocase; bsize:%s; classtype:misc-activity; sid:%s; rev:1; metadata: created_at %s, deployment Perimeter;)" % (msg, domain, len(domain), args.sid, ts_createdat))
                fout.write(rule)
                print (rule)
                args.sid += 1
exit()You’re Drowning in Data — Now What?
Too often companies complete a large data collection project, then when nothing happens wonder what all the fuss was about.
Here are three concrete actions your business can take to avoid this fate.
A good mental model for the data is the encyclopedia. Encyclopedias have millions of entries. Generally, you only care about one or two at a time. So it goes with your new data set. It has millions of entries, which track everything your team could think of. At some point in the future you will need some of that data. The catch is you don’t know which part.
X can be anything from how you display customer journeys to product lifecycles. Is there an area in your operations where decisions are haphazard or ill-informed? Hopefully the new data set provides you the opportunity to dig deeper.
An inventive example of this I observed occurred in a call center. The center transformed the customer data from the multiple screens agents had to wade through to understand the customer’s needs to a single graphical display that instantly provided a picture of the customer’s behaviors and likely wants.
Have a pet theory about how to improve your business? Now is the time to explore. New data sets are wonderful because they provide opportunities for discovery ahead of the competition.
A fresh data set is far more exciting for data scientists than an existing one. Chances are the existing data set has been picked over already and the most impactful insights have already been gleaned.
Collecting data provides a foundation for more informed decisions. However, it is just the foundation. Once collected, the data still needs to be converted to information that can be understood and acted upon.
Nothing says I love you like supplanting your identity with that of your spouse, apparently. This week Cheryl Cole (nee Tweedy), the beautiful and highly successful member of UK pop group Girls Aloud, wowed onlookers by revealing a tattoo across the nape of her neck. It reads "Mrs Cole". She is married to the football player Ashley Cole. Last week, Sarah Michelle Prinze (nee Geller), best known for her vampire-ass-kicking persona Buffy, announced that she has officially changed her last name. What else would be the perfect surprise "anniversary gift" for her husband, the actor. Freddie Prinze, Jr? With their saccharine sweet sentiments, what both women have demonstrated is that marriage is still an oppressive institution. Once a woman has a ring on her finger she is no longer an individual, but a wife. Her existence is defined by her husband. This is an archaic concept, but one that still stalks us like a dark spectre.
It's been said that "a rose by any other name smells just as sweet," but this is not true. Call a rose a shit stick and suddenly people will be reluctant to send or receive a dozen of them on Valentine's Day. And if it were true, then there would be no precedent for women taking their husband's surnames. If a woman retains her maiden name following marriage, she enters into the commitment as an equal partner, maintaining the individuality and the history she forged during her pre-married days. If she loses her surname, she buys into a tradition that has kept women subservient since Eve ate that apple. But this is what women are expected to do: to sacrifice a sense of self for the "greater good," and there is a stigma attached to any alternative.
The idea has permeated the national consciousness to such an extent that keeping your own name, or expecting your husband to take your last name, is considered trans