コード例 #1
0
class Pipeline:
    def __init__(self, domain, prev_snap, permutations_wordlist):
        self.domain = self.folder = domain
        self.prev_snap = self.timestamp = prev_snap
        self.permutations_wordlist = permutations_wordlist

        self.cfg = Config()
        self.helper = Helper()

        if self.prev_snap is None:
            self.runFolder = None
        else:
            self.runFolder = f'{os.path.join(self.folder, self.prev_snap)}'

        # try making root folder for the website
        try:
            os.mkdir(f'{self.folder}')
        except:
            pass

    def init_timestamp(self):
        '''
        Creates the directory for this run and also records the timestamp for further comparison
        '''

        print(f'----> Creating new snapshot ... \n')
        # encode current time with md5
        self.curTime = str(datetime.datetime.now())
        self.timestamp = hashlib.md5(
            self.curTime.encode("utf8")).hexdigest()[:10]

        # create cur time snapshot folder with md5 encoded name
        self.runFolder = f'{os.path.join(self.folder, self.timestamp)}'
        try:
            os.mkdir(self.runFolder)
        except:
            pass

        snapshots_path = os.path.join(self.folder, 'snapshots.csv')
        if os.path.exists(snapshots_path):
            with open(snapshots_path, 'a') as f:
                f.write(','.join([self.timestamp, self.curTime]) + '\n')
        else:
            snapshots = pd.DataFrame([[self.timestamp, self.curTime]])
            snapshots.columns = ['Hash', 'Time']
            snapshots.to_csv(snapshots_path, index=None)

    def find_domains(self):
        '''
        Find all subdomains;
        Currently use findomain, amass
        '''

        print(f'----> Finding domains ... \n')

        # find domains with findomain and amass
        allLinks = self.helper.get_domains(self.domain, self.runFolder)

        # store the domains as file
        domains = '\n'.join(allLinks)
        with open(os.path.join(self.runFolder, f'domains_{self.domain}.txt'),
                  'w') as f:
            f.write(domains)

    def generate_domain_permutations(self):
        '''
        Given permutation wordlist and domains list generate all possible permutations
        '''

        print(f'----> Generating domain permutations ... \n')

        input_path = os.path.join(self.runFolder, f'domains_{self.domain}.txt')
        output_path = os.path.join(self.runFolder, 'permuted_domains.txt')
        wordlist_path = self.permutations_wordlist
        cmd = self.cfg.ALTDNS(input_path, output_path, wordlist_path)

        subprocess.check_output(cmd, shell=True)

        # stack all list of domains together
        with open(output_path, 'r') as f:
            permuted_domains = f.read().split('\n')

        # store all domains at the same file
        domains = '\n'.join(permuted_domains) + '\n'
        with open(os.path.join(self.runFolder, f'domains_{self.domain}.txt'),
                  'a') as f:
            f.write(domains)

    def scan_targets(self):
        '''
        Resolve all the working hosts with LiveTargetsFinder
        '''

        print('----> Resolving target hosts with LiveTargetFinder \n')

        try:
            os.mkdir('output')
        except:
            pass

        # check working domains with LiveTargetsFinder
        cmd = self.cfg.LiveTargetsFinder(
            os.path.join(self.runFolder, f'domains_{self.domain}.txt'))
        subprocess.check_output(cmd, shell=True)

        # move all working urls to snapshot folder
        cmd = f'''sudo mv output/domains_{self.domain}_targetUrls.txt {os.path.join(self.runFolder, 'urls.txt')}'''
        subprocess.check_output(cmd, shell=True)

        # move all resolving domains to snapshot folder
        cmd = f'''sudo mv output/domains_{self.domain}_domains_alive.txt {os.path.join(self.runFolder, 'domains.txt')}'''
        subprocess.check_output(cmd, shell=True)

        # remove output folder
        cmd = f'sudo rm -r output/'
        subprocess.check_output(cmd, shell=True)

        # remove another output
        cmd = f'sudo rm output.csv'
        # subprocess.check_output(cmd, shell = True)

        # remove full list of domains
        cmd = f'''sudo rm -r {os.path.join(self.runFolder, f'domains_{self.domain}.txt')}'''
        subprocess.check_output(cmd, shell=True)

        # remove permuted domains
        cmd = f'''sudo rm -r {os.path.join(self.runFolder, f'permuted_domains.txt')}'''
        # subprocess.check_output(cmd, shell = True)

    def do_screenshots(self):
        '''
        Screenshot all domains and save to folder
        '''
        print(f'----> Screenshotting all subdomains ... \n')

        # screenshot all domains from domains.txt file
        file_path = os.path.join(self.runFolder, 'domains.txt')
        cmd = self.cfg.AQUATONE(file_path, self.runFolder)
        subprocess.check_output(cmd, shell=True)

        # deleted some aquatone stuff
        cmd = f'''sudo rm -r {os.path.join(self.runFolder, f'aquatone* headers/ html/')}'''
        # subprocess.check_output(cmd, shell = True)

    def find_new_domains(self):
        '''
        Checks 2 lists of latest scanned domains to find differences
        '''

        print('----> Checking for differences in snapshots ... \n')
        # get 2 latest snapshots (one is the current)
        snapshots = pd.read_csv(os.path.join(self.folder, 'snapshots.csv'))
        folders = snapshots['Hash'].tail(2).values
        if len(folders) < 2:
            return None
        folder_old, folder_new = folders[0], folders[1]

        old_domains = self.helper.read_link_file(
            os.path.join(self.folder, folder_old, 'urls.txt'))
        new_domains = self.helper.read_link_file(
            os.path.join(self.folder, folder_new, 'urls.txt'))

        # find added and deleted domains
        deleted = []
        for d in old_domains:
            if d not in new_domains:
                deleted.append(d)

        added = []
        for d in new_domains:
            if d not in old_domains:
                added.append(d)

        # store added and deleted domains as files

        if len(deleted) > 0:
            deletedStr = '\n'.join(deleted)
            with open(os.path.join(self.runFolder, f'deleted_domains.txt'),
                      'w') as f:
                f.write(deletedStr)

        if len(added) > 0:
            addedStr = '\n'.join(added)
            with open(os.path.join(self.runFolder, f'added_domains.txt'),
                      'w') as f:
                f.write(addedStr)

        # notify about ned domains found
        self.notify(deleted, added)

    def notify(self, deleted, added):
        '''
        Notifies about detected differences via telegram bot
        '''

        # if number of deleted entries or added entries more than 0, send a message via telegram
        deletedCounts, addedCounts = len(deleted), len(added)

        if addedCounts > 0:
            text = f'Snapshot {self.timestamp} for {self.domain}\nAdded domains: {addedCounts}'

            payload = {
                'chat_id': self.cfg.TELEGRAM_CHAT_ID,
                'caption': text,
            }

            added = open(os.path.join(self.runFolder, f'added_domains.txt'),
                         'r').read()

            fpayload = {
                'document': ('added.txt', added),
            }

            sendfile = requests.post(
                "https://api.telegram.org/bot{token}/sendDocument".format(
                    token=self.cfg.TELEGRAM_TOKEN),
                files=fpayload,
                data=payload)

        if deletedCounts > 0:
            text = f'Snapshot {self.timestamp} for {self.domain}\nDeleted domains: {deletedCounts}'

            payload = {
                'chat_id': self.cfg.TELEGRAM_CHAT_ID,
                'caption': text,
            }

            added = open(os.path.join(self.runFolder, f'deleted_domains.txt'),
                         'r').read()

            fpayload = {
                'document': ('deleted.txt', added),
            }

            sendfile = requests.post(
                "https://api.telegram.org/bot{token}/sendDocument".format(
                    token=self.cfg.TELEGRAM_TOKEN),
                files=fpayload,
                data=payload)

    def run(self):
        '''
        Runs all the recon pipeline
        '''
        # init faze
        if self.prev_snap is None:
            self.init_timestamp()

        # subdomain enumeration
        self.find_domains()
        # self.generate_domain_permutations()

        # resolve subdomains
        self.scan_targets()

        # screenshot
        # self.do_screenshots()

        # check for new subdomains and notify
        self.find_new_domains()