Example #1
0
    def paginate(self, pageNumber=1):

        # Contexto de la búsqueda de la página actual
        searchContext = {
            'max-pages': 15,
            'max-result': 10,
            'start-index': 1,
            'query': 'domain:' + self.context.baseHostname
        }

        # ¿Hay resultados del método actual?
        if (self.hostnames):

            # Excluye los subdominios ya conocidos
            searchContext['query'] += (' -domain:' +
                                       ' -domain:'.join(self.hostnames))

        # Número del resultado de inicio actual
        searchContext['start-index'] = ((
            (pageNumber - 1) * searchContext['max-result']) + 1)

        # Header message for pagination
        self.context.out(
            message=self.context.strings['methods']['bing']['pagination'])

        # Uso del crawler
        crawler = WCrawler()

        # El resultado es de tipo json
        result = None

        try:
            result = crawler.httpRequest(
                'https://www.bing.com/search?' + '&q=' +
                crawler.urlencode(searchContext['query']) + '&first=' +
                str(searchContext['start-index']))

            # Libera la memoria (no es necesario un contexto de navegación)
            crawler.clearContext()

        except Exception as e:
            self.context.out(
                self.context.strings['methods']['bing']['no-connect'])
            return

        # ¿La respuesta HTTP es OK?
        if (result['status-code'] != 200):
            self.context.out(message=self.context.strings['methods']['bing']
                             ['wrong-status-http'],
                             parseDict={'id': result['status-code']})
            return

        # Busca cada nombre de dominio
        # Ejemplo de resultados: <cite>https://foo<strong>ejemplo.com</strong>
        matches = re.findall(
            br'>([\w\.\-\_\$]+?\.' +
            re.escape(self.context.baseHostname).encode() + br')',
            result['response-content'].replace(
                b'<strong>' + self.context.baseHostname.encode(),
                b'.' + self.context.baseHostname.encode()))

        if (len(matches) == 0):
            # No hay resultados
            self.context.out(
                self.context.strings['methods']['bing']['no-more-results'])
            return

        # Procesa cada nombre de dominio encontrado
        for item in matches:

            # ¿El resultado es un subdominio inválido?
            if (not item.decode().endswith('.' + self.context.baseHostname)):
                continue

            # Evita los resultados duplicados utilizando la pila local
            if (item.decode() in self.hostnames):
                continue

            # Agrega el subdominio encontrado a la pila local
            self.hostnames.append(item.decode())

            # Agrega el subdominio encontrado a la pila global de resultados
            self.context.addHostName(
                hostname=item.decode(),
                messageFormat=self.context.strings['methods']['bing']
                ['item-found'])

        # ¿Hay mas páginas donde buscar?
        if (not b'sw_next' in result['response-content']):
            self.context.out(
                self.context.strings['methods']['bing']['no-more-results'])
            return

        # Límite de busqueda de páginas
        if (pageNumber >= searchContext['max-pages']):
            self.context.out(
                self.context.strings['methods']['bing']['no-more-results'])
            return

        # Continua con la siguiente página
        self.paginate(pageNumber=pageNumber + 1)
Example #2
0
    def find(self):

        # Mensaje de la cabecera del método
        self.context.out(
            message=self.context.strings['method-begin'],
            parseDict={
                'current':
                self.context.progress['methods']['current'],
                'total':
                self.context.progress['methods']['total'],
                'title':
                self.context.strings['methods']['certificate-details']['title']
            })

        # Uso del crawler
        crawler = WCrawler()

        # El resultado es de tipo json
        result = None

        try:
            result = crawler.httpRequest(
                url='https://certificatedetails.com/api/list/' +
                crawler.urlencode(self.context.baseHostname))

            # Libera la memoria (no es necesario un contexto de navegación)
            crawler.clearContext()

        except Exception as e:
            self.context.out(self.context.strings['methods']
                             ['certificate-details']['no-connect'])
            return

        # ¿La respuesta HTTP es OK?
        if (result['status-code'] != 200):
            self.context.out(message=self.context.strings['methods']
                             ['certificate-details']['wrong-status-http'],
                             parseDict={'id': result['status-code']})
            return

        try:
            # Convierte el resultado en un objeto de tipo json
            result = json.loads(result['response-content'])

        except Exception as e:
            self.context.out(self.context.strings['methods']
                             ['certificate-details']['corrupt-response'])
            return

        if ((not isinstance(result, list)) or (len(result) == 0)):
            self.context.out(self.context.strings['methods']
                             ['certificate-details']['empty'])
            return

        # Procesa cada nombre de dominio encontrado
        for item in result:

            # ¿Es un subdominio válido?
            if (not item['CommonName'].endswith('.' +
                                                self.context.baseHostname)):
                continue

            # Evita los resultados duplicados utilizando la pila local
            if (item['CommonName'] in self.hostnames):
                continue

            # Agrega el subdominio encontrado a la pila local
            self.hostnames.append(item['CommonName'])

            # Agrega el subdominio encontrado a la pila global de resultados
            self.context.addHostName(
                hostname=item['CommonName'],
                messageFormat=self.context.strings['methods']['crt-sh']
                ['item-found'])

        # Mensaje de cabecera del comienzo de la obtención de todos los enlaces
        self.context.out(self.context.strings['methods']['certificate-details']
                         ['find-links'])

        # Identificador actual del enlace
        linkId = 0

        # Procesa cada enlace
        # Precaución: Un mismo nombre de dominio repetido puede contener uno o
        #             más certificados diferentes.
        for item in result:

            linkId += 1

            self.findInLink(url='https://certificatedetails.com' +
                            item['Link'],
                            linkId=linkId,
                            totalLinks=len(result))
Example #3
0
    def findInApi(self, nextUrl=None, pageId=1):

        # Mensaje de la paginación
        self.context.out(
            message=self.context.strings['methods']['virus-total']['paginating'],
            parseDict={
                'number': pageId
            }
        )

        # Uso del crawler
        crawler = WCrawler()

        # El resultado es de tipo json
        result = None

        try:
            if(nextUrl is None):
                result = crawler.httpRequest(
                    url='https://www.virustotal.com/ui/domains/' + crawler.urlencode(self.context.baseHostname) + '/subdomains?limit=40'
                )
            else:
                result = crawler.httpRequest(nextUrl)

            # Libera la memoria (no es necesario un contexto de navegación)
            crawler.clearContext()

        except Exception as e:

            # Imposible navegar
            self.context.out(
                self.context.strings['methods']['virus-total']['no-connect']
            )

            return

        # ¿La respuesta HTTP es OK?
        if(result['status-code'] != 200):
            self.context.out(
                message=self.context.strings['methods']['virus-total']['wrong-status-http'],
                parseDict={
                    'id': result['status-code']
                }
            )
            return

        try:
            # Convierte el resultado en un objeto de tipo json
            result = json.loads(result['response-content'])

        except Exception as e:

            # Contenido corrupto, no es de tipo json procesable
            self.context.out(
                self.context.strings['methods']['virus-total']['corrupt-response']
            )

            return

        # ¿Hay contenido de la respuesta HTTP?
        if(len(result['data']) == 0):

            # No hay contenido, por lo cual tampoco hay más resultados
            self.context.out(self.context.strings['methods']['virus-total']['no-more'])

            return

        # Procesa todos los subdominios encontrados en la página actual
        for item in result['data']:

            # Evita los resultados duplicados utilizando la pila local
            if(str(item['id']) in self.hostnames):
                continue

            # Agrega el subdominio encontrado a la pila local
            self.hostnames.append(str(item['id']))

            # Agrega el subdominio encontrado a la pila global de resultados
            self.context.addHostName(
                hostname=str(item['id']),
                messageFormat=self.context.strings['methods']['virus-total']['item-found']
            )

        # ¿Necesita continuar paginando resultados?
        if(
            ('links' in result) and
            ('next' in result['links']) and
            (result['links'])
        ):
            # Continua con la siguiente página
            self.findInApi(
                nextUrl=str(result['links']['next']),
                pageId=(pageId + 1)
            )
Example #4
0
    def find(self):

        # Mensaje de la cabecera del método
        self.context.out(message=self.context.strings['method-begin'],
                         parseDict={
                             'current':
                             self.context.progress['methods']['current'],
                             'total':
                             self.context.progress['methods']['total'],
                             'title':
                             self.context.strings['methods']['robtex']['title']
                         })

        # Uso del crawler
        crawler = WCrawler()
        crawler.defaultTimeout = 30

        # Resultado de tipo HTML
        result = None

        try:
            result = crawler.httpRequest(
                url='https://www.robtex.com/dns-lookup/' +
                crawler.urlencode(self.context.baseHostname))

            # Libera la memoria (no es necesario un contexto de navegación)
            crawler.clearContext()

        except Exception as e:

            # Imposible navegar
            self.context.out(
                self.context.strings['methods']['robtex']['no-connect'])

            return

        # ¿La respuesta HTTP es OK?
        if (result['status-code'] != 200):
            self.context.out(message=self.context.strings['methods']['robtex']
                             ['wrong-status-http'],
                             parseDict={'id': result['status-code']})
            return

        # Elimina las etiquetas de negritas del resultado: foo.<b>domain.com</b>
        result['response-content'] = result['response-content'].replace(
            b'<b>', b'').replace(b'</b>', b'')

        # Busca todos los posibles subdominios
        matches = re.findall(
            br'>([\w\.\-\_\$]+?\.' +
            re.escape(self.context.baseHostname).encode() + br')<',
            result['response-content'])

        # ¿Hay resultados?
        if (len(matches) == 0):
            self.context.out(
                self.context.strings['methods']['robtex']['empty'])
            return

        # Procesa todos los resultados
        for item in matches:

            # Agrega el subdominio encontrado a la pila global de resultados
            self.context.addHostName(
                hostname=item.decode(),
                messageFormat=self.context.strings['methods']['robtex']
                ['item-found'])
Example #5
0
    def paginate(self, pageNumber=1):

        # Contexto de la búsqueda de la página actual
        searchContext = {
            'max-pages': 15,
            'max-result': 10,
            'start-index': 1,
            'query': 'site:' + self.context.baseHostname
        }

        # ¿Hay resultados del método actual?
        if (self.hostnames):

            # Excluye los subdominios ya conocidos
            searchContext['query'] += ' -site:' + ' -site:'.join(
                self.hostnames)

        # Número del resultado de inicio actual
        searchContext['start-index'] = ((
            (pageNumber - 1) * searchContext['max-result']) + 1)

        # Mensaje inicial de la paginación
        self.context.out(
            self.context.strings['methods']['google']['pagination'])

        # Uso del crawler
        crawler = WCrawler()

        # El resultado es de tipo json
        result = None

        try:
            # Navega
            result = crawler.httpRequest(
                'https://www.googleapis.com/customsearch/v1?' + 'cx=' +
                crawler.urlencode(self.googleCx) + '&key=' +
                crawler.urlencode(self.googleApiKey) + '&q=' +
                crawler.urlencode(searchContext['query']) + '&start=' +
                str(searchContext['start-index']) + '&filter=1&safe=off&num=' +
                str(searchContext['max-result']))

            # Libera la memoria (no es necesario un contexto de navegación)
            crawler.clearContext()

        except Exception as e:

            # Imposible navegar
            self.context.out(
                self.context.strings['methods']['google']['no-connect'])

            return

        # Los estados 403 y 400 indican que no hay más resultados o que la API
        # está saturada con solicitudes.
        if (result['status-code'] in [403, 400]):
            self.context.out(
                self.context.strings['methods']['google']['no-more-results'])
            return

        # ¿La respuesta HTTP es OK?
        if (result['status-code'] != 200):
            self.context.out(message=self.context.strings['methods']['google']
                             ['wrong-status-http'],
                             parseDict={'id': result['status-code']})
            return

        try:
            # Convierte el resultado en un objeto de tipo json
            result = json.loads(result['response-content'])

        except Exception as e:

            # Contenido corrupto, no es de tipo json procesable
            self.context.out(
                self.context.strings['methods']['google']['corrupt-response'])

            return

        # ¿Hay resultados procesables?
        if ((not 'items' in result) or (len(result['items']) == 0)):

            # No hay más resultados
            self.context.out(
                self.context.strings['methods']['google']['no-more-results'])

            return

        # Procesa cada resultado
        for item in result['items']:

            # ¿El resultado es un subdominio inválido?
            if (not item['displayLink'].endswith('.' +
                                                 self.context.baseHostname)):
                continue

            # Evita los resultados duplicados utilizando la pila local
            if (item['displayLink'] in self.hostnames):
                continue

            # Agrega el subdominio encontrado a la pila local
            self.hostnames.append(item['displayLink'])

            # Agrega el subdominio encontrado a la pila global de resultados
            self.context.addHostName(
                hostname=item['displayLink'],
                messageFormat=self.context.strings['methods']['google']
                ['item-found'])

            # Retorna a la primera página nuevamente debido a que la búsqueda
            # debe contener la exclusión del subdominio encontrado, por ejemplo:
            # site: example.com -site:foo.example.com
            pageNumber = 0

        # Límite de busqueda de páginas
        if (pageNumber >= searchContext['max-pages']):
            self.context.out(
                self.context.strings['methods']['google']['no-more-results'])
            return

        # Continua con la siguiente página
        self.paginate(pageNumber=pageNumber + 1)
Example #6
0
    def find(self):

        # Mensaje de la cabecera del método
        self.context.out(message=self.context.strings['method-begin'],
                         parseDict={
                             'current':
                             self.context.progress['methods']['current'],
                             'total':
                             self.context.progress['methods']['total'],
                             'title':
                             self.context.strings['methods']['crt-sh']['title']
                         })

        # Uso del crawler
        crawler = WCrawler()
        crawler.defaultTimeout = 60

        # El resultado es de tipo json
        result = None

        try:
            result = crawler.httpRequest(
                url='https://crt.sh/?q=' +
                crawler.urlencode('%.' + self.context.baseHostname) +
                '&output=json')

            # Libera la memoria (no es necesario un contexto de navegación)
            crawler.clearContext()

        except Exception as e:
            self.context.out(
                self.context.strings['methods']['crt-sh']['no-connect'])
            return

        # ¿La respuesta HTTP es OK?
        if (result['status-code'] != 200):
            self.context.out(message=self.context.strings['methods']['crt-sh']
                             ['wrong-status-http'],
                             parseDict={'id': result['status-code']})
            return

        try:
            # Convierte el resultado en un objeto de tipo json
            result = json.loads(result['response-content'])

        except Exception as e:
            self.context.out(
                self.context.strings['methods']['crt-sh']['corrupt-response'])
            return

        if ((not isinstance(result, list)) or (len(result) == 0)):
            self.context.out(
                self.context.strings['methods']['crt-sh']['empty'])
            return

        # Procesa cada nombre de dominio encontrado
        for item in result:

            # Evita los resultados duplicados utilizando la pila local
            if (item['name_value'] in self.hostnames):
                continue

            # Agrega el subdominio encontrado a la pila local
            self.hostnames.append(item['name_value'])

            # Agrega el subdominio encontrado a la pila global de resultados
            self.context.addHostName(
                hostname=item['name_value'],
                messageFormat=self.context.strings['methods']['crt-sh']
                ['item-found'])