shodan 0.6.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  Visit the official Shodan API documentation at:
2
2
 
3
- [http://docs.shodanhq.com](http://docs.shodanhq.com)
3
+ [https://developer.shodan.io](https://developer.shodan.io)
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,19 +14,32 @@ Before you can use the API, you need to have an API key.
14
14
 
15
15
  [Get your API key here](http://www.shodanhq.com/api_doc)
16
16
 
17
- Setup the SHODAN WebAPI:
17
+ Setup the Shodan wrapper object:
18
18
 
19
19
  require 'shodan'
20
20
 
21
- api = Shodan::WebAPI.new(MY_API_KEY)
21
+ api = Shodan::Shodan.new(MY_API_KEY)
22
22
 
23
23
  Print a list of cisco-ios devices:
24
24
 
25
25
  result = api.search("cisco-ios")
26
26
  result['matches'].each{ |host|
27
- puts host['ip']
27
+ puts host['ip_str']
28
28
  }
29
29
 
30
+ Print the 2nd page of results for the cisco-ios query:
31
+
32
+ result = api.search("cisco-ios", :page => 2)
33
+ result['matches'].each{ |host|
34
+ puts host['ip_str']
35
+ }
36
+
37
+ Find out how many results there are for "apache" and also return the top 5 organizations for the results:
38
+
39
+ result = api.count("apache", :facets => 'org:5')
40
+ puts "Total number of results: #{result['total']}"
41
+ puts result['facets']
42
+
30
43
  Get all the information SHODAN has on the IP 217.140.75.46:
31
44
 
32
45
  host = api.host('217.140.75.46')
@@ -41,7 +54,3 @@ To properly handle potential errors, you should wrap all requests in a try/excep
41
54
  else
42
55
  puts "Unknown error"
43
56
  end
44
-
45
- ## Articles
46
-
47
- * [Perl, Python and Ruby API libraries](http://www.surtri.com/2010/10/20/perl-python-ruby-api/)
@@ -1,3 +1,4 @@
1
1
  # Import all the SHODAN classes
2
2
  require 'shodan/api'
3
+ require 'shodan/shodan'
3
4
  require 'shodan/version'
@@ -0,0 +1,147 @@
1
+ require 'rubygems'
2
+ require 'cgi'
3
+ require 'json'
4
+ require 'openssl'
5
+ require 'net/http'
6
+
7
+ module Shodan
8
+
9
+ # The Shodan class interfaces with the official Shodan API.
10
+ # For more information on the API, please visit https://developer.shodan.io
11
+ #
12
+ # Author:: achillean (mailto:jmath@shodan.io)
13
+ #
14
+ # :title:Shodan::Shodan
15
+ class Shodan
16
+ attr_accessor :api_key
17
+ attr_accessor :base_url
18
+ attr_accessor :exploits
19
+
20
+ def initialize(api_key)
21
+ @api_key = api_key
22
+ @base_url = "https://api.shodan.io/"
23
+ @base_url_exploits = "https://exploits.shodan.io/api/"
24
+
25
+ @exploits = Exploits.new(self)
26
+ end
27
+
28
+ # Internal method that sends out the HTTP request.
29
+ # Expects a webservice function (ex. 'search') name and a hash of arguments.
30
+ def request(type, func, args)
31
+ if type == "exploits"
32
+ base_url = @base_url_exploits
33
+ else
34
+ base_url = @base_url
35
+ end
36
+
37
+ # Convert the argument hash into a string
38
+ args_string = args.map{|k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join("&")
39
+
40
+ # Craft the final request URL
41
+ url = "#{base_url}#{func}?key=#{@api_key}&#{args_string}"
42
+
43
+ # Send the request
44
+ puts url
45
+ uri = URI.parse(url)
46
+ http = Net::HTTP.new(uri.host, uri.port)
47
+ http.use_ssl = true
48
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
49
+ response = http.get(uri.request_uri)
50
+
51
+ # Convert the JSON data into a native Ruby hash
52
+ data = JSON.parse(response.body)
53
+
54
+ # Raise an error if something went wrong
55
+ if data.has_key? 'error'
56
+ raise data['error']
57
+ end
58
+
59
+ return data
60
+ end
61
+
62
+ # Get all available information on an IP.
63
+ #
64
+ # Arguments:
65
+ # ip - host IP (string)
66
+ #
67
+ # Returns a hash containing the host information
68
+ def host(ip)
69
+ return request('shodan', "shodan/host/#{ip}", {})
70
+ end
71
+
72
+ # Perform a search on Shodan.
73
+ #
74
+ # Arguments:
75
+ # query - search query; same format as the website (string)
76
+ #
77
+ # Returns a hash containing the search results
78
+ def search(query, params={})
79
+ params[:query] = query
80
+ return request('shodan', 'shodan/host/search', params)
81
+ end
82
+
83
+ # Find how many results there are for a search term.
84
+ #
85
+ # Arguments:
86
+ # query - search query; same format as the website (string)
87
+ #
88
+ # Returns a hash containing the total number of search results
89
+ def count(query, params={})
90
+ params[:query] = query
91
+ return request('shodan', 'shodan/host/count', params)
92
+ end
93
+
94
+ # Returns information about the current API key.
95
+ def info()
96
+ return request('shodan', 'api-info', {})
97
+ end
98
+ end
99
+
100
+ # The Exploits class shouldn't be used independently,
101
+ # as it depends on the Shodan class.
102
+ #
103
+ # Author:: achillean (mailto:jmath@shodan.io)
104
+ #
105
+ # :title:Shodan::Exploits
106
+ class Exploits
107
+ attr_accessor :api
108
+
109
+ def initialize(api)
110
+ @api = api
111
+ end
112
+
113
+ # Search the Shodan Exploits archive for exploits.
114
+ #
115
+ # Arguments:
116
+ # query -- Search terms
117
+ #
118
+ # Optional arguments:
119
+ # facets -- A comma-separated list of properties to get summary information on.
120
+ # page -- The page number to page through results 100 exploits at a time.
121
+ #
122
+ # Returns:
123
+ # A dictionary with 2 main items: matches (list) and total (int).
124
+ # Please visit https://developer.shodan.io/api/exploit-specification for up-to-date information on what an Exploit result contains.
125
+ def search(query, params={})
126
+ params[:query] = query
127
+ return @api.request('exploits', 'search', params)
128
+ end
129
+
130
+ # Search the Shodan Exploits archive for exploits but don't return results, only the number of matches.
131
+ #
132
+ # Arguments:
133
+ # query -- Search terms
134
+ #
135
+ # Optional arguments:
136
+ # facets -- A comma-separated list of properties to get summary information on.
137
+ #
138
+ # Returns:
139
+ # A dictionary with 1 main item: total (int).
140
+ def count(query, params={})
141
+ params[:query] = query
142
+ return @api.request('exploits', 'count', params)
143
+ end
144
+
145
+ end
146
+
147
+ end
@@ -1,3 +1,3 @@
1
1
  module Shodan
2
- Version = VERSION = '0.6.1'
2
+ Version = VERSION = '1.0.0'
3
3
  end
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # shodan_ips.py
4
+ # Search SHODAN and print a list of IPs matching the query
5
+ #
6
+ # Author: achillean
7
+ $:.unshift File.dirname(__FILE__)
8
+
9
+ require 'rubygems'
10
+ require 'shodan'
11
+
12
+ # Configuration
13
+ API_KEY = "eMLZhC7qt42If0U8ndfZTlCWSSxFYass"
14
+
15
+ # Input validation
16
+ if ARGV.length == 0
17
+ puts "Usage: ./shodan_ips.rb <search query>"
18
+ exit 1
19
+ end
20
+
21
+ begin
22
+ # Setup the API
23
+ api = Shodan::Shodan.new(API_KEY)
24
+
25
+ # Perform the search
26
+ query = ARGV.join(" ")
27
+
28
+ puts "\n--- shodan.info ---"
29
+ result = api.info()
30
+ puts result
31
+
32
+ puts '--- shodan.search ---'
33
+ result = api.search(query, :page => 2, :facets => 'port')
34
+
35
+ # Loop through the matches and print the IPs
36
+ puts "Total: #{result['total']}"
37
+ result['matches'][0..10].each{ |host|
38
+ puts host['ip_str']
39
+ }
40
+
41
+ puts "\nTop 10 Ports"
42
+ result['facets']['port'].each{ |facet|
43
+ puts "#{facet['value']}: #{facet['count']}"
44
+ }
45
+
46
+ puts "\n--- shodan.count ---"
47
+ result = api.count(query, :facets => 'port')
48
+
49
+ # Loop through the matches and print the IPs
50
+ puts "Total: #{result['total']}"
51
+ result['matches'][0..10].each{ |host|
52
+ puts host['ip_str']
53
+ }
54
+
55
+ puts "\nTop 10 Ports"
56
+ result['facets']['port'].each{ |facet|
57
+ puts "#{facet['value']}: #{facet['count']}"
58
+ }
59
+
60
+ puts "\n--- shodan.host ---"
61
+ result = api.host('217.140.75.46')
62
+ puts result
63
+ rescue Exception => e
64
+ puts "Error: #{e.to_s}"
65
+ exit 1
66
+ end
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # shodan_ips.py
4
+ # Search SHODAN and print a list of IPs matching the query
5
+ #
6
+ # Author: achillean
7
+ $:.unshift File.dirname(__FILE__)
8
+
9
+ require 'rubygems'
10
+ require 'shodan'
11
+
12
+ # Configuration
13
+ API_KEY = "eMLZhC7qt42If0U8ndfZTlCWSSxFYass"
14
+
15
+ # Input validation
16
+ if ARGV.length == 0
17
+ puts "Usage: ./shodan_ips.rb <search query>"
18
+ exit 1
19
+ end
20
+
21
+ begin
22
+ # Setup the API
23
+ api = Shodan::Shodan.new(API_KEY)
24
+
25
+ # Perform the search
26
+ query = ARGV.join(" ")
27
+
28
+ puts "\n--- shodan.exploits.search ---"
29
+ result = api.exploits.search(query, :page => 2, :facets => 'author')
30
+
31
+ # Loop through the matches and print the IPs
32
+ puts "Total: #{result['total']}"
33
+ result['matches'][0..10].each{ |exploit|
34
+ puts exploit
35
+ }
36
+
37
+ puts result['facets']
38
+
39
+ puts "\n--- shodan.exploits.search ---"
40
+ result = api.exploits.count(query, :facets => 'author')
41
+
42
+ # Loop through the matches and print the IPs
43
+ puts "Total: #{result['total']}"
44
+ result['matches'][0..10].each{ |exploit|
45
+ puts exploit
46
+ }
47
+
48
+ puts result['facets']
49
+ rescue Exception => e
50
+ puts "Error: #{e.to_s}"
51
+ exit 1
52
+ end
metadata CHANGED
@@ -1,88 +1,75 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: shodan
3
- version: !ruby/object:Gem::Version
4
- hash: 5
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 6
9
- - 1
10
- version: 0.6.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - John Matherly
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-08-26 00:00:00 -07:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2014-02-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: json
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 11
30
- segments:
31
- - 1
32
- - 4
33
- - 6
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
34
21
  version: 1.4.6
35
22
  type: :runtime
36
- version_requirements: *id001
37
- description: " A Ruby library to interact with the SHODAN API.\n"
38
- email: jmath@surtri.com
39
- executables: []
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.6
30
+ description: ! ' A Ruby library to interact with the Shodan API.
40
31
 
32
+ '
33
+ email: jmath@shodan.io
34
+ executables: []
41
35
  extensions: []
42
-
43
- extra_rdoc_files:
36
+ extra_rdoc_files:
44
37
  - LICENSE
45
38
  - README.md
46
- files:
39
+ files:
47
40
  - README.md
48
41
  - LICENSE
49
42
  - HISTORY.md
43
+ - lib/test_exploits.rb
44
+ - lib/test.rb
45
+ - lib/shodan.rb
50
46
  - lib/shodan/version.rb
47
+ - lib/shodan/shodan.rb
51
48
  - lib/shodan/api.rb
52
- - lib/shodan.rb
53
- has_rdoc: true
54
49
  homepage: http://github.com/achillean/shodan-ruby
55
50
  licenses: []
56
-
57
51
  post_install_message:
58
- rdoc_options:
52
+ rdoc_options:
59
53
  - --charset=UTF-8
60
- require_paths:
54
+ require_paths:
61
55
  - lib
62
- required_ruby_version: !ruby/object:Gem::Requirement
56
+ required_ruby_version: !ruby/object:Gem::Requirement
63
57
  none: false
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- hash: 3
68
- segments:
69
- - 0
70
- version: "0"
71
- required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
63
  none: false
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- hash: 3
77
- segments:
78
- - 0
79
- version: "0"
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
80
68
  requirements: []
81
-
82
69
  rubyforge_project:
83
- rubygems_version: 1.3.7
70
+ rubygems_version: 1.8.23
84
71
  signing_key:
85
72
  specification_version: 3
86
- summary: A Ruby library to interact with the SHODAN API.
73
+ summary: A Ruby library to interact with the Shodan API.
87
74
  test_files: []
88
-
75
+ has_rdoc: