├── images
├── README.md
├── banner.png
└── demo.jpeg
├── README.md
├── sholister_org.py
└── sholister_hostname.py
/images/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eslam3kl/ShoLister/HEAD/images/banner.png
--------------------------------------------------------------------------------
/images/demo.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eslam3kl/ShoLister/HEAD/images/demo.jpeg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## ShoLister
2 | ShoLister is a tool that collects all available subdomains for specific hostname or organization from Shodan. The tool is designed to be used from Penetration Tester and Bug Bounty Hunters.
3 |
4 |
5 |
6 |
7 |
8 | ### Requirments/Install
9 | 1. Shodan paid account.
10 | 2. Python3
11 |
12 | ```
13 | pip install shodan
14 | pip install termcolor
15 | shodan init YOUR_API_KEY
16 | ```
17 |
18 | ### Usage
19 | -> You have 2 python scripts, the first one will search for your scope subdomains using 2 filters **hostname** and **Ssl.cert.subject.CN** The second script will search using filter **org**
20 |
21 | **sholister_hostname.py**
22 | ```
23 | > scope_domains.txt example:
24 | yahoo.com
25 | uber.com
26 | twitter.com
27 |
28 | > Run:
29 | python3 sholister_hostname.py scope_domains.txt
30 | ```
31 |
32 | **sholister_org.py**
33 | ```
34 | > scope_organizations.txt example:
35 | Google LLC
36 | Uber Technologies LLC
37 | Twitter
38 |
39 | > Run:
40 | python3 sholister_org.py scope_organizations.txt
41 | ```
42 | 
43 |
44 |
45 | ### Differences between ShoLister and Shodan CLI
46 | 1. ShoLister based on Shodan Library so they're using the same gateway to get the results.
47 | 2. Filter the results to avoid ISP false positive domains.
48 | 3. You can pass a file with multiple hosts or organizations names to make it more easier to get the results.
49 | 4. ShoLister provide the results as a separate file for each hostname or organization.
50 |
51 | ----------------------------------
52 | ### Stay in touch <3
53 | [LinkedIn](https://www.linkedin.com/in/eslam3kl/) | [Blog](https://eslam3kl.medium.com/) | [Twitter](https://twitter.com/eslam3kll)
54 |
--------------------------------------------------------------------------------
/sholister_org.py:
--------------------------------------------------------------------------------
1 | from shodan import Shodan
2 | from shodan.cli.helpers import get_api_key
3 | from termcolor import colored
4 | import sys
5 |
6 | header1 = r'''
7 | _ _ _ _ _ _ _ _ _
8 | / \ / \ / \ / \ / \ / \ / \ / \ / \
9 | ( s | h | o | l | i | s | t | e | r )
10 | \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ v0.1
11 | '''
12 | header2 = r'''
13 | Hostname search using [Org] Filter.
14 | Coded By: Eslam Akl (@eslam3kll)
15 | '''
16 | print(colored(header1, 'red', attrs=['bold']))
17 | print(colored(header2, 'white', attrs=['bold']))
18 | main_domains_file = sys.argv[1]
19 | api = Shodan(get_api_key())
20 | limit = 1000
21 | counter = 0
22 | results = []
23 | with open(main_domains_file, 'r') as domains:
24 | try:
25 | for line in domains:
26 | line = line.strip()
27 | filename = line + '_shodan.txt'
28 | f = open(filename, 'a+')
29 | print(colored("[+] Searching for: ", 'green') + line)
30 |
31 | # org search
32 | org_query = 'org:"' + line + '" 200'
33 | for banner in api.search_cursor(org_query):
34 | for hostname in banner['hostnames']:
35 | results.append(hostname)
36 | counter += 1
37 | if counter >= limit:
38 | break
39 |
40 | results_length = len(results)
41 | print(colored("-> Found " + str(results_length) + " unique result for Organization ["+ line + "] responds with status code [200 OK]", 'cyan'))
42 | print(colored("-> Output file name: " + filename, 'cyan') + "\n")
43 | # get results to output file
44 | for line in results:
45 | f.write(line + "\n")
46 | f.close()
47 | results = []
48 |
49 |
50 | except KeyboardInterrupt:
51 | print(colored("\nKeyboardInterrupt detected! GoodBye", 'red'))
52 | pass
53 |
--------------------------------------------------------------------------------
/sholister_hostname.py:
--------------------------------------------------------------------------------
1 | from shodan import Shodan
2 | from shodan.cli.helpers import get_api_key
3 | from termcolor import colored
4 | import sys
5 |
6 | header1 = r'''
7 | _ _ _ _ _ _ _ _ _
8 | / \ / \ / \ / \ / \ / \ / \ / \ / \
9 | ( s | h | o | l | i | s | t | e | r )
10 | \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ v0.1
11 | '''
12 | header2 = r'''
13 | Hostname search using [hostname] and [Ssl.cert.subject.CN] Filters.
14 | Coded By: Eslam Akl (@eslam3kll)
15 | '''
16 | print(colored(header1, 'red', attrs=['bold']))
17 | print(colored(header2, 'white', attrs=['bold']))
18 | main_domains_file = sys.argv[1]
19 | api = Shodan(get_api_key())
20 | limit = 1000
21 | counter = 0
22 | results = []
23 | with open(main_domains_file, 'r') as domains:
24 | try:
25 | for line in domains:
26 | line = line.strip()
27 | filename = line + '_shodan.txt'
28 | f = open(filename, 'a+')
29 | print(colored("[+] Searching for: ", 'green') + line)
30 |
31 | # ssl search
32 | ssl_query = 'Ssl.cert.subject.CN:"' + line + '" 200'
33 | for banner in api.search_cursor(ssl_query):
34 | for hostname in banner['hostnames']:
35 | #print(hostname)
36 | if line in hostname:
37 | results.append(hostname)
38 | counter += 1
39 | if counter >= limit:
40 | break
41 | # hostname search
42 | hostname_query = 'hostname:"' + line + '" 200'
43 | for banner in api.search_cursor(hostname_query):
44 | for hostname in banner['hostnames']:
45 | #print(hostname)
46 | if line in hostname:
47 | if hostname not in results:
48 | results.append(hostname)
49 | counter += 1
50 | if counter >= limit:
51 | break
52 | results_length = len(results)
53 | print(colored("-> Found " + str(results_length) + " unique result for subdomain ["+ line + "] responds with status code [200 OK]", 'cyan'))
54 | print(colored("-> Output file name: " + filename, 'cyan') + "\n")
55 | # get results to output file
56 | for line in results:
57 | f.write(line + "\n")
58 | f.close()
59 | results = []
60 |
61 | except KeyboardInterrupt:
62 | print(colored("\nKeyboardInterrupt detected! GoodBye", 'red'))
63 | pass
64 |
65 |
66 |
--------------------------------------------------------------------------------