Ever needed to quickly check the exposure of a specific type of network device, or verify if a known vulnerability is present across your external-facing infrastructure? Manually probing IPs can be a tedious and time-consuming process. What if you could query the entire internet for devices, services, and even known vulnerabilities, all from a simple API call?
This article will walk you through using Python to programmatically query ScanSearch, an internet-wide search engine for network devices, services, and vulnerabilities. We'll focus on practical examples that demonstrate how to find specific device types, filter results, and extract useful information.
The Problem: Manual Network Reconnaissance is Slow
Imagine you're a security analyst, and a new vulnerability (CVE-2023-XXXX) has just been announced, affecting a specific version of a network-attached storage (NAS) device. Your immediate thought is: Are any of our external-facing devices vulnerable? And what about other organizations I'm responsible for monitoring?
Traditionally, you'd start with IP ranges, port scans, and banner grabbing – a process that's not only slow but also might miss devices outside your known ranges. This is where a tool like ScanSearch comes in handy, providing a fast way to query pre-indexed internet data.
Getting Started with ScanSearch
ScanSearch (https://scansearch.net) offers an API that allows you to perform these queries programmatically. While the specifics of API key acquisition aren't covered here, assume you have an API key ready for the following examples.
We'll use Python's requests library to interact with the ScanSearch API. First, let's set up our basic request structure.
import requests
import json
API_KEY = 'YOUR_SCANSEARCH_API_KEY' # Replace with your actual API key
BASE_URL = 'https://api.scansearch.net/v1/search'
def query_scansearch(query_string, page=1, limit=10):
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
params = {
'q': query_string,
'page': page,
'limit': limit
}
try:
response = requests.get(BASE_URL, headers=headers, params=params)
response.raise_for_status() # Raise an exception for HTTP errors
return response.json()
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
print(f"Response body: {response.text}")
except Exception as err:
print(f"An error occurred: {err}")
return None
This query_scansearch function takes a query_string, page, and limit and handles the API call, including basic error checking.
Example 1: Finding Specific Device Types
Let's say we want to find all publicly exposed instances of nginx web servers. The query_string for ScanSearch is quite powerful and supports various filters. A simple query for nginx will return services identified as such.
print("\n--- Searching for Nginx Servers ---")
nginx_results = query_scansearch('nginx')
if nginx_results and 'results' in nginx_results:
print(f"Found {len(nginx_results['results'])} Nginx instances (first {len(nginx_results['results'])} results shown):")
for i, result in enumerate(nginx_results['results'][:5]): # Print first 5 for brevity
print(f" {i+1}. IP: {result.get('ip')}, Port: {result.get('port')}, Banners: {result.get('banners', [])[0] if result.get('banners') else 'N/A'}")
# You can inspect the full result object for more details
# print(json.dumps(result, indent=2))
else:
print("No Nginx results found or an error occurred.")
This code snippet sends a query for nginx and then iterates through the results, printing out the IP, port, and the first banner string found. ScanSearch's data includes a lot more, so feel free to inspect the result object more deeply.
Example 2: Filtering by Port and Service
What if you're interested in SSH services running on non-standard ports, say port 2222? ScanSearch allows combining search terms.
print("\n--- Searching for SSH on Port 2222 ---")
ssh_port_results = query_scansearch('service:ssh port:2222')
if ssh_port_results and 'results' in ssh_port_results:
print(f"Found {len(ssh_port_results['results'])} SSH services on port 2222:")
for i, result in enumerate(ssh_port_results['results'][:5]):
print(f" {i+1}. IP: {result.get('ip')}, Port: {result.get('port')}, Country: {result.get('location', {}).get('country_name')}")
else:
print("No SSH on port 2222 results found or an error occurred.")
Here, service:ssh specifically targets services identified as SSH, and port:2222 narrows it down to that specific port. The results also contain geographical information under location.
Example 3: Searching for Vulnerabilities (CVEs)
ScanSearch also indexes known vulnerabilities. This is incredibly powerful for security auditing. Let's look for devices exposed to a hypothetical (or real, if you substitute a current one) CVE.
print("\n--- Searching for Devices with CVE-2021-44228 (Log4Shell) ---")
# Note: ScanSearch indexes vulnerabilities; results will show devices associated with them.
log4shell_results = query_scansearch('cve:CVE-2021-44228')
if log4shell_results and 'results' in log4shell_results:
print(f"Found {len(log4shell_results['results'])} devices potentially affected by CVE-2021-44228:")
for i, result in enumerate(log4shell_results['results'][:5]):
print(f" {i+1}. IP: {result.get('ip')}, Port: {result.get('port')}, Service: {result.get('service')}")
# For vulnerability queries, you might want to inspect the 'vulnerabilities' key in the full result.
# print(json.dumps(result.get('vulnerabilities', []), indent=2))
else:
print("No CVE-2021-44228 results found or an error occurred.")
This example demonstrates how to query for a specific CVE ID. ScanSearch's data includes an association between identified services/devices and known vulnerabilities, which can be invaluable for threat hunting and patch validation.
Considerations and Best Practices
- API Key Security: Never hardcode your API key directly into public repositories. Use environment variables or a secure configuration management system.
- Rate Limiting: Be mindful of API rate limits. Implement delays or back-off strategies if you're making a large number of requests.
- Result Paging: The
pageandlimitparameters are crucial for fetching all results when your query returns more than the default limit. Implement a loop to fetch subsequent pages. - Data Structure: The exact structure of the results can vary slightly depending on the query. Always inspect the JSON response to understand the available fields.
- Query Syntax: Familiarize yourself with ScanSearch's query syntax for more precise searches. This often includes field-specific searches (e.g.,
product:apache,os:linux).
Conclusion
Programmatically querying an internet-wide search engine like ScanSearch significantly speeds up network reconnaissance, security auditing, and threat intelligence gathering. By leveraging its API with a few lines of Python, developers and security professionals can quickly gain insights into internet-facing infrastructure, identify specific device types, services, and even potential vulnerabilities without resorting to slow, active scanning.
Explore the ScanSearch website (https://scansearch.net) to learn more about its capabilities and detailed query options.
Top comments (0)