Shodan

Shodanz

This section comes from Shodan Pentesting Guide on TurgenSec blog written by noraj.

Installation

In a virtual ruby environment like rbenv:
1
$ gem install shodanz
Copied!
Then the API key will always be initialized like that in our code:
1
require 'shodanz'
2
3
api = Shodanz.client.new(key: 'YOUR_API_KEY')
Copied!
For production projects you may prefer read the API key via the environment variable SHODAN_API_KEY.

Examples

1
# Search Shodan
2
results = api.host_search('apache')
3
4
# Show results
5
puts "Results found: #{results['total']}"
6
results['matches'].each do |result|
7
puts "IP: #{result['ip_str']}"
8
puts result['data'] + "\n"
9
end
Copied!
Example of output:
1
IP: 154.218.139.58
2
HTTP/1.1 200 OK
3
Date: Tue, 28 Jan 2020 22:13:53 GMT
4
Server: Apache
5
Upgrade: h2
6
Connection: Upgrade, close
7
Last-Modified: Wed, 26 Apr 2017 08:03:47 GMT
8
ETag: "52e-54e0d47a39ec0"
9
Accept-Ranges: bytes
10
Content-Length: 1326
11
Vary: Accept-Encoding
12
Content-Type: text/html
13
14
15
IP: 132.148.235.102
16
HTTP/1.1 200 OK
17
Date: Tue, 28 Jan 2020 22:13:53 GMT
18
Server: Apache
19
Upgrade: h2,h2c
20
Connection: Upgrade
21
Last-Modified: Fri, 10 May 2019 09:10:49 GMT
22
ETag: "a4edb-7ab-58884f152c219"
23
Accept-Ranges: bytes
24
Content-Length: 1963
25
Vary: Accept-Encoding,User-Agent
26
Content-Type: text/html
27
28
29
IP: 112.126.140.94
30
HTTP/1.1 404 Not Found
31
Date: Tue, 28 Jan 2020 22:13:34 GMT
32
Server: Apache
33
X-Powered-By: PHP/5.2.17
34
X-UA-Compatible: IE=EmulateIE7
35
Transfer-Encoding: chunked
36
Content-Type: text/html
Copied!

Available ports of a host

1
# Lookup the host
2
host = api.host('1.1.1.1')
3
4
# Print general info
5
puts "
6
IP: #{host['ip_str']}
7
Organization: #{host['org'] || 'n/a'}
8
Operating System: #{host['os'] || 'n/a'}
9
"
10
11
# Print all banners
12
host['data'].each do |item|
13
puts "
14
Port: #{item['port'] || 'n/a'}
15
Banner: #{item['data'] || 'n/a'}
16
17
"
18
end
Copied!
Example of output:
1
IP: 1.1.1.1
2
Organization: Mountain View Communications
3
Operating System: n/a
4
5
Port: 443
6
Banner: HTTP/1.1 403 Forbidden
7
Server: cloudflare
8
Date: Tue, 28 Jan 2020 18:34:35 GMT
9
Content-Type: text/html
10
Content-Length: 553
11
Connection: keep-alive
12
CF-RAY: 55c50fb4e8149d5a-AMS
13
14
15
16
17
Port: 80
18
Banner: HTTP/1.1 409 Conflict
19
Date: Tue, 28 Jan 2020 17:26:54 GMT
20
Content-Type: text/html; charset=UTF-8
21
Transfer-Encoding: chunked
22
Connection: close
23
Set-Cookie: __cfduid=d189a930262f96d94a707a90d853a56bd1580232414; expires=Thu, 27-Feb-20 17:26:54 GMT; path=/; domain=.www.1yhaoduo.com; HttpOnly; SameSite=Lax
24
Cache-Control: max-age=6
25
Expires: Tue, 28 Jan 2020 17:27:00 GMT
26
X-Frame-Options: SAMEORIGIN
27
Vary: Accept-Encoding
28
Server: cloudflare
29
CF-RAY: 55c4ac8fba63801a-SAN
30
31
32
33
34
Port: 53
35
Banner:
36
Recursion: enabled
37
Resolver ID: AMS
Copied!

Displaying stats

1
# The list of properties we want summary information on
2
FACETS = {
3
'org': 3,
4
'domain': 5,
5
'port': 5,
6
'asn': 5,
7
'country': 10,
8
}
9
10
FACET_TITLES = {
11
'org': 'Top 3 Organizations',
12
'domain': 'Top 5 Domains',
13
'port': 'Top 5 Ports',
14
'asn': 'Top 5 Autonomous Systems',
15
'country': 'Top 10 Countries',
16
}
17
18
# Query
19
query = 'apache 2.4'
20
21
# Count results
22
result = api.host_count(query, facets: FACETS)
23
puts 'Shodan Summary Information'
24
puts "Query: #{query}"
25
puts "Total Results: #{result['total']}\n"
26
27
# Print the summary info from the facets
28
result['facets'].each do |facet, _v|
29
puts FACET_TITLES[facet]
30
31
result['facets'][facet].each do |term|
32
puts "#{term['value']}: #{term['count']}"
33
end
34
35
# Print an empty line between summary info
36
puts ''
37
end
Copied!
Example of output:
1
Shodan Summary Information
2
Query: apache 2.4
3
Total Results: 63939
4
5
Liquid Web, L.L.C: 23126
6
Amazon.com: 7843
7
Hetzner Online GmbH: 1798
8
9
10
amazonaws.com: 10398
11
telecom.net.ar: 1609
12
your-server.de: 1232
13
t-ipconnect.de: 629
14
vultr.com: 450
15
16
17
80: 21131
18
443: 19772
19
8080: 3023
20
10000: 1672
21
8081: 1372
22
23
24
as53824: 13810
25
as32244: 9316
26
as16509: 6138
27
as24940: 1740
28
as7303: 1410
29
30
31
US: 30877
32
DE: 5781
33
CN: 4432
34
BR: 2949
35
AR: 1757
36
JP: 1472
37
GB: 1168
38
IN: 1030
39
FR: 720
40
CA: 613
Copied!

Async support with the stream API

1
require 'async'
2
require 'shodanz'
3
4
api = Shodanz.client.new(key: 'YOUR_API_KEY')
5
6
# Asynchronously stream banner info from shodan and check any
7
# IP addresses against the experimental honeypot scoring service.
8
api.streaming_api.banners do |banner|
9
if ip = banner['ip_str']
10
Async do
11
score = api.rest_api.honeypot_score(ip).wait
12
puts "#{ip} has a #{score * 100}% chance of being a honeypot"
13
rescue Shodanz::Errors::RateLimited
14
sleep rand
15
retry
16
rescue # any other errors
17
next
18
end
19
end
20
end
Copied!
Warning: Freelancer API plan or better required for using the stream API, developer or free plan won't work.
Note: this async example comes from the shodanz documentation.

Useful methods

1
# Returns all the protocols that can be used when launching an Internet scan
2
api.protocols
3
4
# Returns a list of port numbers that the Shodan crawlers are looking for
5
api.ports
6
7
# Returns information about the Shodan account linked to this API key
8
api.profile
9
10
# Look up the IP address for the provided list of hostnames
11
api.resolve('archlinux.org', 'blackarch.org')
12
13
# Look up the hostnames that have been defined for the given list of IP addresses
14
api.reverse_lookup('138.201.81.199', '176.31.253.211')
15
16
# Get your current IP address as seen from the Internet
17
api.my_ip
18
19
# Calculates a honeypot probability score ranging from 0 (not a honeypot) to 1.0 (is a honeypot)
20
api.honeypot_score('1.1.1.1')
21
22
# API Plan Information
23
api.info
Copied!

Exploits API

1
puts client.exploit_count(port: 22, page: 1)
2
puts client.exploit_search('rce couchdb', type: 'remote', platform: 'linux', author: 'Metasploit')
Copied!
You can find more examples here or read the shodanz API documentation.
Last modified 5mo ago