Scripting With Shodan API

Scripting With Shodan API

Following the article I wrote about Shodan, I promised to come back with a more advanced introduction to using their API and I will be doing a Python implementation specifically.

They have a bunch of other languages and clients listed here if you are not into Python.

If you missed my introductory article on Shodan, read it here and hopefully, you already created an article because you will need an API key which is free for the basic account and will help us access

image.png

Any device connected to the internet must reveal some sort of information regarding itself. This can be relatively limited, as clever system configurations can block most undesired requests. On some devices, one might be able to scan ports to reveal things such as the services running on a web server or the name of a webcam connected to a wireless network.

So we shall see two different use-cases, one will be about basic searching using the API and the other will be about creating an advanced search using facets. Nginx and Apache are popular web servers used to deliver web pages to a user's browser.

shodan

So let's create a python file and add the following code which I am going to explain later;

import shodan
SHODAN_API_KEY = "your API key"

api = shodan.Shodan(SHODAN_API_KEY)

try:
    # Search Shodan
    results = api.search('apache')
    total_results = results['total']
#     print(results)

    # Show the results
    print('Total results found: {}'.format(total_results))

    matches = results['matches']
    for result in matches:
        print('IP: {}'.format(result['ip_str']))
        print(result['data'])
        print('')
except shodan.APIError as e:
    print('Error: {}'.format(e))

Grab your API key from the account dashboard and replace the string "Your API key"

We used api.search() method to search for all apache webservers which returns a list of python dicts. We loop through and query for all the data we need. You can uncomment to see the different results.

The matches variable returns all matched results dictionary and we then print out what we want. We wrapped the code under a try and except block for error handling.

If we ran the script;

image.png

The powerful ability of the Shodan API is able to get a piece of summary information on a variety of properties. For example, if you wanted to learn which countries have the most Apache servers then you would use facets.

If you wanted to figure out which version of nginx is most popular, you would use facets. Or if you wanted to see what the uptime distribution is for Microsoft-IIS servers then you would use facets.

Now create a new file and add;

import shodan
import sys

# Configuration
API_KEY = 'your API key'

# The list of properties we want summary information on
FACETS = [
    'org',
    'domain',
    'port',
    'asn',

    # We only care about the top 3 countries, this is how we let Shodan know to return 3 instead of the
    # default 5 for a facet. If you want to see more than 5, you could do ('country', 1000) for example
    # to see the top 1,000 countries for a search query.
    ('country', 3),
]

FACET_TITLES = {
    'org': 'Top 5 Organizations',
    'domain': 'Top 5 Domains',
    'port': 'Top 5 Ports',
    'asn': 'Top 5 Autonomous Systems',
    'country': 'Top 3 Countries',
}

# Input validation
if len(sys.argv) == 1:
    print('Usage: %s <search query>' % sys.argv[0])
    sys.exit(1)

try:
    # Setup the api
    api = shodan.Shodan(API_KEY)

    # Generate a query string out of the command-line arguments
    query = ' '.join(sys.argv[1:])

    # Use the count() method because it doesn't return results and doesn't require a paid API plan
    # And it also runs faster than doing a search().
    result = api.count(query, facets=FACETS)

    print('Shodan Summary Information')
    print('Query: %s' % query)
    print('Total Results: %s\n' % result['total'])

    # Print the summary info from the facets
    for facet in result['facets']:
        print(FACET_TITLES[facet])

        for term in result['facets'][facet]:
            print('%s: %s' % (term['value'], term['count']))

        # Print an empty line between summary info
        print('')

except Exception as e:
    print('Error: %s' % e)
    sys.exit(1)

The above script shows how to use the shodan.Shodan.count() method to search Shodan without returning any results as well as asking the API to return faceted information on the organization, domain, port, ASN and country.

Please refer to my comments for more elaboration.

If we ran the script by providing a parameter like this; py facets.py nginx We would get something related to;

image.png

All the code in this article is available here;

🔸 Conclusion

Once again, hope you learned something today from my little closet.

Please consider subscribing or following me for related content, especially about Tech, Python & General Programming.

You can show extra love by buying me a coffee to support this free content and I am also open to partnerships, technical writing roles, collaborations and Python-related training or roles.

Buy Ronnie A Coffee 📢 You can also follow me on Twitter : ♥ ♥ Waiting for you! 🙂