├── .gitignore ├── requirements.txt ├── config.json ├── README.md ├── brand_watch.py └── BrandWatch ├── __init__.py └── Leet.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | investigate==1.2.0 2 | requests==2.10.0 3 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "investigate_api_key": "YOUR KEY" 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Brand Watcher 2 | 3 | This is meant to be run periodically to identify if a new domain was seen in OpenDNS' investigate that matches a defined brand 4 | 5 | ## Set up 6 | 7 | To use set up a virtualenv and install required packages 8 | 9 | ``` 10 | virtualenv venv 11 | source venv/bin/activate 12 | pip install -r requirements.txt 13 | ``` 14 | 15 | Then modify `brand_watch.py` and define your `api_key` 16 | 17 | ``` 18 | api_key='YOUR INVESTIGATE API KEY' 19 | ``` 20 | 21 | ## Running 22 | 23 | Set up a cron job or periodically run brand_watch with a brand you'd like to watch. For instance, to check out paypal, just provide it as a parameter. 24 | 25 | ``` 26 | python brand_watch.py paypal 27 | ``` 28 | 29 | If you have a list of known newly registered domains, you can exclude them from results with the `-e` option: 30 | 31 | ``` 32 | python brand_watch.py -e exclude.list paypal 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /brand_watch.py: -------------------------------------------------------------------------------- 1 | """ 2 | brand_watch.py 3 | @brad_anton 4 | 5 | """ 6 | 7 | from BrandWatch import Watcher 8 | import argparse 9 | 10 | 11 | api_key = None # Define your api key here or in config.json 12 | 13 | if __name__ == '__main__': 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument('brand') 16 | parser.add_argument('-e', '--exclude') 17 | args = parser.parse_args() 18 | 19 | if api_key is None: 20 | with open('config.json', 'rb') as f: 21 | from json import load 22 | config = load(f) 23 | api_key = config['investigate_api_key'] 24 | 25 | if not args.exclude: 26 | w = Watcher(api_key=api_key, brand=args.brand, days=30) 27 | else: 28 | with open(args.exclude, 'rb') as f: 29 | exclude = f.read().splitlines() 30 | 31 | w = Watcher(api_key=api_key, brand=args.brand, exclude=exclude) 32 | 33 | w.search() 34 | -------------------------------------------------------------------------------- /BrandWatch/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | __init__.py 3 | @brad_anton 4 | 5 | Implements the Watcher class 6 | """ 7 | 8 | import investigate 9 | import datetime 10 | 11 | from Leet import Leet 12 | 13 | class Watcher: 14 | def __init__(self, api_key=None, brand=None, exclude=None, days=1, limit=100, include_category=False): 15 | """Create a new Watcher instance 16 | 17 | Keyword arguments: 18 | api_key -- Investigate API Key for making queries 19 | brand -- Brand name string to include in pattern searches. Brands that are also very common names may return lots of results 20 | exclude -- (Optional) list of domains that should be excluded from searches 21 | """ 22 | 23 | if api_key is None or brand is None: 24 | raise Exception('No API key or Brand defined') 25 | 26 | self.api_key = api_key 27 | self.brand = brand 28 | self.exclude = exclude 29 | self.days = days 30 | self.limit = limit 31 | self.include_category=include_category 32 | self.regex_list = [] 33 | 34 | self.inv = investigate.Investigate(api_key) 35 | self.generate() 36 | 37 | def leet(self): 38 | l = Leet(self.brand) 39 | return '.*{0}.*'.format(l.get_regex_duplicate()) 40 | 41 | def simple(self): 42 | # This is also covered by leet() 43 | return '.*{0}.*'.format(self.brand) 44 | 45 | def generate(self): 46 | # Simple is also covered by leet() 47 | # self.regex_list.append(self.simple()) 48 | self.regex_list.append(self.leet()) 49 | 50 | def search(self): 51 | for r in self.regex_list: 52 | results = self.inv.search(r, start=datetime.timedelta(days=self.days), limit=self.limit, include_category=self.include_category) 53 | if len(results['matches']) > 0: 54 | for result in results['matches']: 55 | name = result['name'] 56 | if self.exclude is not None: 57 | # Check for any explicit matches 58 | if name not in self.exclude: 59 | # Check for more full host matches 60 | if all([not name.endswith('.{}'.format(e)) for e in self.exclude]): 61 | print name 62 | else: 63 | print name 64 | 65 | -------------------------------------------------------------------------------- /BrandWatch/Leet.py: -------------------------------------------------------------------------------- 1 | """ 2 | Leet.py 3 | @brad_anton 4 | 5 | Inspired by of this LeetSpeek generator: 6 | https://github.com/floft/leetspeak/blob/master/LeetSpeak.py 7 | """ 8 | class Leet: 9 | def __init__(self, word=None): 10 | if word is None: 11 | raise exception('No word provided') 12 | self.word = word 13 | 14 | self.a=['a','4'] 15 | self.b=['b','8','6'] 16 | self.c=['c','k'] 17 | self.d=['d','0'] 18 | self.e=['e','3'] 19 | self.f=['f'] 20 | self.g=['g','6','9'] 21 | self.h=['h'] 22 | self.i=['i','!','1','|','l'] 23 | self.j=['j'] 24 | self.k=['k','x'] 25 | self.l=['l','1','7'] 26 | self.m=['m','nn'] 27 | self.n=['n'] 28 | self.o=['o','0'] 29 | self.p=['p','9','q'] 30 | self.q=['q','9'] 31 | self.r=['r'] 32 | self.s=['s','5','z','es','2'] 33 | self.t=['t','7','1'] 34 | self.u=['u','m'] 35 | self.v=['v'] 36 | self.w=['w','vv'] 37 | self.x=['x','ex'] 38 | self.y=['y','j'] 39 | self.z=['z','2'] 40 | self.zero=['0','o'] 41 | self.one=['1','l'] 42 | self.two=['two','2','z'] 43 | self.three=['e','3','three'] 44 | self.four=['4','four','for','fore','a'] 45 | self.five=['5','five','s'] 46 | self.six=['6','six','g'] 47 | self.seven=['7','seven','t','l'] 48 | self.eight=['8','eight','b'] 49 | self.nine=['9','nine','g'] 50 | 51 | self.alphabet={ 'a':self.a, 'b':self.b, 'c':self.c, 52 | 'd':self.d, 'e':self.e, 'f':self.f, 'g':self.g, 53 | 'h':self.h, 'i':self.i, 'j':self.j, 'k':self.k, 54 | 'l':self.l, 'm':self.m, 'n':self.n, 'o':self.o, 55 | 'p':self.p, 'q':self.q, 'r':self.r, 's':self.s, 56 | 't':self.t, 'u':self.u, 'v':self.v, 'w':self.w, 57 | 'x':self.x, 'y':self.y, 'z':self.z, '0':self.zero, 58 | '1':self.one,'2':self.two,'3':self.three,'4':self.four, 59 | '5':self.five,'6':self.six,'7':self.seven,'8':self.eight, 60 | '9':self.nine } 61 | 62 | def get_permutations(self, letter): 63 | try: 64 | permutations = self.alphabet[letter] 65 | except KeyError: 66 | permutations = letter 67 | regex = '[' 68 | for p in permutations[:-1]: 69 | regex += '{0}|'.format(p) 70 | regex += '{0}]'.format(permutations[-1]) 71 | 72 | return regex 73 | 74 | def get_regex(self): 75 | result = '' 76 | for letter in self.word: 77 | result += self.get_permutations(letter) 78 | return result 79 | 80 | def get_regex_duplicate(self): 81 | result = '' 82 | length = len(self.word) 83 | duplicate = False 84 | for i in range(length): 85 | if i == 0: 86 | result += self.get_permutations(self.word[i]) 87 | elif self.word[i] == self.word[i-1] and not duplicate: 88 | duplicate = True 89 | result += '+' 90 | elif self.word[i] != self.word[i-1]: 91 | duplicate = False 92 | result += self.get_permutations(self.word[i]) 93 | return result 94 | --------------------------------------------------------------------------------