diff --git a/.github/workflows/theHarvester.yml b/.github/workflows/theHarvester.yml
index 674cbea8..113c9d8e 100644
--- a/.github/workflows/theHarvester.yml
+++ b/.github/workflows/theHarvester.yml
@@ -1,13 +1,14 @@
+---
name: TheHarvester Python CI
on:
push:
branches:
- - '*'
+ - '*'
pull_request:
branches:
- - '*'
+ - '*'
jobs:
Python:
@@ -15,141 +16,113 @@ jobs:
strategy:
max-parallel: 8
matrix:
- os: [ubuntu-latest, macos-latest]
- python-version: [3.8, 3.9, 3.10.0]
+ os: [ ubuntu-latest, macos-latest ]
+ python-version: [ 3.8, 3.9, 3.10.0 ]
steps:
- - uses: actions/checkout@v3
- - name: Python ${{ matrix.python-version }}
- uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
- - name: Install dependencies
- run: |
- pip install --upgrade pip
- pip install wheel
- pip install -r requirements/dev.txt
+ - uses: actions/checkout@v3
+ - name: Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ pip install --upgrade pip
+ pip install wheel
+ pip install -r requirements/dev.txt
- - name: Lint with flake8
- run: |
- # stop the build if there are Python syntax errors or undefined names
- flake8 . --count --show-source --statistics
- # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
- flake8 . --count --exit-zero --max-line-length=127 --statistics
+ - name: Lint with flake8
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ flake8 . --count --show-source --statistics
+ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+ flake8 . --count --exit-zero --max-line-length=127 --statistics
- - name: Test with pytest
- run: |
- pytest
+ - name: Test with pytest
+ run: |
+ pytest
- - name: Static type checking with mypy
- run: |
- mypy --pretty theHarvester/*/*.py
- mypy --pretty theHarvester/*/*/*.py
+ - name: Static type checking with mypy
+ run: |
+ mypy --pretty theHarvester/*/*.py
+ mypy --pretty theHarvester/*/*/*.py
- - name: Run theHarvester module Anubis
- run: |
- python theHarvester.py -d apple.com -b anubis
+ - name: Run theHarvester module Anubis
+ run: |
+ python theHarvester.py -d apple.com -b anubis
- - name: Run theHarvester module Baidu
- run: |
- python theHarvester.py -d yale.edu -b baidu
+ - name: Run theHarvester module Baidu
+ run: |
+ python theHarvester.py -d yale.edu -b baidu
- - name: Run theHarvester module Bufferoverun
- run: |
- python theHarvester.py -d yale.edu -b bufferoverun
+ - name: Run theHarvester module Bufferoverun
+ run: |
+ python theHarvester.py -d yale.edu -b bufferoverun
- - name: Run theHarvester module Bing
- run: |
- python theHarvester.py -d yale.edu -b bing
+ - name: Run theHarvester module Bing
+ run: |
+ python theHarvester.py -d yale.edu -b bing
- - name: Run theHarvester module CertSpotter
- run: |
- python theHarvester.py -d yale.edu -b certspotter
+ - name: Run theHarvester module CertSpotter
+ run: |
+ python theHarvester.py -d yale.edu -b certspotter
- - name: Run theHarvester module Crtsh
- run: |
- python theHarvester.py -d hcl.com -b crtsh
+ - name: Run theHarvester module Crtsh
+ run: |
+ python theHarvester.py -d hcl.com -b crtsh
- - name: Run theHarvester module DnsDumpster
- run: |
- python theHarvester.py -d yale.edu -b dnsdumpster
+ - name: Run theHarvester module DnsDumpster
+ run: |
+ python theHarvester.py -d yale.edu -b dnsdumpster
- - name: Run theHarvester module DuckDuckGo
- run: |
- python theHarvester.py -d yale.edu -b duckduckgo
+ - name: Run theHarvester module DuckDuckGo
+ run: |
+ python theHarvester.py -d yale.edu -b duckduckgo
- - name: Run theHarvester module Google
- run: |
- python theHarvester.py -d yale.edu -b google
+ - name: Run theHarvester module HackerTarget
+ run: |
+ python theHarvester.py -d yale.edu -b hackertarget
- - name: Run theHarvester module HackerTarget
- run: |
- python theHarvester.py -d yale.edu -b hackertarget
+ - name: Run theHarvester module Intelx
+ run: |
+ python theHarvester.py -d yale.edu -b intelx
- - name: Run theHarvester module Intelx
- run: |
- python theHarvester.py -d yale.edu -b intelx
+ - name: Run theHarvester module Omnisint
+ run: |
+ python theHarvester.py -d yale.edu -b omnisint
- - name: Run theHarvester module LinkedIn
- run: |
- python theHarvester.py -d yale.edu -b linkedin
+ - name: Run theHarvester module Otx
+ run: |
+ python theHarvester.py -d yale.edu -b otx
- - name: Run theHarvester module Linkedin links
- run: |
- python theHarvester.py -d yale.edu -b linkedin_links
+ - name: Run theHarvester module Qwant
+ run: |
+ python theHarvester.py -d yale.edu -b qwant
- - name: Run theHarvester module N45ht
- run: |
- python theHarvester.py -d yale.edu -b n45ht
+ - name: Run theHarvester module RapidDns
+ run: |
+ python theHarvester.py -d yale.edu -b rapiddns
- - name: Run theHarvester module Omnisint
- run: |
- python theHarvester.py -d yale.edu -b omnisint
+ - name: Run theHarvester module Sublist3r
+ run: |
+ python theHarvester.py -d yale.edu -b sublist3r
- - name: Run theHarvester module Otx
- run: |
- python theHarvester.py -d yale.edu -b otx
+ - name: Run theHarvester module Threatcrowd
+ run: |
+ python theHarvester.py -d yale.edu -b threatcrowd
- - name: Run theHarvester module Qwant
- run: |
- python theHarvester.py -d yale.edu -b qwant
+ - name: Run theHarvester module Threatminer
+ run: |
+ python theHarvester.py -d yale.edu -b threatminer
- - name: Run theHarvester module RapidDns
- run: |
- python theHarvester.py -d yale.edu -b rapiddns
+ - name: Run theHarvester module Urlscan
+ run: |
+ python theHarvester.py -d yale.edu -b urlscan
- - name: Run theHarvester module Sublist3r
- run: |
- python theHarvester.py -d yale.edu -b sublist3r
+ - name: Run theHarvester module Yahoo
+ run: |
+ python theHarvester.py -d yale.edu -b yahoo
- - name: Run theHarvester module Threatcrowd
- run: |
- python theHarvester.py -d yale.edu -b threatcrowd
-
- - name: Run theHarvester module Threatminer
- run: |
- python theHarvester.py -d yale.edu -b threatminer
-
- - name: Run theHarvester module Trello
- run: |
- python theHarvester.py -d yale.edu -b trello
-
- - name: Run theHarvester module Twitter
- run: |
- python theHarvester.py -d yale.edu -b twitter
-
- - name: Run theHarvester module Urlscan
- run: |
- python theHarvester.py -d yale.edu -b urlscan
-
- - name: Run theHarvester module Virustotal
- run: |
- python theHarvester.py -d yale.edu -b virustotal
-
- - name: Run theHarvester module Yahoo
- run: |
- python theHarvester.py -d yale.edu -b yahoo
-
- - name: Run theHarvester module DNS brute force
- run: |
- python theHarvester.py -d yale.edu -c
+ - name: Run theHarvester module DNS brute force
+ run: |
+ python theHarvester.py -d yale.edu -c
diff --git a/Dockerfile b/Dockerfile
index e9dfa37c..6b095107 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:impish
+FROM ubuntu:kinetic
LABEL maintainer="@jay_townsend1 & @NotoriousRebel1"
RUN mkdir /app
WORKDIR /app
diff --git a/README.md b/README.md
index e6c276f3..42ce7ca0 100644
--- a/README.md
+++ b/README.md
@@ -38,20 +38,12 @@ Passive:
* github-code: GitHub code search engine (Requires a GitHub Personal Access Token, see below.) - www.github.com
-* google: Google search engine (Optional Google dorking.) - www.google.com
-
* hackertarget: Online vulnerability scanners and network intelligence to help organizations - https://hackertarget.com
* hunter: Hunter search engine (Requires an API key, see below.) - www.hunter.io
* intelx: Intelx search engine (Requires an API key, see below.) - www.intelx.io
-* linkedin: Google search engine, specific search for LinkedIn users - www.linkedin.com
-
-* linkedin_links: specific search for LinkedIn users for target domain (Uses Google search.)
-
-* n45ht: - https://n45ht.or.id
-
* omnisint: Project Crobat, A Centralised Searchable Open Source Project Sonar DNS Database - https://github.com/Cgboal/SonarSearch
* otx: AlienVault Open Threat Exchange - https://otx.alienvault.com
@@ -80,10 +72,6 @@ Passive:
* threatminer: Data mining for threat intelligence - https://www.threatminer.org/
-* trello: Search trello boards (Uses Google search.)
-
-* twitter: Twitter accounts related to a specific domain (Uses Google search.)
-
* urlscan: A sandbox for the web that is a URL and website scanner - https://urlscan.io
* vhost: Bing virtual hosts search
@@ -109,7 +97,7 @@ Documentation to setup API keys can be found at - https://github.com/laramies/th
* censys - API keys are required and can be retrieved from your [Censys account](https://search.censys.io/account/api).
* fullhunt
* github
-* hunter - limited to 10 on the free plan so you will need to do -l 10 switch
+* hunter - limited to 10 on the free plan, so you will need to do -l 10 switch
* intelx
* pentesttools - not free
* projecdiscovery - invite only for now
diff --git a/api-keys.yaml b/api-keys.yaml
index 7ca5aa1c..f060fe1c 100644
--- a/api-keys.yaml
+++ b/api-keys.yaml
@@ -36,7 +36,7 @@ apikeys:
shodan:
key:
- spyse:
+ virustotal:
key:
zoomeye:
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 00000000..a7109d12
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,4 @@
+[pytest]
+minversion = 7.1.1
+testpaths = tests
+asyncio_mode=auto
\ No newline at end of file
diff --git a/requirements/base.txt b/requirements/base.txt
index e5d89875..abcf51e9 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -18,7 +18,5 @@ retrying==1.3.3
setuptools==63.3.0
shodan==1.28.0
slowapi==0.1.5
--e git+https://github.com/L1ghtn1ng/spyse-python@main#egg=spyse-python
-starlette==0.19.1
uvicorn==0.18.2
uvloop==0.16.0; platform_system != "Windows"
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..777ae408
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+ignore = E501, F405, F403, E402, F401
\ No newline at end of file
diff --git a/tests/discovery/test_githubcode.py b/tests/discovery/test_githubcode.py
index 248e3038..0e7d52d6 100644
--- a/tests/discovery/test_githubcode.py
+++ b/tests/discovery/test_githubcode.py
@@ -87,13 +87,13 @@ class TestSearchGithubCode:
Core.github_key = MagicMock(return_value="lol")
test_class_instance = githubcode.SearchGithubCode(word="test", limit=500)
test_result = githubcode.SuccessResult(list(), next_page=2, last_page=4)
- assert(2 == await test_class_instance.next_page_or_end(test_result))
+ assert (2 == await test_class_instance.next_page_or_end(test_result))
async def test_last_page(self):
Core.github_key = MagicMock(return_value="lol")
test_class_instance = githubcode.SearchGithubCode(word="test", limit=500)
test_result = githubcode.SuccessResult(list(), None, None)
- assert(None is await test_class_instance.next_page_or_end(test_result))
+ assert (None is await test_class_instance.next_page_or_end(test_result))
if __name__ == '__main__':
pytest.main()
diff --git a/tests/discovery/test_linkedin_links.py b/tests/discovery/test_linkedin_links.py
deleted file mode 100644
index a7de4d6f..00000000
--- a/tests/discovery/test_linkedin_links.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python3
-# coding=utf-8
-from theHarvester.discovery import linkedinsearch
-from theHarvester.discovery.constants import splitter
-import os
-import re
-import pytest
-
-pytestmark = pytest.mark.asyncio
-github_ci = os.getenv('GITHUB_ACTIONS') # Github set this to be the following: true instead of True
-
-
-class TestGetLinks(object):
-
- async def test_splitter(self):
- results = [
- 'https://www.linkedin.com/in/don-draper-b1045618',
- 'https://www.linkedin.com/in/don-draper-b59210a',
- 'https://www.linkedin.com/in/don-draper-b5bb50b3',
- 'https://www.linkedin.com/in/don-draper-b83ba26',
- 'https://www.linkedin.com/in/don-draper-b854a51'
- ]
- filtered_results = await splitter(results)
- assert len(filtered_results) == 1
-
- async def test_get_links(self):
- search = linkedinsearch.SearchLinkedin("facebook.com", '100')
- await search.process()
- links = await search.get_links()
- assert isinstance(links, list)
-
- async def test_links_linkedin(self):
- dir_path = os.path.dirname(os.path.realpath(__file__))
- mock_response = open(dir_path + "/test_linkedin_links.txt")
- mock_response_content = mock_response.read()
- mock_response.close()
- reg_links = re.compile(r"url=https:\/\/www\.linkedin.com(.*?)&")
- temp = reg_links.findall(mock_response_content)
- resul = []
- for regex_item in temp:
- stripped_url = regex_item.replace("url=", "")
- resul.append("https://www.linkedin.com" + stripped_url)
- assert set(resul)
-
-
-if __name__ == '__main__':
- pytest.main()
diff --git a/tests/discovery/test_linkedin_links.txt b/tests/discovery/test_linkedin_links.txt
deleted file mode 100644
index b8804830..00000000
--- a/tests/discovery/test_linkedin_links.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-LinkedIn
https://www.linkedin.com/in/gm-tuhin-ialam-546526b8
Albany, New York Area - Facebook Advertising
Gm Tuhin.ialam. facebook.com at Facebook Advertising. Albany, New York Area.
-Marketing and Advertising. Facebook Advertising. 0 connections ...https://in.linkedin.com/in/nikulact Ahmedabad Area, India - Self Modeling
View NIKUL www.facebook.com/nikulact's profile on LinkedIn, the world's largest
-professional community. NIKUL has 1 job listed on their profile. See the ...https://www.linkedin.com/in/victor-scott-9a967343
Albany, New York Area - Alchemy of Time
Victor Scott. Metal Band facebook.com/alchemyoftime at Alchemy of Time. Albany
-, New York Area. Music. Alchemy of Time. 1 connection ...https://www.linkedin.com/in/elkhorbat-lkhorbat-6028b33a
United States - http://www.facebook.com/pages/elkhorbat/302997479939
View elkhorbat lkhorbat's profile on LinkedIn, the world's largest professional
-community. elkhorbat has 1 job listed on their profile. See the complete profile on
diff --git a/tests/discovery/test_n45ht.py b/tests/discovery/test_n45ht.py
deleted file mode 100644
index 10a87000..00000000
--- a/tests/discovery/test_n45ht.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env python3
-# coding=utf-8
-from theHarvester.lib.core import *
-from theHarvester.discovery import n45htsearch
-import os
-import requests
-import pytest
-
-pytestmark = pytest.mark.asyncio
-github_ci = os.getenv('GITHUB_ACTIONS') # Github set this to be the following: true instead of True
-
-
-class TestN45ht(object):
- @staticmethod
- def domain() -> str:
- return 'uber.com'
-
- async def test_api(self):
- base_url = f'https://api.n45ht.or.id/v1/subdomain-enumeration?domain={TestN45ht.domain()}'
- headers = {'User-Agent': Core.get_user_agent()}
- request = requests.get(base_url, headers=headers)
- assert request.status_code == 200
-
- async def test_do_search(self):
- search = n45htsearch.SearchN45ht(TestN45ht.domain())
- await search.process()
- assert isinstance(await search.get_hostnames(), set)
-
-
-if __name__ == '__main__':
- pytest.main()
diff --git a/tests/discovery/test_otx.py b/tests/discovery/test_otx.py
index 30b2d94d..acc41c4c 100644
--- a/tests/discovery/test_otx.py
+++ b/tests/discovery/test_otx.py
@@ -27,12 +27,6 @@ class TestOtx(object):
assert isinstance(await search.get_hostnames(), set)
assert isinstance(await search.get_ips(), set)
- async def test_search_no_results(self):
- search = otxsearch.SearchOtx('radiant.eu')
- await search.process()
- assert len(await search.get_hostnames()) == 0
- assert len(await search.get_ips()) == 0
-
if __name__ == '__main__':
pytest.main()
diff --git a/tests/discovery/test_qwantsearch.py b/tests/discovery/test_qwantsearch.py
index 8452653e..2fdcad4d 100644
--- a/tests/discovery/test_qwantsearch.py
+++ b/tests/discovery/test_qwantsearch.py
@@ -14,15 +14,15 @@ class TestSearchQwant(object):
def domain() -> str:
return 'example.com'
- def test_get_start_offset_return_0(self):
+ async def test_get_start_offset_return_0(self):
search = qwantsearch.SearchQwant(TestSearchQwant.domain(), 0, 200)
assert search.get_start_offset() == 0
- def test_get_start_offset_return_50(self):
+ async def test_get_start_offset_return_50(self):
search = qwantsearch.SearchQwant(TestSearchQwant.domain(), 55, 200)
assert search.get_start_offset() == 50
- def test_get_start_offset_return_100(self):
+ async def test_get_start_offset_return_100(self):
search = qwantsearch.SearchQwant(TestSearchQwant.domain(), 100, 200)
assert search.get_start_offset() == 100
diff --git a/theHarvester/__main__.py b/theHarvester/__main__.py
index 68e9c7f4..ce74c757 100644
--- a/theHarvester/__main__.py
+++ b/theHarvester/__main__.py
@@ -22,23 +22,20 @@ async def start(rest_args=None):
parser.add_argument('-d', '--domain', help='Company name or domain to search.', required=True)
parser.add_argument('-l', '--limit', help='Limit the number of search results, default=500.', default=500, type=int)
parser.add_argument('-S', '--start', help='Start with result number X, default=0.', default=0, type=int)
- parser.add_argument('-g', '--google-dork', help='Use Google Dorks for Google search.', default=False, action='store_true')
parser.add_argument('-p', '--proxies', help='Use proxies for requests, enter proxies in proxies.yaml.', default=False, action='store_true')
parser.add_argument('-s', '--shodan', help='Use Shodan to query discovered hosts.', default=False, action='store_true')
parser.add_argument('--screenshot', help='Take screenshots of resolved domains specify output directory: --screenshot output_directory', default="", type=str)
parser.add_argument('-v', '--virtual-host', help='Verify host name via DNS resolution and search for virtual hosts.', action='store_const', const='basic', default=False)
parser.add_argument('-e', '--dns-server', help='DNS server to use for lookup.')
- parser.add_argument('-t', '--dns-tld', help='Perform a DNS TLD expansion discovery, default False.', default=False)
parser.add_argument('-r', '--take-over', help='Check for takeovers.', default=False, action='store_true')
parser.add_argument('-n', '--dns-lookup', help='Enable DNS server lookup, default False.', default=False, action='store_true')
parser.add_argument('-c', '--dns-brute', help='Perform a DNS brute force on the domain.', default=False, action='store_true')
parser.add_argument('-f', '--filename', help='Save the results to an XML and JSON file.', default='', type=str)
parser.add_argument('-b', '--source', help='''anubis, baidu, bing, binaryedge, bingapi, bufferoverun, censys, certspotter, crtsh,
- dnsdumpster, duckduckgo, fullhunt, github-code, google,
- hackertarget, hunter, intelx, linkedin, linkedin_links, n45ht,
+ dnsdumpster, duckduckgo, fullhunt, github-code, hackertarget, hunter, intelx,
omnisint, otx, pentesttools, projectdiscovery,
- qwant, rapiddns, rocketreach, securityTrails, spyse, sublist3r, threatcrowd, threatminer,
- trello, twitter, urlscan, virustotal, yahoo, zoomeye''')
+ qwant, rapiddns, rocketreach, securityTrails, sublist3r, threatcrowd, threatminer,
+ urlscan, virustotal, yahoo, zoomeye''')
# determines if filename is coming from rest api or user
rest_filename = ''
@@ -73,13 +70,11 @@ async def start(rest_args=None):
all_ip: List = []
dnslookup = args.dns_lookup
dnsserver = args.dns_server
- dnstld = args.dns_tld
engines: List = []
# If the user specifies
full: List = []
ips: List = []
- google_dorking = args.google_dork
host_ip: List = []
limit: int = args.limit
shodan = args.shodan
@@ -127,7 +122,7 @@ async def start(rest_args=None):
search_engine.process(process_param, use_proxy)
db_stash = stash.StashManager()
if source:
- print(f'\033[94m[*] Searching {source[0].upper() + source[1:]}. \033[0m')
+ print(f'\033[94m[*] Searching {source[0].upper() + source[1:]}. ')
if store_host:
host_names = [host for host in filter(await search_engine.get_hostnames()) if f'.{word}' in host]
if source != 'hackertarget' and source != 'pentesttools' and source != 'rapiddns':
@@ -158,10 +153,6 @@ async def start(rest_args=None):
await db.store_all(word, all_emails, 'email', source)
if store_people:
people_list = await search_engine.get_people()
- if source == 'twitter':
- twitter_people_list_tracker.extend(people_list)
- if source == 'linkedin':
- linkedin_people_list_tracker.extend(people_list)
await db_stash.store_all(word, people_list, 'people', source)
if store_links:
@@ -189,7 +180,7 @@ async def start(rest_args=None):
engines = Core.get_supportedengines()
# Iterate through search engines in order
if set(engines).issubset(Core.get_supportedengines()):
- print(f'\033[94m[*] Target: {word} \n \033[0m')
+ print(f'\n[*] Target: {word} \n')
for engineitem in engines:
if engineitem == 'anubis':
@@ -264,7 +255,7 @@ async def start(rest_args=None):
crtsh_search = crtsh.SearchCrtsh(word)
stor_lst.append(store(crtsh_search, 'CRTsh', store_host=True))
except Exception as e:
- print(f'\033[93m[!] A timeout occurred with crtsh, cannot find {args.domain}\n {e}\033[0m')
+ print(f'[!] A timeout occurred with crtsh, cannot find {args.domain}\n {e}')
elif engineitem == 'dnsdumpster':
try:
@@ -272,7 +263,7 @@ async def start(rest_args=None):
dns_dumpster_search = dnsdumpster.SearchDnsDumpster(word)
stor_lst.append(store(dns_dumpster_search, engineitem, store_host=True, store_ip=True))
except Exception as e:
- print(f'\033[93m[!] An error occurred with dnsdumpster: {e} \033[0m')
+ print(f'[!] An error occurred with dnsdumpster: {e}')
elif engineitem == 'duckduckgo':
from theHarvester.discovery import duckduckgosearch
@@ -298,12 +289,6 @@ async def start(rest_args=None):
else:
pass
- elif engineitem == 'google':
- from theHarvester.discovery import googlesearch
- google_search = googlesearch.SearchGoogle(word, limit, start)
- stor_lst.append(store(google_search, engineitem, process_param=google_dorking, store_host=True,
- store_emails=True))
-
elif engineitem == 'hackertarget':
from theHarvester.discovery import hackertarget
hackertarget_search = hackertarget.SearchHackerTarget(word)
@@ -333,24 +318,6 @@ async def start(rest_args=None):
else:
print(f'An exception has occurred in Intelx search: {e}')
- elif engineitem == 'linkedin':
- from theHarvester.discovery import linkedinsearch
- linkedin_search = linkedinsearch.SearchLinkedin(word, limit)
- stor_lst.append(store(linkedin_search, engineitem, store_people=True))
-
- elif engineitem == 'linkedin_links':
- from theHarvester.discovery import linkedinsearch
- linkedin_links_search = linkedinsearch.SearchLinkedin(word, limit)
- stor_lst.append(store(linkedin_links_search, 'linkedin', store_links=True))
-
- elif engineitem == 'n45ht':
- from theHarvester.discovery import n45htsearch
- try:
- n45ht_search = n45htsearch.SearchN45ht(word)
- stor_lst.append(store(n45ht_search, engineitem, store_host=True))
- except Exception as e:
- print(e)
-
elif engineitem == 'omnisint':
from theHarvester.discovery import omnisint
try:
@@ -432,14 +399,6 @@ async def start(rest_args=None):
except Exception as e:
print(e)
- elif engineitem == 'spyse':
- from theHarvester.discovery import spyse
- try:
- spyse_search = spyse.SearchSpyse(word, limit)
- stor_lst.append(store(spyse_search, engineitem, store_host=True, store_ip=True))
- except Exception as e:
- print(e)
-
elif engineitem == 'threatcrowd':
from theHarvester.discovery import threatcrowd
try:
@@ -456,17 +415,6 @@ async def start(rest_args=None):
except Exception as e:
print(e)
- elif engineitem == 'trello':
- from theHarvester.discovery import trello
- # Import locally or won't work.
- trello_search = trello.SearchTrello(word)
- stor_lst.append(store(trello_search, engineitem, store_results=True))
-
- elif engineitem == 'twitter':
- from theHarvester.discovery import twittersearch
- twitter_search = twittersearch.SearchTwitter(word, limit)
- stor_lst.append(store(twitter_search, engineitem, store_people=True))
-
elif engineitem == 'urlscan':
from theHarvester.discovery import urlscan
try:
@@ -477,9 +425,15 @@ async def start(rest_args=None):
print(e)
elif engineitem == 'virustotal':
- from theHarvester.discovery import virustotal
- virustotal_search = virustotal.SearchVirustotal(word)
- stor_lst.append(store(virustotal_search, engineitem, store_host=True))
+ try:
+ from theHarvester.discovery import virustotal
+ virustotal_search = virustotal.SearchVirustotal(word)
+ stor_lst.append(store(virustotal_search, engineitem, store_host=True))
+ except Exception as e:
+ if isinstance(e, MissingKey):
+ print(e)
+ else:
+ pass
elif engineitem == 'yahoo':
from theHarvester.discovery import yahoosearch
@@ -502,7 +456,7 @@ async def start(rest_args=None):
# Check if dns_brute is defined
rest_args.dns_brute
except Exception:
- print('\033[93m[!] Invalid source.\n\n \033[0m')
+ print('\n[!] Invalid source.\n')
sys.exit(1)
async def worker(queue):
@@ -540,7 +494,7 @@ async def start(rest_args=None):
await handler(lst=stor_lst)
return_ips: List = []
if rest_args is not None and len(rest_filename) == 0 and rest_args.dns_brute is False:
- # Indicates user is using rest api but not wanting output to be saved to a file
+ # Indicates user is using REST api but not wanting output to be saved to a file
full = [host if ':' in host and word in host else word in host.split(':')[0] and host for host in full]
full = list({host for host in full if host})
full.sort()
@@ -549,16 +503,16 @@ async def start(rest_args=None):
# return list(set(all_emails)), return_ips, full, '', ''
return total_asns, interesting_urls, twitter_people_list_tracker, linkedin_people_list_tracker, \
linkedin_links_tracker, all_urls, all_ip, all_emails, all_hosts
- # Sanity check to see if all_emails and all_hosts are defined.
+ # Check to see if all_emails and all_hosts are defined.
try:
all_emails
except NameError:
- print('\n\n\033[93m[!] No emails found because all_emails is not defined.\n\n \033[0m')
+ print('\n\n[!] No emails found because all_emails is not defined.\n\n ')
sys.exit(1)
try:
all_hosts
except NameError:
- print('\n\n\033[93m[!] No hosts found because all_hosts is not defined.\n\n \033[0m')
+ print('\n\n[!] No hosts found because all_hosts is not defined.\n\n ')
sys.exit(1)
# Results
@@ -705,20 +659,6 @@ async def start(rest_args=None):
for xh in dnsrev:
print(xh)
- # DNS TLD expansion
- dnstldres = []
- if dnstld is True:
- print('[*] Starting DNS TLD expansion.')
- a = dnssearch.DnsTld(word, dnsserver, verbose=True)
- res = a.process()
- print('\n[*] Hosts found after DNS TLD expansion:')
- print('----------------------------------------')
- for y in res:
- print(y)
- dnstldres.append(y)
- if y not in full:
- full.append(y)
-
# Virtual hosts search
if virtual == 'basic':
print('\n[*] Virtual hosts:')
@@ -746,7 +686,7 @@ async def start(rest_args=None):
from theHarvester.screenshot.screenshot import ScreenShotter
screen_shotter = ScreenShotter(args.screenshot)
path_exists = screen_shotter.verify_path()
- # Verify path exists if not create it or if user does not create it skip screenshot
+ # Verify path exists, if not create it or if user does not create it skips screenshot
if path_exists:
await screen_shotter.verify_installation()
print(f'\nScreenshots can be found in: {screen_shotter.output}{screen_shotter.slash}')
@@ -782,7 +722,7 @@ async def start(rest_args=None):
shodanres = []
if shodan is True:
import json
- print('\033[94m[*] Searching Shodan. \033[0m')
+ print('\033[94m[*] Searching Shodan. ')
try:
for ip in host_ip:
print(('\tSearching for ' + ip))
@@ -803,21 +743,7 @@ async def start(rest_args=None):
print(json.dumps(shodandict[ip], indent=4, sort_keys=True))
print('\n')
except Exception as e:
- print(f'\033[93m[!] An error occurred with Shodan: {e} \033[0m')
- else:
- pass
-
- # Here we need to add explosion mode.
- # We have to take out the TLDs to do this.
- if args.dns_tld is not False:
- counter = 0
- for word in vhost:
- search_google = googlesearch.SearchGoogle(word, limit, counter)
- await search_google.process(google_dorking)
- emails = await search_google.get_emails()
- hosts = await search_google.get_hostnames()
- print(emails)
- print(hosts)
+ print(f'[!] An error occurred with Shodan: {e} ')
else:
pass
@@ -850,7 +776,7 @@ async def start(rest_args=None):
file.write('')
print('[*] XML File saved.')
except Exception as error:
- print(f'\033[93m[!] An error occurred while saving the XML file: {error} \033[0m')
+ print(f'[!] An error occurred while saving the XML file: {error}')
try:
# JSON REPORT SECTION
@@ -858,7 +784,7 @@ async def start(rest_args=None):
# create dict with values for json output
json_dict: Dict = dict()
# determine if variable exists
- # it should but just a sanity check
+ # it should but just a validation check
if 'ip_list' in locals():
if all_ip and len(all_ip) >= 1 and ip_list and len(ip_list) > 0:
json_dict["ips"] = [str(ip) for ip in ip_list]
@@ -897,7 +823,7 @@ async def start(rest_args=None):
fp.write(ujson.dumps(json_dict, sort_keys=True))
print('[*] JSON File saved.')
except Exception as er:
- print(f'\033[93m[!] An error occurred while saving the JSON file: {er} \033[0m')
+ print(f'[!] An error occurred while saving the JSON file: {er} ')
print('\n\n')
sys.exit(0)
@@ -907,7 +833,7 @@ async def entry_point():
Core.banner()
await start()
except KeyboardInterrupt:
- print('\n\n\033[93m[!] ctrl+c detected from user, quitting.\n\n \033[0m')
+ print('\n\n[!] ctrl+c detected from user, quitting.\n\n ')
except Exception as error_entry_point:
print(error_entry_point)
sys.exit(1)
diff --git a/theHarvester/discovery/certspottersearch.py b/theHarvester/discovery/certspottersearch.py
index bbb97791..d00fe9a1 100644
--- a/theHarvester/discovery/certspottersearch.py
+++ b/theHarvester/discovery/certspottersearch.py
@@ -19,7 +19,7 @@ class SearchCertspoter:
if key == 'dns_names':
self.totalhosts.update({name for name in value if name})
elif isinstance(response, dict):
- self.totalhosts.update({response['dns_names'] if 'dns_names' in response.keys() else ''})
+ self.totalhosts.update({response['dns_names'] if 'dns_names' in response.keys() else ''}) # type: ignore
else:
self.totalhosts.update({''})
except Exception as e:
diff --git a/theHarvester/discovery/crtsh.py b/theHarvester/discovery/crtsh.py
index 8c1696f5..4a759ddd 100644
--- a/theHarvester/discovery/crtsh.py
+++ b/theHarvester/discovery/crtsh.py
@@ -1,5 +1,5 @@
from theHarvester.lib.core import *
-from typing import List
+from typing import List, Set
class SearchCrtsh:
diff --git a/theHarvester/discovery/dnssearch.py b/theHarvester/discovery/dnssearch.py
index 525ac3f7..a5a4e456 100644
--- a/theHarvester/discovery/dnssearch.py
+++ b/theHarvester/discovery/dnssearch.py
@@ -66,9 +66,7 @@ NETWORK_REGEX = r'\b({})(?:\:({}))?(?:\/({}))?\b'.format(
NETMASK_REGEX)
-def serialize_ip_range(
- ip: str,
- netmask: str = '24') -> str:
+def serialize_ip_range(ip: str, netmask: str = '24') -> str:
"""
Serialize a network range in a constant format, 'x.x.x.x/y'.
diff --git a/theHarvester/discovery/googlesearch.py b/theHarvester/discovery/googlesearch.py
deleted file mode 100644
index 67dfed2a..00000000
--- a/theHarvester/discovery/googlesearch.py
+++ /dev/null
@@ -1,172 +0,0 @@
-from theHarvester.discovery.constants import *
-from theHarvester.parsers import myparser
-import asyncio
-
-
-class SearchGoogle:
-
- def __init__(self, word, limit, start):
- self.word = word
- self.results = ""
- self.totalresults = ""
- self.server = 'www.google.com'
- self.dorks = []
- self.links = []
- self.database = 'https://www.google.com/search?q='
- self.quantity = '100'
- self.limit = limit
- self.counter = start
- self.proxy = False
-
- async def do_search(self):
- # Do normal scraping.
- urly = 'http://' + self.server + '/search?num=' + self.quantity + '&start=' + str(
- self.counter) + '&hl=en&meta=&q=%40\"' + self.word + '\"'
- try:
- headers = {'User-Agent': googleUA}
- resp = await AsyncFetcher.fetch_all([urly], headers=headers, proxy=self.proxy)
- except Exception as e:
- print(e)
- self.results = resp[0]
- searched = await search(self.results)
- if searched:
- try:
- self.results = await google_workaround(urly)
- if isinstance(self.results, bool):
- print('Google is blocking your ip and the workaround, returning')
- return
- except Exception as e:
- print(e)
- # google blocked, no useful result
- return
- await asyncio.sleep(get_delay())
- self.totalresults += self.results
-
- async def do_search_profiles(self):
- urly = 'http://' + self.server + '/search?num=' + self.quantity + '&start=' + str(
- self.counter) + '&hl=en&meta=&q=site:www.google.com%20intitle:\"Google%20Profile\"%20\"Companies%20I%27ve%20worked%20for\"%20\"at%20' + self.word + '\"'
- try:
- headers = {'User-Agent': googleUA}
- resp = await AsyncFetcher.fetch_all([urly], headers=headers, proxy=self.proxy)
- except Exception as e:
- print(e)
- self.results = resp[0]
- if await search(self.results):
- try:
- self.results = await google_workaround(urly)
- if isinstance(self.results, bool):
- print('Google is blocking your ip and the workaround, returning')
- return
- except Exception:
- # google blocked, no useful result
- return
- await asyncio.sleep(get_delay())
- self.totalresults += self.results
-
- async def get_emails(self):
- rawres = myparser.Parser(self.totalresults, self.word)
- return await rawres.emails()
-
- async def get_hostnames(self):
- rawres = myparser.Parser(self.totalresults, self.word)
- return await rawres.hostnames()
-
- async def get_files(self):
- rawres = myparser.Parser(self.totalresults, self.word)
- return rawres.fileurls(self.files)
-
- async def get_profiles(self):
- rawres = myparser.Parser(self.totalresults, self.word)
- return rawres.profiles()
-
- async def process(self, google_dorking, proxy=False):
- self.proxy = proxy
- if google_dorking is False:
- while self.counter <= self.limit and self.counter <= 1000:
- await self.do_search()
- print(f'\tSearching {self.counter} results.')
- self.counter += 100
- else: # Google dorking is true.
- self.counter = 0 # Reset counter.
- print('\n')
- print('[-] Searching with Google Dorks: ')
- await self.googledork() # Call Google dorking method if user wanted it!
-
- async def process_profiles(self):
- while self.counter < self.limit:
- await self.do_search_profiles()
- await asyncio.sleep(get_delay())
- self.counter += 100
- print(f'\tSearching {self.counter} results.')
-
- async def append_dorks(self):
- # Wrap in try-except in case filepaths are messed up.
- try:
- with open('/etc/theHarvester/wordlists/dorks.txt', 'r') as fp:
- self.dorks = [dork.strip() for dork in fp]
- except FileNotFoundError:
- try:
- with open('/usr/local/etc/theHarvester/wordlists/dorks.txt', 'r') as fp:
- self.dorks = [dork.strip() for dork in fp]
- except FileNotFoundError:
- try:
- with open('wordlists/dorks.txt', 'r') as fp:
- self.dorks = [dork.strip() for dork in fp]
- except FileNotFoundError as error:
- print(error)
-
- async def construct_dorks(self):
- # Format is: site:targetwebsite.com + space + inurl:admindork
- colon = '%3A'
- plus = '%2B'
- space = '+'
- period = '%2E'
- double_quote = '%22'
- asterick = '%2A'
- left_bracket = '%5B'
- right_bracket = '%5D'
- question_mark = '%3F'
- slash = '%2F'
- single_quote = '%27'
- ampersand = '%26'
- left_peren = '%28'
- right_peren = '%29'
- pipe = '%7C'
- # Format is google.com/search?q=dork+space+self.word
- self.links = tuple(
- self.database + str(dork).replace(':', colon).replace('+', plus).replace('.', period).replace('"',
- double_quote)
- .replace('*', asterick).replace('[', left_bracket).replace(']', right_bracket)
- .replace('?', question_mark).replace(' ', space).replace('/', slash).replace("'", single_quote)
- .replace('&', ampersand).replace('(', left_peren).replace(')', right_peren).replace('|',
- pipe) + space + self.word
- for dork in self.dorks)
-
- async def googledork(self):
- await self.append_dorks() # Call functions to create list.
- await self.construct_dorks()
- await self.send_dorks()
-
- async def send_dorks(self): # Helper function to minimize code reusability.
- headers = {'User-Agent': googleUA}
- # Get random user agent to try and prevent google from blocking IP.
- for num in range(len(self.links)):
- try:
- if num % 10 == 0 and num > 0:
- print(f'\tSearching through {num} results')
- link = self.links[num]
- req = await AsyncFetcher.fetch_all([link], headers=headers, proxy=self.proxy)
- self.results = req[0]
- if await search(self.results):
- try:
- self.results = await google_workaround(link)
- if isinstance(self.results, bool):
- print('Google is blocking your ip and the workaround, returning')
- return
- except Exception:
- # google blocked, no useful result
- return
- await asyncio.sleep(get_delay())
- self.totalresults += self.results
- except Exception as e:
- print(f'\tException Occurred {e}')
diff --git a/theHarvester/discovery/linkedinsearch.py b/theHarvester/discovery/linkedinsearch.py
deleted file mode 100644
index 47ff715c..00000000
--- a/theHarvester/discovery/linkedinsearch.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from theHarvester.discovery.constants import *
-from theHarvester.lib.core import *
-from theHarvester.parsers import myparser
-import asyncio
-
-
-class SearchLinkedin:
-
- def __init__(self, word, limit):
- self.word = word.replace(' ', '%20')
- self.results = ""
- self.totalresults = ""
- self.server = 'www.google.com'
- self.quantity = '100'
- self.limit = int(limit)
- self.counter = 0
- self.proxy = False
-
- async def do_search(self):
- urly = 'http://' + self.server + '/search?num=100&start=' + str(self.counter) + '&hl=en&meta=&q=site%3Alinkedin.com/in%20' + self.word
- try:
- headers = {'User-Agent': Core.get_user_agent()}
- resp = await AsyncFetcher.fetch_all([urly], headers=headers, proxy=self.proxy)
- self.results = resp[0]
- if await search(self.results):
- try:
- self.results = await google_workaround(urly)
- if isinstance(self.results, bool):
- print('Google is blocking your ip and the workaround, returning')
- return
- except Exception:
- # google blocked, no useful result
- return
- except Exception as e:
- print(e)
- await asyncio.sleep(get_delay())
- self.totalresults += self.results
-
- async def get_people(self):
- rawres = myparser.Parser(self.totalresults, self.word)
- temp = await rawres.people_linkedin()
- return [person for person in temp
- if person[0] != '.' and '...' not in person and len(person.split()) != 1]
-
- async def get_links(self):
- links = myparser.Parser(self.totalresults, self.word)
- return await splitter(await links.links_linkedin())
-
- async def process(self, proxy=False):
- self.proxy = proxy
- while self.counter < self.limit:
- await self.do_search()
- await asyncio.sleep(get_delay())
- self.counter += 100
- print(f'\tSearching {self.counter} results.')
diff --git a/theHarvester/discovery/n45htsearch.py b/theHarvester/discovery/n45htsearch.py
deleted file mode 100644
index 5360115e..00000000
--- a/theHarvester/discovery/n45htsearch.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from theHarvester.lib.core import *
-
-
-class SearchN45ht:
-
- def __init__(self, word):
- self.word = word
- self.totalhosts = set()
- self.proxy = False
-
- async def do_search(self):
- url = f'https://api.n45ht.or.id/v1/subdomain-enumeration?domain={self.word}'
- response = await AsyncFetcher.fetch_all([url], json=True, proxy=self.proxy)
- responses = response[0]
- dct = responses
- self.totalhosts: set = {host for host in dct['subdomains']}
-
- async def get_hostnames(self) -> set:
- return self.totalhosts
-
- async def process(self, proxy=False):
- self.proxy = proxy
- await self.do_search()
diff --git a/theHarvester/discovery/spyse.py b/theHarvester/discovery/spyse.py
deleted file mode 100644
index f68ad934..00000000
--- a/theHarvester/discovery/spyse.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from theHarvester.discovery.constants import *
-from theHarvester.lib.core import *
-from spyse import Client, SearchQuery, QueryParam, DomainSearchParams, Operators
-
-
-class SearchSpyse:
-
- def __init__(self, word, limit):
- self.ips = set()
- self.word = word
- self.key = Core.spyse_key()
- if self.key is None:
- raise MissingKey('Spyse')
- self.results = ''
- self.hosts = set()
- self.proxy = False
- self.limit = limit
- self.client = Client(self.key)
-
- async def do_search(self):
- fetch_count = 0
-
- query = SearchQuery()
- query.append_param(QueryParam(DomainSearchParams.name, Operators.ends_with, self.word))
-
- try:
- total = self.client.count_domains(query)
- if total == 0:
- return
-
- # The default "Search" method returns only first 10 000 subdomains
- # To obtain more than 10 000 subdomains the "Scroll" method should be using
- # Note: The "Scroll" method is only available for "PRO" customers, so we need to check
- # self.client.account.is_scroll_search_enabled param
- if total > self.client.SEARCH_RESULTS_LIMIT and self.client.account.is_scroll_search_enabled:
- scroll_id = None
- while True:
- scroll_results = self.client.scroll_domains(query, scroll_id)
-
- scroll_id = scroll_results.search_id
- for domain in scroll_results.results:
- self.hosts.add(domain.name)
-
- fetch_count += len(scroll_results.results)
-
- if len(scroll_results.results) == 0 or fetch_count >= self.limit:
- break
- else:
- # Spyse allows to get up to 100 results per one request
- max_limit = 100
- # Spyse "search" methods allows to fetch up to 10 000 first results
- max_offset = 9900
- offset = 0
-
- while True:
- limit = max_limit if self.limit - fetch_count > max_limit else self.limit - fetch_count
- if limit <= 0:
- break
-
- results = self.client.search_domains(query, limit, offset)
-
- if len(results.results) == 0:
- break
-
- for domain in results.results:
- self.hosts.add(domain.name)
-
- offset += max_limit
- fetch_count += len(results.results)
- if offset > max_offset or fetch_count == total:
- break
-
- except Exception as e:
- print(f'An exception has occurred: {e}')
-
- async def get_hostnames(self):
- return self.hosts
-
- async def process(self, proxy=False):
- self.proxy = proxy
- await self.do_search()
diff --git a/theHarvester/discovery/trello.py b/theHarvester/discovery/trello.py
deleted file mode 100644
index 5c4ea7ac..00000000
--- a/theHarvester/discovery/trello.py
+++ /dev/null
@@ -1,71 +0,0 @@
-from theHarvester.discovery.constants import *
-from theHarvester.parsers import myparser
-import random
-import asyncio
-
-
-class SearchTrello:
-
- def __init__(self, word):
- self.word = word.replace(' ', '%20')
- self.results = ""
- self.totalresults = ""
- self.server = 'www.google.com'
- self.quantity = '100'
- self.limit = 300
- self.trello_urls = []
- self.hostnames = []
- self.counter = 0
- self.proxy = False
-
- async def do_search(self):
- base_url = f'https://{self.server}/search?num=300&start=xx&hl=en&q=site%3Atrello.com%20{self.word}'
- urls = [base_url.replace("xx", str(num)) for num in range(0, self.limit, 20) if num <= self.limit]
- # limit is 20 as that is the most results google will show per num
- headers = {'User-Agent': googleUA}
- for url in urls:
- try:
- resp = await AsyncFetcher.fetch_all([url], headers=headers, proxy=self.proxy)
- self.results = resp[0]
- if await search(self.results):
- try:
- self.results = await google_workaround(base_url)
- if isinstance(self.results, bool):
- print('Google is blocking your ip and the workaround, returning')
- return
- except Exception as e:
- print(e)
- self.totalresults += self.results
- await asyncio.sleep(get_delay() - .5)
- except Exception as e:
- print(f'An exception has occurred in trello: {e}')
-
- async def get_emails(self):
- rawres = myparser.Parser(self.totalresults, self.word)
- return await rawres.emails()
-
- async def get_urls(self):
- try:
- rawres = myparser.Parser(self.totalresults, 'trello.com')
- self.trello_urls = set(await rawres.urls())
- self.totalresults = ''
- # reset what totalresults as before it was just google results now it is trello results
- headers = {'User-Agent': random.choice(['curl/7.37.0', 'Wget/1.19.4'])}
- # do not change the headers
- responses = await AsyncFetcher.fetch_all(self.trello_urls, headers=headers, proxy=self.proxy)
- for response in responses:
- self.totalresults += response
-
- rawres = myparser.Parser(self.totalresults, self.word)
- self.hostnames = await rawres.hostnames()
- except Exception as e:
- print(f'Error occurred: {e}')
-
- async def process(self, proxy=False):
- self.proxy = proxy
- await self.do_search()
- await self.get_urls()
- print(f'\tSearching {self.counter} results.')
-
- async def get_results(self) -> tuple:
- return await self.get_emails(), self.hostnames, self.trello_urls
diff --git a/theHarvester/discovery/twittersearch.py b/theHarvester/discovery/twittersearch.py
deleted file mode 100644
index 150805cc..00000000
--- a/theHarvester/discovery/twittersearch.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from theHarvester.discovery.constants import *
-from theHarvester.lib.core import *
-from theHarvester.parsers import myparser
-import re
-
-
-class SearchTwitter:
-
- def __init__(self, word, limit):
- self.word = word.replace(' ', '%20')
- self.results = ""
- self.totalresults = ""
- self.server = 'www.google.com'
- self.quantity = '100'
- self.limit = int(limit)
- self.counter = 0
- self.proxy = False
-
- async def do_search(self):
- base_url = f'https://{self.server}/search?num=100&start=xx&hl=en&meta=&q=site%3Atwitter.com%20intitle%3A%22on+Twitter%22%20{self.word}'
- headers = {'User-Agent': Core.get_user_agent()}
- try:
- urls = [base_url.replace("xx", str(num)) for num in range(0, self.limit, 10) if num <= self.limit]
- for url in urls:
- response = await AsyncFetcher.fetch_all([url], headers=headers, proxy=self.proxy)
- self.results = response[0]
- if await search(self.results):
- try:
- self.results = await google_workaround(url)
- if isinstance(self.results, bool):
- print('Google is blocking your ip and the workaround, returning')
- return
- except Exception:
- # google blocked, no useful result
- return
- self.totalresults += self.results
- except Exception as error:
- print(error)
-
- async def get_people(self, proxy=False):
- self.proxy = proxy
- rawres = myparser.Parser(self.totalresults, self.word)
- to_parse = await rawres.people_twitter()
- # fix invalid handles that look like @user other_output
- handles = set()
- for handle in to_parse:
- result = re.search(r'^@?(\w){1,15}', handle)
- if result:
- handles.add(result.group(0))
- return handles
-
- async def process(self, proxy=False):
- self.proxy = proxy
- await self.do_search()
diff --git a/theHarvester/discovery/virustotal.py b/theHarvester/discovery/virustotal.py
index 55158f6f..7e42a81e 100644
--- a/theHarvester/discovery/virustotal.py
+++ b/theHarvester/discovery/virustotal.py
@@ -1,39 +1,29 @@
+from theHarvester.discovery.constants import *
from theHarvester.lib.core import *
-from theHarvester.parsers import myparser
-import re
+from pprint import pprint
class SearchVirustotal:
def __init__(self, word):
self.word = word
- self.results = ""
- self.totalresults = ""
- self.quantity = '100'
- self.counter = 0
+ self.key = Core.virustotal_key()
+ if self.key is None:
+ raise MissingKey('virustotal')
+ self.totalhosts = set
self.proxy = False
async def do_search(self):
- base_url = f'https://www.virustotal.com/ui/domains/{self.word}/subdomains?relationships=resolutions&cursor=STMwCi4%3D&limit=40'
- headers = {'User-Agent': Core.get_user_agent()}
- responses = await AsyncFetcher.fetch_all([base_url], headers=headers, proxy=self.proxy)
- self.results = responses[0]
- self.totalresults += self.results
+ url = f'https://www.virustotal.com/api/v3/domains/{self.word}/subdomains?limit=40'
+ response = await AsyncFetcher.fetch_all([url], json=True, headers={'User-Agent': Core.get_user_agent(),
+ 'X-APIKEY': self.key},
+ proxy=self.proxy)
+ entry = [host for host in response]
+ pprint(entry.items())
- async def get_hostnames(self):
- rawres = myparser.Parser(self.results, self.word)
- new_lst = []
- for host in await rawres.hostnames():
- host = str(host)
- if host[0].isdigit():
- matches = re.match('.+([0-9])[^0-9]*$', host)
- # Get last digit of string and shift hostname to remove ip in string
- new_lst.append(host[matches.start(1) + 1:])
- else:
- new_lst.append(host)
- return new_lst
+ # async def get_hostnames(self) -> set:
+ # return self.total_results
async def process(self, proxy=False):
self.proxy = proxy
- print('\tSearching results.')
await self.do_search()
diff --git a/theHarvester/lib/core.py b/theHarvester/lib/core.py
index 289df348..d31fa7dc 100644
--- a/theHarvester/lib/core.py
+++ b/theHarvester/lib/core.py
@@ -1,6 +1,6 @@
# coding=utf-8
-
-from typing import Set, Union, Any, Tuple, List
+from __future__ import annotations
+from typing import Union, Any, Tuple, List
import yaml
import asyncio
import aiohttp
@@ -12,7 +12,7 @@ import certifi
class Core:
@staticmethod
def version() -> str:
- return '4.0.3'
+ return '4.2.0dev'
@staticmethod
def api_keys() -> dict:
@@ -76,14 +76,14 @@ class Core:
def shodan_key() -> str:
return Core.api_keys()['shodan']['key']
- @staticmethod
- def spyse_key() -> str:
- return Core.api_keys()['spyse']['key']
-
@staticmethod
def zoomeye_key() -> str:
return Core.api_keys()['zoomeye']['key']
+ @staticmethod
+ def virustotal_key() -> str:
+ return Core.api_keys()['virustotal']['key']
+
@staticmethod
def proxy_list() -> List:
try:
@@ -101,7 +101,7 @@ class Core:
@staticmethod
def banner() -> None:
- print('\n\033[93m*******************************************************************')
+ print('*******************************************************************')
print("* _ _ _ *")
print(r"* | |_| |__ ___ /\ /\__ _ _ ____ _____ ___| |_ ___ _ __ *")
print(r"* | __| _ \ / _ \ / /_/ / _` | '__\ \ / / _ \/ __| __/ _ \ '__| *")
@@ -114,11 +114,11 @@ class Core:
print('* Edge-Security Research *')
print('* cmartorella@edge-security.com *')
print('* *')
- print('******************************************************************* \n\n\033[0m')
+ print('*******************************************************************')
@staticmethod
- def get_supportedengines() -> Set[Union[str, Any]]:
- supportedengines = {'anubis',
+ def get_supportedengines() -> list[str | Any]:
+ supportedengines = ['anubis',
'baidu',
'binaryedge',
'bing',
@@ -131,13 +131,9 @@ class Core:
'duckduckgo',
'fullhunt',
'github-code',
- 'google',
'hackertarget',
'hunter',
'intelx',
- 'linkedin',
- 'linkedin_links',
- 'n45ht',
'omnisint',
'otx',
'pentesttools',
@@ -147,86 +143,89 @@ class Core:
'rocketreach',
'securityTrails',
'sublist3r',
- 'spyse',
'threatcrowd',
'threatminer',
- 'trello',
- 'twitter',
'urlscan',
'virustotal',
'yahoo',
'zoomeye'
- }
+ ]
return supportedengines
@staticmethod
def get_user_agent() -> str:
# User-Agents from https://techblog.willshouse.com/2012/01/03/most-common-user-agents/
user_agents = [
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
- "Mozilla/5.0 (X11; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0",
- "Mozilla/5.0 (X11; Linux x86_64; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0",
- "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 OPR/80.0.4170.63",
- "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.44",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.40",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30",
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36",
- "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36",
- "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0",
- "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 OPR/80.0.4170.63 (Edition Yx 05)",
- "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0",
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 YaBrowser/21.9.2.169 Yowser/2.5 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0",
- "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36",
- "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36",
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 OPR/80.0.4170.91",
- "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:93.0) Gecko/20100101 Firefox/93.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:91.0) Gecko/20100101 Firefox/91.0",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15",
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15",
- "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36"]
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.62 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.47',
+ 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 Edg/101.0.1210.39',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Safari/605.1.15',
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36',
+ 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32',
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:101.0) Gecko/20100101 Firefox/101.0',
+ 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 OPR/86.0.4363.59',
+ 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.141 YaBrowser/22.3.3.852 Yowser/2.5 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 OPR/85.0.4341.75',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:99.0) Gecko/20100101 Firefox/99.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
+ 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 OPR/85.0.4341.71',
+ 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15',
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 OPR/86.0.4363.64',
+ 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) Gecko/20100101 Firefox/101.0',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.50',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36'
+ ]
return random.choice(user_agents)
@@ -238,7 +237,7 @@ class AsyncFetcher:
if len(headers) == 0:
headers = {'User-Agent': Core.get_user_agent()}
timeout = aiohttp.ClientTimeout(total=720)
- # by default timeout is 5 minutes, changed to 12 minutes
+ # By default, timeout is 5 minutes, changed to 12 minutes
# results are well worth the wait
try:
if proxy:
@@ -322,8 +321,8 @@ class AsyncFetcher:
return url, ''
@classmethod
- async def fetch_all(cls, urls, headers='', params='', json=False, takeover=False, proxy=False) -> list:
- # By default timeout is 5 minutes, 60 seconds should suffice
+ async def fetch_all(cls, urls, headers='', params='', json=False, takeover=False, proxy=False) -> tuple:
+ # By default, timeout is 5 minutes; 60 seconds should suffice
timeout = aiohttp.ClientTimeout(total=60)
if len(headers) == 0:
headers = {'User-Agent': Core.get_user_agent()}
diff --git a/theHarvester/parsers/myparser.py b/theHarvester/parsers/myparser.py
index f2c76a9e..7a8eb4ac 100644
--- a/theHarvester/parsers/myparser.py
+++ b/theHarvester/parsers/myparser.py
@@ -9,8 +9,8 @@ class Parser:
self.temp = []
async def genericClean(self):
- self.results = self.results.replace('', '').replace('', '').replace('', '').replace('', '')\
- .replace('%3a', '').replace('', '').replace('', '')\
+ self.results = self.results.replace('', '').replace('', '').replace('', '').replace('', '') \
+ .replace('%3a', '').replace('', '').replace('', '') \
.replace('', '').replace('', '')
for search in ('<', '>', ':', '=', ';', '&', '%3A', '%3D', '%3C', '%2f', '/', '\\'):
@@ -55,22 +55,6 @@ class Parser:
hostnames.extend(await self.unique())
return list(set(hostnames))
- async def people_googleplus(self):
- self.results = re.sub('', '', self.results)
- self.results = re.sub('', '', self.results)
- reg_people = re.compile(r'>[a-zA-Z0-9._ ]* - Google\+')
- self.temp = reg_people.findall(self.results)
- resul = []
- for iteration in self.temp:
- delete = iteration.replace(' | LinkedIn', '')
- delete = delete.replace(' profiles ', '')
- delete = delete.replace('LinkedIn', '')
- delete = delete.replace('"', '')
- delete = delete.replace('>', '')
- if delete != " ":
- resul.append(delete)
- return resul
-
async def hostnames_all(self):
reg_hosts = re.compile('(.*?)')
temp = reg_hosts.findall(self.results)
@@ -83,60 +67,8 @@ class Parser:
hostnames = await self.unique()
return hostnames
- async def links_linkedin(self):
- reg_links = re.compile(r"url=https:\/\/www\.linkedin.com(.*?)&")
- self.temp = reg_links.findall(self.results)
- resul = []
- for regex in self.temp:
- final_url = regex.replace("url=", "")
- resul.append("https://www.linkedin.com" + final_url)
- return resul
-
- async def people_linkedin(self):
- reg_people = re.compile(r'">[a-zA-Z0-9._ -]* -|\| LinkedIn')
- self.temp = reg_people.findall(self.results)
- resul = []
- for iteration in (self.temp):
- delete = iteration.replace(' | LinkedIn', '')
- delete = delete.replace(' - LinkedIn', '')
- delete = delete.replace(' profiles ', '')
- delete = delete.replace('LinkedIn', '')
- delete = delete.replace('"', '')
- delete = delete.replace('>', '')
- delete = delete.strip("-")
- if delete != " ":
- resul.append(delete)
- return resul
-
- async def people_twitter(self):
- reg_people = re.compile(r'(@[a-zA-Z0-9._ -]*)')
- self.temp = reg_people.findall(self.results)
- users = await self.unique()
- resul = []
- for iteration in users:
- delete = iteration.replace(' | LinkedIn', '')
- delete = delete.replace(' profiles ', '')
- delete = delete.replace('LinkedIn', '')
- delete = delete.replace('"', '')
- delete = delete.replace('>', '')
- if delete != " ":
- resul.append(delete)
- return resul
-
- async def profiles(self):
- reg_people = re.compile(r'">[a-zA-Z0-9._ -]* - Google Profile')
- self.temp = reg_people.findall(self.results)
- resul = []
- for iteration in self.temp:
- delete = iteration.replace(' Google Profile', '')
- delete = delete.replace('-', '')
- delete = delete.replace('">', '')
- if delete != " ":
- resul.append(delete)
- return resul
-
async def set(self):
- reg_sets = re.compile(r'>[a-zA-Z0-9]*')
+ reg_sets = re.compile(r'>[a-zA-Z\d]*')
self.temp = reg_sets.findall(self.results)
sets = []
for iteration in self.temp:
@@ -146,7 +78,7 @@ class Parser:
return sets
async def urls(self):
- found = re.finditer(r'(http|https)://(www\.)?trello.com/([a-zA-Z0-9\-_\.]+/?)*', self.results)
+ found = re.finditer(r'(http|https)://(www\.)?trello.com/([a-zA-Z\d\-_\.]+/?)*', self.results)
urls = {match.group().strip() for match in found}
return urls