shodanz 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 64bf4789450bf85bdb1d354218d49c8bde71505e
4
- data.tar.gz: ef3506930d1125e20c93a4d2126defdfba8ba797
2
+ SHA256:
3
+ metadata.gz: e5da697873b94e412d3732b7a6ed529f83b9aa70bc2e14ae4b9a3ac8738659d4
4
+ data.tar.gz: f6636ec96aa077123f9e312e14259e1ddfadf6709225bc7c9b3b64b06c0ef611
5
5
  SHA512:
6
- metadata.gz: 9ec386f513214a9782eab065267661b75657468dc685740758e10da26b8b51417754eab719907adc3b5840884eeae317167a91b314f0fc2dd0964a23155a1533
7
- data.tar.gz: 6adda2fd0ac14b127c4de42325d1051cbd5bd4dea5ac2bb93858dfe9b5c31cdaaa903165fe1c71e72a281ed7e84fe5f59725df7debe67bca96f731f5851e33e1
6
+ metadata.gz: 4ca0447aa1e55d340da2959730edfb982565771adfe80bdc3a2206f4215669bf998c7cfc4c981c77635a3a58abb830f30b96ce29db46d7f72654166982d46f4e
7
+ data.tar.gz: f814bf859bbd66b80e85e3c9be339c4e68dde1717f389f49940910acfd648bd26178fd140d19d83935b632097d3525ff5c4688d860d8a30468b7d324e0754214
data/README.md CHANGED
@@ -54,9 +54,8 @@ client.rest_api.host_count("apache")
54
54
  client.rest_api.host_count("apache", country: "US")
55
55
  client.rest_api.host_count("apache", country: "US", state: "MI")
56
56
  client.rest_api.host_count("apache", country: "US", state: "MI", city: "Detroit")
57
- client.rest_api.host_count("apache", country: "US", state: "MI", city: "Detroit")
58
- client.rest_api.host_count("nginx". facets: { country: 5 })
59
- client.rest_api.host_count("apache". facets: { country: 5 })
57
+ client.rest_api.host_count("nginx", facets: { country: 5 })
58
+ client.rest_api.host_count("apache", facets: { country: 5 })
60
59
  ```
61
60
 
62
61
  #### Scan Targets
@@ -2,8 +2,10 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'shodanz'
3
3
  require 'pry'
4
4
 
5
- rest_api = Shodanz.api.rest.new
6
- streaming_api = Shodanz.api.streaming.new
7
- exploits_api = Shodanz.api.exploits.new
5
+ # rest_api = Shodanz.api.rest.new
6
+ # streaming_api = Shodanz.api.streaming.new
7
+ # exploits_api = Shodanz.api.exploits.new
8
+
9
+ client = Shodanz.client.new
8
10
 
9
11
  binding.pry
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require "shodanz"
3
+ require "chart_js"
4
+
5
+ module Top10
6
+ @rest_api = Shodanz.api.rest.new
7
+ def self.check(product)
8
+ begin
9
+ @rest_api.host_count(product: product, facets: { country: 10 })["facets"]["country"].collect { |x| x.values }.to_h.invert
10
+ rescue
11
+ puts "Unable to succesffully check the Shodan API."
12
+ exit 1
13
+ end
14
+ end
15
+ end
16
+
17
+ results = Top10.check("apache")
18
+
19
+ ChartJS.bar do
20
+ file "top_10_apache.html"
21
+ data do
22
+ labels results.keys
23
+ dataset "Countries" do
24
+ color :random
25
+ data results.values
26
+ end
27
+ end
28
+ end
@@ -1,13 +1,18 @@
1
- require "unirest"
2
- require "oj"
3
- require "shodanz/version"
4
- require "shodanz/api"
5
- require "shodanz/client"
1
+ require 'unirest'
2
+ require 'oj'
3
+ require 'shodanz/version'
4
+ require 'shodanz/api'
5
+ require 'shodanz/client'
6
6
 
7
+ # Shodanz is a modern Ruby gem for Shodan, the world's
8
+ # first search engine for Internet-connected devices.
7
9
  module Shodanz
10
+ # Shortcut for {Shodanz::API}
8
11
  def self.api
9
12
  API
10
13
  end
14
+
15
+ # Shortcut for {Shodanz::Client}
11
16
  def self.client
12
17
  Client
13
18
  end
@@ -1,29 +1,31 @@
1
- require_relative "apis/rest.rb"
2
- require_relative "apis/streaming.rb"
3
- require_relative "apis/exploits.rb"
1
+ require_relative 'apis/rest.rb'
2
+ require_relative 'apis/streaming.rb'
3
+ require_relative 'apis/exploits.rb'
4
4
 
5
5
  module Shodanz
6
- # There are 2 APIs for accessing Shodan: the REST API
7
- # and the Streaming API. The REST API provides methods
8
- # to search Shodan, look up hosts, get summary information
9
- # on queries and a variety of utility methods to make
10
- # developing easier. The Streaming API provides a raw,
11
- # real-time feed of the data that Shodan is currently
12
- # collecting. There are several feeds that can be subscribed
13
- # to, but the data can't be searched or otherwise interacted
14
- # with; it's a live feed of data meant for large-scale
6
+ # There are 2 APIs for accessing Shodan: the REST API
7
+ # and the Streaming API. The REST API provides methods
8
+ # to search Shodan, look up hosts, get summary information
9
+ # on queries and a variety of utility methods to make
10
+ # developing easier. The Streaming API provides a raw,
11
+ # real-time feed of the data that Shodan is currently
12
+ # collecting. There are several feeds that can be subscribed
13
+ # to, but the data can't be searched or otherwise interacted
14
+ # with; it's a live feed of data meant for large-scale
15
15
  # consumption of Shodan's information.
16
+ #
17
+ # @author Kent 'picat' Gruber
16
18
  module API
17
19
  # REST API class.
18
20
  def self.rest
19
21
  REST
20
22
  end
21
-
23
+
22
24
  # Streaming API class.
23
25
  def self.streaming
24
26
  Streaming
25
27
  end
26
-
28
+
27
29
  # Exploits API class.
28
30
  def self.exploits
29
31
  Exploits
@@ -1,8 +1,7 @@
1
1
  module Shodanz
2
-
3
2
  module API
4
- # The Exploits API provides access to several exploit
5
- # and vulnerability data sources. At the moment, it
3
+ # The Exploits API provides access to several exploit
4
+ # and vulnerability data sources. At the moment, it
6
5
  # searches across the following:
7
6
  # - Exploit DB
8
7
  # - Metasploit
@@ -10,76 +9,80 @@ module Shodanz
10
9
  #
11
10
  # @author Kent 'picat' Gruber
12
11
  class Exploits
12
+ # @return [String]
13
13
  attr_accessor :key
14
-
14
+
15
15
  # The path to the REST API endpoint.
16
- URL = "https://exploits.shodan.io/api/"
16
+ URL = 'https://exploits.shodan.io/api/'.freeze
17
17
 
18
- # @param key [String] SHODAN API key, defaulted to the *SHODAN_API_KEY* enviroment variable.
18
+ # @param key [String] SHODAN API key, defaulted to
19
+ # the *SHODAN_API_KEY* enviroment variable.
19
20
  def initialize(key: ENV['SHODAN_API_KEY'])
20
21
  self.key = key
21
- warn "No key has been found or provided!" unless self.key?
22
+ warn 'No key has been found or provided!' unless key?
22
23
  end
23
24
 
24
25
  # Check if there's an API key.
26
+ # @return [String]
25
27
  def key?
26
- return true if @key; false
28
+ return true if @key
29
+ false
27
30
  end
28
31
 
29
- # Search across a variety of data sources for exploits and
32
+ # Search across a variety of data sources for exploits and
30
33
  # use facets to get summary information.
31
34
  # == Example
32
35
  # api.search("SQL", port: 443)
33
36
  # api.search(port: 22)
34
37
  # api.search(type: "dos")
35
- def search(query = "", facets: {}, page: 1, **params)
38
+ def search(query = '', page: 1, **params)
36
39
  params[:query] = query
37
40
  params = turn_into_query(params)
38
41
  facets = turn_into_facets(facets)
39
42
  params[:page] = page
40
- get("search", params.merge(facets))
43
+ get('search', params.merge(facets))
41
44
  end
42
45
 
43
- # This method behaves identical to the "/search" method with
46
+ # This method behaves identical to the "/search" method with
44
47
  # the difference that it doesn't return any results.
45
48
  # == Example
46
49
  # api.count(type: "dos")
47
- def count(query = "", facets: {}, page: 1, **params)
50
+ def count(query = '', page: 1, **params)
48
51
  params[:query] = query
49
52
  params = turn_into_query(params)
50
53
  facets = turn_into_facets(params)
51
54
  params[:page] = page
52
- get("count", params.merge(facets))
55
+ get('count', params.merge(facets))
53
56
  end
54
57
 
55
58
  # Perform a direct GET HTTP request to the REST API.
56
59
  def get(path, **params)
57
60
  resp = Unirest.get "#{URL}#{path}?key=#{@key}", parameters: params
58
- raise resp.body["error"] if resp.code != 200 and resp.body.has_key?("error")
61
+ if resp.code != 200 && resp.body.key?('error')
62
+ raise resp.body['error']
63
+ end
59
64
  resp.body
60
65
  end
61
66
 
62
67
  private
63
68
 
64
69
  def turn_into_query(params)
65
- filters = params.reject { |key, value| key == :query }
70
+ filters = params.reject { |key, _| key == :query }
66
71
  filters.each do |key, value|
67
72
  params[:query] << " #{key}:#{value}"
68
73
  end
69
- params.select { |key, value| key == :query }
74
+ params.select { |key, _| key == :query }
70
75
  end
71
76
 
72
77
  def turn_into_facets(facets)
73
- filters = facets.reject { |key, value| key == :facets }
78
+ filters = facets.reject { |key, _| key == :facets }
74
79
  facets[:facets] = []
75
80
  filters.each do |key, value|
76
81
  facets[:facets] << "#{key}:#{value}"
77
82
  end
78
- facets[:facets] = facets[:facets].join(",")
79
- facets.select { |key, value| key == :facets }
83
+ facets[:facets] = facets[:facets].join(',')
84
+ facets.select { |key, _| key == :facets }
80
85
  end
81
-
82
86
  end
83
-
84
87
  end
85
88
  end
@@ -5,6 +5,7 @@ module Shodanz
5
5
  # hosts, get summary information on queries and a variety
6
6
  # of other utilities. This requires you to have an API key
7
7
  # which you can get from Shodan.
8
+ #
8
9
  # @author Kent 'picat' Gruber
9
10
  class REST
10
11
  attr_accessor :key
@@ -112,7 +113,7 @@ module Shodanz
112
113
  def crawl_for(**params)
113
114
  params[:query] = ""
114
115
  params = turn_into_query(params)
115
- post("shodan/scan/internet", params)
116
+ post('shodan/scan/internet', params)
116
117
  end
117
118
 
118
119
  # Check the progress of a previously submitted scan request.
@@ -122,49 +123,52 @@ module Shodanz
122
123
 
123
124
  # Use this method to obtain a list of search queries that users have saved in Shodan.
124
125
  def community_queries(**params)
125
- get("shodan/query", params)
126
+ get('shodan/query', params)
126
127
  end
127
128
 
128
129
  # Use this method to search the directory of search queries that users have saved in Shodan.
129
130
  def search_for_community_query(query, **params)
130
131
  params[:query] = query
131
132
  params = turn_into_query(params)
132
- get("shodan/query/search", params)
133
+ get('shodan/query/search', params)
133
134
  end
134
135
 
135
136
  # Use this method to obtain a list of popular tags for the saved search queries in Shodan.
136
137
  def popular_query_tags(size = 10)
137
138
  params = {}
138
139
  params[:size] = size
139
- get("shodan/query/tags", params)
140
+ get('shodan/query/tags', params)
140
141
  end
141
142
 
142
143
  # Returns information about the Shodan account linked to this API key.
143
144
  def profile
144
- get("account/profile")
145
+ get('account/profile')
145
146
  end
146
147
 
147
148
  # Look up the IP address for the provided list of hostnames.
148
149
  def resolve(*hostnames)
149
- get("dns/resolve", hostnames: hostnames.join(","))
150
+ get('dns/resolve', hostnames: hostnames.join(","))
150
151
  end
151
152
 
152
- # Look up the hostnames that have been defined for the given list of IP addresses.
153
+ # Look up the hostnames that have been defined for the
154
+ # given list of IP addresses.
153
155
  def reverse_lookup(*ips)
154
- get("dns/reverse", ips: ips.join(","))
156
+ get('dns/reverse', ips: ips.join(","))
155
157
  end
156
158
 
157
- # Shows the HTTP headers that your client sends when connecting to a webserver.
159
+ # Shows the HTTP headers that your client sends when
160
+ # connecting to a webserver.
158
161
  def http_headers
159
- get("tools/httpheaders")
162
+ get('tools/httpheaders')
160
163
  end
161
164
 
162
165
  # Get your current IP address as seen from the Internet.
163
166
  def my_ip
164
- get("tools/my_ip")
167
+ get('tools/myip')
165
168
  end
166
169
 
167
- # Calculates a honeypot probability score ranging from 0 (not a honeypot) to 1.0 (is a honeypot).
170
+ # Calculates a honeypot probability score ranging
171
+ # from 0 (not a honeypot) to 1.0 (is a honeypot).
168
172
  def honeypot_score(ip)
169
173
  get("labs/honeyscore/#{ip}")
170
174
  end
@@ -177,38 +181,43 @@ module Shodanz
177
181
  # Perform a direct GET HTTP request to the REST API.
178
182
  def get(path, **params)
179
183
  resp = Unirest.get "#{URL}#{path}?key=#{@key}", parameters: params
180
- raise resp if resp.code != 200 #and resp.body.has_key?("error")
184
+ if resp.code != 200
185
+ binding.pry
186
+ raise resp.body['error'] if resp.body.key?('error')
187
+ raise resp
188
+ end
181
189
  resp.body
182
190
  end
183
191
 
184
192
  # Perform a direct POST HTTP request to the REST API.
185
193
  def post(path, **params)
186
194
  resp = Unirest.post "#{URL}#{path}?key=#{@key}", parameters: params
187
- raise resp.body["error"] if resp.code != 200 and resp.body.has_key?("error")
195
+ if resp.code != 200
196
+ raise resp.body['error'] if resp.body.key?('error')
197
+ raise resp
198
+ end
188
199
  resp.body
189
200
  end
190
201
 
191
202
  private
192
203
 
193
204
  def turn_into_query(params)
194
- filters = params.reject { |key, value| key == :query }
205
+ filters = params.reject { |key, _| key == :query }
195
206
  filters.each do |key, value|
196
207
  params[:query] << " #{key}:#{value}"
197
208
  end
198
- params.select { |key, value| key == :query }
209
+ params.select { |key, _| key == :query }
199
210
  end
200
211
 
201
212
  def turn_into_facets(facets)
202
- filters = facets.reject { |key, value| key == :facets }
213
+ filters = facets.reject { |key, _| key == :facets }
203
214
  facets[:facets] = []
204
215
  filters.each do |key, value|
205
216
  facets[:facets] << "#{key}:#{value}"
206
217
  end
207
- facets[:facets] = facets[:facets].join(",")
208
- facets.select { |key, value| key == :facets }
218
+ facets[:facets] = facets[:facets].join(',')
219
+ facets.select { |key, _| key == :facets }
209
220
  end
210
-
211
221
  end
212
-
213
222
  end
214
223
  end
@@ -1,22 +1,22 @@
1
1
  module Shodanz
2
+ # General client container class for all three
3
+ # of Shodan's available API endpoints in a
4
+ # convient place to use.
5
+ #
6
+ # @author Kent 'picat' Gruber
2
7
  class Client
8
+ # @return [Shodanz::API::REST]
9
+ attr_reader :rest_api
10
+ # @return [Shodanz::API::Streaming]
11
+ attr_reader :streaming_api
12
+ # @return [Shodanz::API::Exploits]
13
+ attr_reader :exploits_api
14
+
3
15
  # Create a new client to connect to any of the APIs.
4
16
  def initialize
5
17
  @rest_api = Shodanz.api.rest.new
6
18
  @streaming_api = Shodanz.api.streaming.new
7
- @exploits_api = Shodanz.api.exploits.new
8
- end
9
-
10
- def rest_api
11
- @rest_api
12
- end
13
-
14
- def streaming_api
15
- @streaming_api
16
- end
17
-
18
- def exploits_api
19
- @exploits_api
19
+ @exploits_api = Shodanz.api.exploits.new
20
20
  end
21
21
  end
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module Shodanz
2
- VERSION = "1.0.2"
2
+ VERSION = '1.0.3'.freeze
3
3
  end
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ["lib"]
21
21
 
22
22
  spec.add_dependency "unirest", "1.1.2"
23
- spec.add_dependency "json", "1.8.6"
24
- spec.add_dependency "oj", "3.3.8"
23
+ spec.add_dependency "json" # specifying version breaks things, what?
24
+ spec.add_dependency "oj", "3.5.0"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.15"
27
- spec.add_development_dependency "rake", "~> 10.0"
28
- spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "bundler", "~> 1.16.1"
27
+ spec.add_development_dependency "rake", "~> 12.3.1"
28
+ spec.add_development_dependency "rspec", "~> 3.7.0"
29
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shodanz
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kent 'picatz' Gruber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-20 00:00:00.000000000 Z
11
+ date: 2018-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: unirest
@@ -28,72 +28,72 @@ dependencies:
28
28
  name: json
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.8.6
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 1.8.6
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: oj
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 3.3.8
47
+ version: 3.5.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 3.3.8
54
+ version: 3.5.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.15'
61
+ version: 1.16.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.15'
68
+ version: 1.16.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: 12.3.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: 12.3.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.0'
89
+ version: 3.7.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.0'
96
+ version: 3.7.0
97
97
  description: Featuring full support for the REST, Streaming and Exploits API
98
98
  email:
99
99
  - kgruber1@emich.edu
@@ -111,6 +111,7 @@ files:
111
111
  - Rakefile
112
112
  - examples/debug.rb
113
113
  - examples/top_10_countries_running.rb
114
+ - examples/top_10_countries_running_apache_chart.rb
114
115
  - lib/shodanz.rb
115
116
  - lib/shodanz/api.rb
116
117
  - lib/shodanz/apis/exploits.rb
@@ -139,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
140
  version: '0'
140
141
  requirements: []
141
142
  rubyforge_project:
142
- rubygems_version: 2.6.12
143
+ rubygems_version: 2.7.3
143
144
  signing_key:
144
145
  specification_version: 4
145
146
  summary: A modern Ruby gem for Shodan, the world's first search engine for Internet-connected