Looking up IP Information

Do you want to see where an IP is located? Which ports/ services it has available? The Shodan API gives you the ability to quickly lookup information for an IP.

Requirements

The shodan Python package is required for this tutorial and a valid API key, which is available for free with every Shodan account. You can install it using easy_install or pip:

pip install --user shodan

You can get your Shodan API key from your account page at:

https://account.shodan.io

Looking up IPs via the main Shodan REST API requires at least a Shodan Membership (one-time payment of $49 for lifetime account upgrade). For free IP lookups check out the InternetDB API.

Getting Started

To lookup information about an IP we will use the Shodan.host() method. Getting started with the basics is straight-forward:

import shodan
api = shodan.Shodan('YOUR API KEY')

info = api.host('8.8.8.8')

The above code requests information about Google's DNS resolver 8.8.8.8 and stores it in the info variable. Here is a closer look at the data that the info object now holds:

{
    "data": [
        {
            "asn": "AS15169", 
            "hash": -553166942, 
            "ip": 134744072, 
            "isp": "Google", 
            "transport": "udp", 
            "data": "\nRecursion: enabled", 
            "port": 53, 
            "hostnames": [
                "google-public-dns-a.google.com"
            ], 
            "location": {
                "city": null, 
                "region_code": null, 
                "area_code": null, 
                "longitude": -97.822, 
                "country_code3": "USA", 
                "latitude": 37.751000000000005, 
                "postal_code": null, 
                "dma_code": null, 
                "country_code": "US", 
                "country_name": "United States"
            }, 
            "timestamp": "2018-03-16T03:06:34.553526", 
            "domains": [
                "google.com"
            ], 
            "org": "Google", 
            "os": null, 
            "_shodan": {
                "crawler": "6ff540e4d43ec69d8de2a7b60e1de2d9ddb406dc", 
                "options": {}, 
                "module": "dns-udp", 
                "id": null
            }, 
            "opts": {}, 
            "ip_str": "8.8.8.8"
        }
    ], 
    "city": null, 
    "region_code": null, 
    "tags": [], 
    "ip": 134744072, 
    "isp": "Google", 
    "area_code": null, 
    "dma_code": null, 
    "last_update": "2018-03-16T03:06:34.553526", 
    "country_code3": "USA", 
    "latitude": 37.751000000000005, 
    "hostnames": [
        "google-public-dns-a.google.com"
    ], 
    "postal_code": null, 
    "longitude": -97.822, 
    "country_code": "US", 
    "org": "Google", 
    "country_name": "United States", 
    "ip_str": "8.8.8.8", 
    "os": null, 
    "asn": "AS15169", 
    "ports": [
        53
    ]
}

The result from api.host() contains information about the services it runs, where it's located, the hosting provider and more. There are a few top-level properties of note:

  • data: a list of banners that provide details about the services that had an open port
  • ports: a list of open ports on the IP
  • tags: Shodan does additional validation for some services/ devices and has special tags to make identifying certain types of devices easier (for example, "ics" tag to identify industrial control systems)

Historic Data

There are a few common reasons to look at a history of an IP:

  • When was a service first exposed?
  • When was the system patched?
  • How long has the device been online?

We can get a full history of an IP address by providing an optional history=True parameter:

import shodan
api = shodan.Shodan('YOUR API KEY')

info = api.host('8.8.8.8', history=True)

The resulting info object will have the same structure as before but the top-level data property now contains a list of all the banners that were ever seen for that IP.

Bulk Lookups

The Corporate API plan gives you the ability to lookup 100 IPs per request. If you're building a data processing pipeline that wants to do a lot of IP enrichment then doing bulk IP lookups is the way to go. And using them is nearly the same as doing individual IP lookups:

import shodan
api = shodan.Shodan('YOUR CORPORATE API KEY')

hosts = api.host([
    '8.8.8.8',
    '8.8.4.4',
])

for info in hosts:
    # Each record in the "hosts" list is what an individual IP lookup returns
    print(info['ip_str'])

# The above is equivalent to doing
info = api.host('8.8.8.8')
# ...
info = api.host('8.8.4.4')

Instead of giving the Shodan.host() method an IP address we can also give it a list of IPs. The result of a bulk IP lookup is a list of objects where each object contains the same information you'd see when doing an individual IP lookup.