Beispiel #1
0
	def load_ports(self):
		if not os.path.exists('data/port-popularity'):
			error('Could not find {bgreen}data/port-popularity{rst}.')
			return False

		self.port_popularity = {}

		with open('data/port-popularity', 'r') as f:
			data = yaml.load(f, Loader=yaml.BaseLoader)
			self.port_popularity = {'TCP': data[0]['TCP'], 'UDP': data[1]['UDP']}
Beispiel #2
0
	def serve(self):
		loop = asyncio.get_event_loop()

		tcp_success = 0
		for port in self.tcp_ports:
			if self.verbose >= 2:
				debug('Starting listener for TCP port {byellow}{port}{rst}...')

			try:
				tcp_socket = socket.socket(family=socket.AF_INET6, type=socket.SOCK_STREAM)
				tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
				tcp_socket.bind(('::', int(port)))

				loop_server = loop.run_until_complete(
					loop.create_server(
						lambda: HoneypotServerTCP(self),
						sock=tcp_socket))
				loop.create_task(loop_server.serve_forever())

				tcp_success += 1
			except:
				error('Failed to bind to TCP port {port}.')

		info('Started listening on {byellow}{tcp_success}{rst} TCP ports.')

		udp_success = 0
		for port in self.udp_ports:
			if self.verbose >= 3:
				debug('Starting listener for UDP port {byellow}{port}{rst}...')

			try:
				udp_socket = socket.socket(family=socket.AF_INET6, type=socket.SOCK_DGRAM)
				udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
				udp_socket.bind(('::', int(port)))

				transport, protocol = loop.run_until_complete(
					loop.create_datagram_endpoint(
						lambda: HoneypotServerUDP(self),
						sock=udp_socket))
				
				udp_success += 1
			except:
				error('Failed to bind to UDP port {port}.')

		info('Started listening on {byellow}{udp_success}{rst} UDP ports.')

		try:
			loop.run_forever()
		except:
			pass
Beispiel #3
0
	def load_probes(self):
		if not os.path.exists('data/service-probes'):
			error('Could not find {bgreen}data/service-probes{rst}.')
			return False

		self.probes   = {'UDP': {}, 'TCP': {}}
		self.payloads = {'UDP': {}, 'TCP': {}}

		with open('data/service-probes', 'r') as f:
			lines = f.readlines()
			
			current = None
			for line in lines:
				line = line.strip()
				lowline = line.lower()

				if not line:
					continue

				if lowline.startswith('probe '):
					probe_type, proto, name, payload = line.split(' ', 3)
					payload = payload[2:-1].encode('utf-8').decode('unicode_escape')
					self.probes[proto][name] = payload
					current = (proto, name)

				elif lowline.startswith('match ') or lowline.startswith('softmatch '):
					if not current:
						continue

					action, name, regex = line.split(' ', 2)

					# check what separator is being used for the regex
					# and extract the regex itself

					rgxsep = regex[1]
					rgxend = regex[2:].find(rgxsep) + 2
					regex  = regex[2:rgxend]

					if current[1] not in self.payloads[current[0]]:
						self.payloads[current[0]][current[1]] = []

					self.payloads[current[0]][current[1]].append(regex)

		if self.verbose >= 1:
			tcp_probes = len(self.probes['TCP'])
			udp_probes = len(self.probes['UDP'])
			debug('Loaded {bgreen}{tcp_probes}{rst} TCP and {bgreen}{udp_probes}{rst} UDP probes.')
			
		return len(self.probes['UDP']) > 0 and len(self.probes['TCP']) > 0
Beispiel #4
0
    def _scan_host(self, scanner_group, address, results):
        for idx, scanner in enumerate(scanner_group):
            name = scanner.name()
            cache = scanner.code()
            result = None

            if idx > 0:
                info(
                    'Re-trying {bblue}{name}{rst}/{byellow}{address}{rst} with next implementation...'
                )

            if self.has_cached_result(address, cache):
                if self.verbose >= 1:
                    debug(
                        'Returning {bblue}{name}{rst}/{byellow}{address}{rst} from recent cache.'
                    )

                result = self.read_result(address, cache)

            if result is None and not self.no_query:
                if self.verbose >= 1:
                    debug(
                        'Getting fresh {bblue}{name}{rst}/{byellow}{address}{rst} data...'
                    )

                result = scanner.get(address)
                if result is not None:
                    self.write_result(address, cache, result)

            if result is None:
                error(
                    'Failed to get passive scan data for {byellow}{address}{rst}.'
                )
                continue

            parsed = scanner.enum(result)

            if self.verbose >= 1:
                for svc in parsed:
                    debug(
                        'Discovered service {bgreen}{svc[service]}{rst} on port {bgreen}{svc[port]}{rst}/{bgreen}{svc[transport]}{rst} running {bgreen}{svc[product]}{rst}/{bgreen}{svc[version]}{rst}.'
                    )

            results[name] = parsed
            break
Beispiel #5
0
    def get_scanners(self):
        base = PassiveBase()
        order = (base.config('order') or '').split(':')
        if len(order) == 1 and not order[0]:
            error(
                'Scanner order is not specified in {byellow}precon.conf{rst}.')
            return None

        scanners = []
        for group in order:
            group = group.split(',')
            scanner_group = []

            for name in group:
                if name not in globals():
                    error(
                        'Specified class {byellow}{name}{rst} does not exist.')
                    continue

                clss = globals()[name]
                if not issubclass(clss, PassiveBase):
                    error(
                        'Specified class {byellow}{name}{rst} is not a supported scanner.'
                    )
                    continue

                inst = clss()
                scanner_group.append(inst)

            scanners.append(scanner_group)

        return scanners
Beispiel #6
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get('https://www.shodan.io/host/' + address + '/raw',
                           headers=self.headers(
                               'https://www.shodan.io/host/' + address,
                               'www.shodan.io'))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}Shodan{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        match = re.search(r'let data = ({.+});', req.text)
        if not match or not match.group(1):
            error(
                'Failed to get {bblue}Shodan{rst}/{byellow}{address}{rst}: could not extract data.'
            )
            return None

        # use YAML to parse the JSON, as Shodan sometimes returns invalid escapes, which the YAML parser is more lax with
        data = None
        try:
            data = yaml.load(match.group(1), Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}Shodan{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        return data
Beispiel #7
0
    def run_cmd(self, cmd, tag='?', redirect=None):
        if redirect is None:
            redirect = self.verbose >= 2

        info(('Skipping' if self.dryrun else 'Running') +
             ' task {bgreen}{tag}{rst}' +
             (' with {bblue}{cmd}{rst}' if self.verbose >= 1 else '...'))

        if self.dryrun:
            return True

        proc = subprocess.Popen(
            cmd,
            shell=True,
            stdout=subprocess.PIPE if redirect else subprocess.DEVNULL,
            stderr=subprocess.PIPE if redirect else subprocess.DEVNULL)

        if redirect:
            thdout = threading.Event()
            thderr = threading.Event()

            threading.Thread(target=self.dump_pipe,
                             args=(proc.stdout, thdout, tag)).start()
            threading.Thread(target=self.dump_pipe,
                             args=(proc.stderr, thderr, tag,
                                   Fore.RED)).start()

        ret = proc.wait()

        if redirect:
            thdout.set()
            thderr.set()

        if ret != 0:
            error('Task {bred}{tag}{rst} returned non-zero exit code: {ret}')
        else:
            info('Task {bgreen}{tag}{rst} finished successfully.')

        return ret == 0
Beispiel #8
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get('https://leakix.net/host/' + address,
                           headers=self.headers(self.config('key')))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}LeakIX{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        data = None
        try:
            data = yaml.load(req.text, Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}LeakIX{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        return data
Beispiel #9
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get('https://api.zoomeye.org/host/search',
                           headers=self.headers(self.config('key')),
                           params=(('query', address), ('sub_type', 'all')))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        data = None
        try:
            data = yaml.load(req.text, Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        return data
Beispiel #10
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get('https://search.censys.io/api/v2/hosts/' + address,
                           headers=self.headers(),
                           auth=(self.config('id'), self.config('secret')))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}Censys{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        data = None
        try:
            data = yaml.load(req.text, Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}Censys{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        return data['result'] if 'result' in data else None
Beispiel #11
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get(
            'https://search.censys.io/hosts/' + address + '/data/json',
            headers=self.headers('https://search.censys.io/hosts/' + address,
                                 'search.censys.io'))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}Censys{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        match = re.search(
            r'<pre><code class="language-json">({.+})</code></pre>', req.text,
            re.DOTALL)
        if not match or not match.group(1):
            error(
                'Failed to get {bblue}Censys{rst}/{byellow}{address}{rst}: could not extract data.'
            )
            return None

        json = match.group(1)
        json = re.sub(r'<a (?:href|class)=".*?</a>', '-', json)
        json = html.unescape(json)

        data = None
        try:
            data = yaml.load(json, Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}Censys{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        return data
Beispiel #12
0
    def scan_service(self, address, port, service):
        if port < 0:
            is_udp = True
            port *= -1
        else:
            is_udp = False

        info(
            'Scanning service {bgreen}{service}{rst} on port {bgreen}{port}{rst}/{bgreen}{proto}{rst}...',
            proto='udp' if is_udp else 'tcp')
        basedir = os.path.join(self.outdir, address + self.srvname)
        os.makedirs(basedir, exist_ok=True)

        if self.bruteforce:
            error('self.bruteforce-only mode is currently not available.')
            return

        if 'http' in service:
            self.enum_http(address, port, service, basedir)

        elif 'smtp' in service:
            self.enum_smtp(address, port, service, basedir)

        elif 'pop3' in service:
            self.enum_pop3(address, port, service, basedir)

        elif 'imap' in service:
            self.enum_imap(address, port, service, basedir)

        elif 'ftp' in service:
            self.enum_ftp(address, port, service, basedir)

        elif 'microsoft-ds' in service or 'netbios' in service:
            self.enum_smb(address, port, service, basedir)

        elif 'ms-sql' in service or 'msSql' in service:
            self.enum_mssql(address, port, service, basedir)

        elif 'mysql' in service:
            self.enum_mysql(address, port, service, basedir)

        elif 'oracle' in service:
            self.enum_oracle(address, port, service, basedir)

        elif 'nfs' in service or 'rpcbind' in service:
            self.enum_nfs(address, port, service, basedir)

        elif 'snmp' in service:
            self.enum_snmp(address, port, service, basedir)

        elif 'domain' in service or 'dns' in service:
            self.enum_dns(address, port, service, basedir)

        elif 'rdp' in service or 'ms-wbt-server' in service or 'ms-term-serv' in service:
            self.enum_rdp(address, port, service, basedir)

        elif 'vnc' in service:
            self.enum_vnc(address, port, service, basedir)

        elif not is_udp:
            warn(
                'Service {byellow}{service}{rst} will be scanned generically.')

            self.enum_generic_tcp(address, port, service, basedir)

        else:
            if port <= 1024:
                warn(
                    'Service {byellow}{service}{rst} will be scanned generically.'
                )

                self.enum_generic_udp(address, port, service, basedir)

            else:
                warn(
                    'Service {byellow}{service}{rst} will not be scanned generically.'
                )

                with open(os.path.join(basedir, '0_untouched.txt'),
                          'a') as file:
                    file.writelines(
                        str(port) + '\t' + ('udp' if is_udp else 'tcp') +
                        '\t' + service + '\n')
Beispiel #13
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get('https://leakix.net/host/' + address,
                           headers=self.headers(
                               'https://leakix.net/search?scope=service&q=' +
                               address, 'leakix.net'))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}LeakIX{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        tree = etree.HTML(req.text)
        svcs = tree.xpath('//ul[@id="service-panel"]/li')

        # enumerate services tab with ports + banners

        ports = {}

        for svc in svcs:
            port = svc.xpath('.//a[starts-with(@href, "/host")]/text()')

            if len(port) > 0:
                port = port[0].split(':')[-1]
            else:
                continue

            banner = svc.xpath('.//pre')
            if len(banner) > 0:
                banner = banner[0].text
            else:
                banner = None

            if port not in ports or not ports[port]:
                ports[port] = banner

        # enumerate software list

        data = []

        softs = tree.xpath(
            '//div[h5[contains(text(), "Software information")]]//div[contains(@class, "list-group-item")]'
        )
        for soft in softs:
            prod = soft.xpath('./p[@class="h5"]/small')
            version = None
            if len(prod) > 0:
                version = prod[0].text
                prod = prod[0].xpath('./preceding-sibling::text()')[-1].strip()
            else:
                prod = None

            svcs = soft.xpath('.//span[contains(@class, "badge")]/text()')
            for svc in svcs:
                svc = svc.split('/')

                data.append({
                    'port':
                    svc[1],
                    'transport':
                    svc[0],
                    'product':
                    prod,
                    'version':
                    version,
                    'banner':
                    ports[svc[1]] if svc[1] in ports else None
                })

        # check if anything is missing

        if len(data) == 0 and len(ports) == 0:
            error(
                'Failed to get {bblue}LeakIX{rst}/{byellow}{address}{rst}: no services found.'
            )
            return None

        for svc in data:
            if svc['port'] in ports:
                del ports[svc['port']]

        for port in ports:
            data.append({
                'port': port,
                'transport': 'tcp',
                'product': None,
                'version': None,
                'banner': ports[port]
            })

        return data
Beispiel #14
0
    def get(self, address):
        if not self.enabled():
            return None

        req = requests.get(
            'https://www.zoomeye.org/search',
            headers=self.headers(
                'https://www.zoomeye.org/searchResult?q=ip%3A%22' + address +
                '%22', 'www.zoomeye.org'),
            params=(
                ('q', 'ip%3A%22' + address + '%22'),
                ('page', '1'),
                ('pageSize', '20'),
                ('t', 'v4+v6'),
            ))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: HTTP status code is {bred}{req.status_code}{rst}.'
            )
            return None

        try:
            search = yaml.load(req.text, Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        print(search)
        if 'status' in search and search['status'] != 200:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: API status code is {bred}{search[status]}{rst}.'
            )
            return None

        if 'matches' not in search or len(search['matches']) == 0:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: no results.'
            )
            return None

        host_token = None
        web_token = None
        for match in search['matches']:
            if address not in match['ip']:
                continue

            if host_token is None and match['type'] == 'host':
                host_token = match['token']

            elif web_token is None and match['type'] == 'web':
                web_token = match['token']

        if web_token is None and host_token is None:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: failed to find tokens in results.'
            )
            return None

        token = host_token if host_token is not None else web_token
        type = 'host' if host_token is not None else 'web'

        req = requests.get(
            'https://www.zoomeye.org/' + type + '/details/' + token,
            headers=self.headers(
                'https://www.zoomeye.org/searchDetail?type=' + type +
                '&title=' + token, 'www.zoomeye.org'),
            params=(('from', 'detail'), ))

        if req.status_code != 200:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: status code is {bred}{req.status_code}{rst}.'
            )
            return None

        data = None
        try:
            data = yaml.load(req.text, Loader=yaml.FullLoader)
        except:
            error(
                'Failed to get {bblue}ZoomEye{rst}/{byellow}{address}{rst}: failed to parse data.'
            )
            return None

        return data
Beispiel #15
0
	def error_received(self, exc):
		lport = self.transport.get_extra_info('sockname')[1]
		error('Error on {byellow}udp:{lport}{rst}: {bred}{exc}{rst}')
Beispiel #16
0
    verbose = args.verbose

    if not os.path.isfile('vulns.db'):
        fail(
            'Failed to find {bgreen}vulns.db{rst}. Use {bblue}-u{rst} to download the dependencies and build the database.'
        )

    conn = sqlite3.connect('vulns.db')
    c = conn.cursor()

    if args.query.lower().startswith('cpe:/'):
        info('Finding vulnerabilities for {bgreen}{query}{rst}...',
             query=args.query.lower())
        get_vulns_cli(args.query.lower())

    elif os.path.isfile(args.query):
        info('Processing nmap report {bgreen}{args.query}{rst}...')
        process_nmap(args.query)

    else:
        info('Performing fuzzy matching for {bgreen}{args.query}{rst}...')

        cpe = fuzzy_find_cpe(args.query)
        if cpe is None:
            error('Failed to resolve query to a CPE name.')
        else:
            info('Fuzzy-matched query to name {byellow}cpe:/{cpe}{rst}.')
            get_vulns_cli(cpe)

    conn.close()