apullo 0.1.5 → 0.2.0

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
2
  SHA256:
3
- metadata.gz: 96eb9917a6d5fcef270fe520a2312f7447896b2d1e6f0bfc61f966d554e8f9c6
4
- data.tar.gz: ca4807677d7519969aae72fcc647cad01f3799e04cea1d3aee3433efbb4e77bc
3
+ metadata.gz: 1e817b368f4df9a10f01670a5319264d9fd1378f16e1a22590e587c8f75aba52
4
+ data.tar.gz: 52aa9310b175ee65cd82b1c9d800382edbf58081031bb2b16f88e63c9eba237b
5
5
  SHA512:
6
- metadata.gz: 8d32ee78a83177d0dbca9a7d418f5e5e8af4894f516d05ed705a1ab8b082601663353f69e30571663015ddf0fbe9e91b19e6ac0b83431369a7866f51b147b6f7
7
- data.tar.gz: 5e846ede99ffd718f5e75944eb1ef79b97be719f6cbbf62a43ebf05891e405142a1781d6676ec7e8fabdfe5d0530b7fddeedf7ef0573ca07165110828644a098
6
+ metadata.gz: a005b2e6d73cbac89b060e08e38147c27cc5d633eb6526e804f652ea813d9395236445c8674e8c41eec32a643f4c9cf1d550ffa79a4cc10244068e41cf3661f6
7
+ data.tar.gz: 9d8cb76e97fe4a7adc43618abbce2419e8c2b0549abe894611159e54486110a47c88be51bfd13eb86fb4bad52866ee99d7e048bececefb14c3cd92a2b9cf654f
data/README.md CHANGED
@@ -50,34 +50,43 @@ $ apullo check https://example.com
50
50
  },
51
51
  "cert": {
52
52
  "md5": "3510c21c66bd62010fc547d3cd3f0ce6",
53
- "serial": "21020869104500376438182461249190639870",
53
+ "serial": 21020869104500376438182461249190639870,
54
54
  "sha1": "7bb698386970363d2919cc5772846984ffd4a889",
55
55
  "sha256": "9250711c54de546f4370e0c3d3a3ec45bc96092a25a4a71a1afa396af7047eb8"
56
56
  },
57
57
  "favicon": {
58
58
  },
59
59
  "headers": {
60
- "accept-ranges": "bytes",
61
60
  "cache-control": "max-age=604800",
62
61
  "content-type": "text/html; charset=UTF-8",
63
- "date": "Thu, 07 Nov 2019 23:21:43 GMT",
62
+ "date": "Sat, 11 Jan 2020 10:47:09 GMT",
64
63
  "etag": "\"3147526947+gzip\"",
65
- "expires": "Thu, 14 Nov 2019 23:21:43 GMT",
64
+ "expires": "Sat, 18 Jan 2020 10:47:09 GMT",
66
65
  "last-modified": "Thu, 17 Oct 2019 07:18:26 GMT",
67
- "server": "ECS (sec/9739)",
66
+ "server": "ECS (oxr/830F)",
68
67
  "vary": "Accept-Encoding",
69
68
  "x-cache": "HIT",
70
69
  "content-length": "648"
71
70
  },
72
71
  "meta": {
73
- "url": "https://example.com"
72
+ "url": "https://example.com",
73
+ "links": {
74
+ "shodan": {
75
+ "body": "https://www.shodan.io/search?query=http.html_hash%3A-2087618365",
76
+ "cert": "https://www.shodan.io/search?q=ssl.cert.serial%3A21020869104500376438182461249190639870"
77
+ },
78
+ "censys": {
79
+ "body": "https://censys.io/ipv4?q=ea8fac7c65fb589b0d53560f5251f74f9e9b243478dcb6b3ea79b5e36449c8d9",
80
+ "cert": "https://censys.io/ipv4?q=9250711c54de546f4370e0c3d3a3ec45bc96092a25a4a71a1afa396af7047eb8"
81
+ }
82
+ }
74
83
  }
75
84
  },
76
85
  "domain": {
77
86
  "dns": {
78
87
  "ns": [
79
- "b.iana-servers.net",
80
- "a.iana-servers.net"
88
+ "a.iana-servers.net",
89
+ "b.iana-servers.net"
81
90
  ],
82
91
  "cname": [
83
92
 
@@ -122,6 +131,11 @@ $ apullo check https://example.com
122
131
  "technical_contacts": [
123
132
 
124
133
  ]
134
+ },
135
+ "meta": {
136
+ "links": {
137
+ "securitytrails": "https://securitytrails.com/domain/example.com/dns"
138
+ }
125
139
  }
126
140
  },
127
141
  "ssh": {
@@ -130,6 +144,115 @@ $ apullo check https://example.com
130
144
  "target": "https://example.com"
131
145
  }
132
146
  }
147
+
148
+ $ apullo check jppost-ku.com
149
+ {
150
+ "http": {
151
+ "body": {
152
+ "md5": "0728450344e6ea95107ce8c3b00f10ae",
153
+ "mmh3": 421543491,
154
+ "sha1": "6fa29d366b33d5f3c54d62c95b23aa1cce2587a3",
155
+ "sha256": "7bc86f6a3d8877bd84d9917c3661658867af3fdb44842b973be2d299fe793dc2"
156
+ },
157
+ "cert": {
158
+ },
159
+ "favicon": {
160
+ "md5": "ad184c25a1a01d97696dcb59a1ffef74",
161
+ "mmh3": 111036816,
162
+ "sha1": "cb4842a54c3e96408765290cb810793302c17f0b",
163
+ "sha256": "6949c58f841fa21a89e2e2375ae5645e1db62385f89a0218766f2b0a9c490fb8",
164
+ "meta": {
165
+ "url": "https://www.post.japanpost.jp/img/common/touch-icon.png"
166
+ }
167
+ },
168
+ "headers": {
169
+ "server": "Apache-Coyote/1.1",
170
+ "accept-ranges": "bytes",
171
+ "etag": "W/\"54423-1577193448000\"",
172
+ "last-modified": "Tue, 24 Dec 2019 13:17:28 GMT",
173
+ "content-type": "text/html",
174
+ "content-length": "54423",
175
+ "date": "Sat, 11 Jan 2020 10:48:28 GMT"
176
+ },
177
+ "meta": {
178
+ "url": "http://jppost-ku.com",
179
+ "links": {
180
+ "shodan": {
181
+ "body": "https://www.shodan.io/search?query=http.html_hash%3A421543491",
182
+ "favicon": "https://www.shodan.io/search?query=http.favicon.hash%3A111036816"
183
+ },
184
+ "censys": {
185
+ "body": "https://censys.io/ipv4?q=7bc86f6a3d8877bd84d9917c3661658867af3fdb44842b973be2d299fe793dc2"
186
+ }
187
+ }
188
+ }
189
+ },
190
+ "domain": {
191
+ "dns": {
192
+ "ns": [
193
+ "ns2.bdydns.cn",
194
+ "ns1.bdydns.cn"
195
+ ],
196
+ "cname": [
197
+
198
+ ],
199
+ "soa": [
200
+ "sa.dudns.com"
201
+ ],
202
+ "mx": [
203
+
204
+ ],
205
+ "a": [
206
+ "45.10.90.113"
207
+ ],
208
+ "aaaa": [
209
+
210
+ ]
211
+ },
212
+ "whois": {
213
+ "registrant_contacts": [
214
+
215
+ ],
216
+ "admin_contacts": [
217
+
218
+ ],
219
+ "technical_contacts": [
220
+
221
+ ]
222
+ },
223
+ "meta": {
224
+ "links": {
225
+ "securitytrails": "https://securitytrails.com/domain/jppost-ku.com/dns"
226
+ }
227
+ }
228
+ },
229
+ "ssh": {
230
+ "rsa": {
231
+ "md5": "565c74c34ca3a4a44625e8cbf732bed5",
232
+ "sha1": "2fb4d2241f7b6dd83c376548a794d5e903ce2b64",
233
+ "sha256": "e97b6fa7a9c3cb00919fbe90d862b08c2b4b1ac8c09701a0bb063e47ae764160"
234
+ },
235
+ "ecdsa-sha2-nistp256": {
236
+ "md5": "59e75650c592742fbe54a56140965af6",
237
+ "sha1": "1cddc49647d0e3cd5fefcc15e41fa036651ba903",
238
+ "sha256": "54a7bcac7ac7c2ffc501396dd1ae68b0c7f7b3a627c813c0020822b7a01e6a69"
239
+ },
240
+ "ed25519": {
241
+ "md5": "5ca62c892f4cb1c3197b245b2e1b9254",
242
+ "sha1": "9bbcfec876f80c831a9ace061dfa7ba7d207c2d2",
243
+ "sha256": "e7c2073b8ae07dea059307eb4d1f435c92d25228e5def49075e8007f5cb44765"
244
+ },
245
+ "meta": {
246
+ "links": {
247
+ "shodan": "https://www.shodan.io/search?query=port%3A22+56%3A5c%3A74%3Ac3%3A4c%3Aa3%3Aa4%3Aa4%3A46%3A25%3Ae8%3Acb%3Af7%3A32%3Abe%3Ad5",
248
+ "censys": "https://censys.io/ipv4?q=54a7bcac7ac7c2ffc501396dd1ae68b0c7f7b3a627c813c0020822b7a01e6a69"
249
+ }
250
+ }
251
+ },
252
+ "meta": {
253
+ "target": "jppost-ku.com"
254
+ }
255
+ }
133
256
  ```
134
257
 
135
258
  ## Notes
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency "ipaddr", "~> 1.2"
36
36
  spec.add_dependency "mem", "~> 0.1"
37
37
  spec.add_dependency "murmurhash3", "~> 0.1"
38
- spec.add_dependency "oga", "~> 3.0"
38
+ spec.add_dependency "oga", "~> 3.2"
39
39
  spec.add_dependency "parallel", "~> 1.19"
40
40
  spec.add_dependency "public_suffix", "~> 4.0"
41
41
  spec.add_dependency "ssh_scan", "~> 0.0"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "resolv"
4
+ require "uri"
4
5
  require "whois-parser"
5
6
 
6
7
  module Apullo
@@ -21,6 +22,9 @@ module Apullo
21
22
  {
22
23
  dns: resources,
23
24
  whois: contacts,
25
+ meta: {
26
+ links: links
27
+ }
24
28
  }
25
29
  end
26
30
 
@@ -89,6 +93,16 @@ module Apullo
89
93
  technical_contacts: technical_contacts
90
94
  }
91
95
  end
96
+
97
+ def securitytrails_link
98
+ target.domain? ? "https://securitytrails.com/domain/#{target.host}/dns" : "https://securitytrails.com/list/ip/#{target.host}"
99
+ end
100
+
101
+ def links
102
+ {
103
+ securitytrails: securitytrails_link
104
+ }
105
+ end
92
106
  end
93
107
  end
94
108
  end
@@ -24,7 +24,7 @@ module Apullo
24
24
  sha1: hash.sha1,
25
25
  sha256: hash.sha256,
26
26
  meta: {
27
- url: uri.to_s
27
+ url: uri.to_s,
28
28
  }
29
29
  }
30
30
  end
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mem"
3
4
  require "net/http"
4
5
  require "oga"
5
6
  require "openssl"
7
+ require "uri"
6
8
 
7
9
  module Apullo
8
10
  module Fingerprint
9
11
  class HTTP < Base
12
+ include Mem
13
+
10
14
  attr_writer :headers
11
15
 
12
16
  def initialize(target)
@@ -26,7 +30,8 @@ module Apullo
26
30
  favicon: favicon,
27
31
  headers: response_headers,
28
32
  meta: {
29
- url: target.url
33
+ url: target.url,
34
+ links: links
30
35
  }
31
36
  }
32
37
  end
@@ -42,6 +47,7 @@ module Apullo
42
47
  sha256: hash.sha256,
43
48
  }
44
49
  end
50
+ memoize :cert
45
51
 
46
52
  def body
47
53
  return {} unless @body
@@ -54,6 +60,7 @@ module Apullo
54
60
  sha256: hash.sha256,
55
61
  }
56
62
  end
63
+ memoize :body
57
64
 
58
65
  def favicon
59
66
  url = favicon_url
@@ -62,6 +69,7 @@ module Apullo
62
69
  favicon = Favicon.new(url)
63
70
  favicon.results
64
71
  end
72
+ memoize :favicon
65
73
 
66
74
  def response_headers
67
75
  @response_headers || {}
@@ -133,6 +141,38 @@ module Apullo
133
141
  def rebuild_target(url)
134
142
  @target = Target.new(url)
135
143
  end
144
+
145
+ def shodan_link
146
+ uri = URI("https://www.shodan.io/search")
147
+ uri.query = URI.encode_www_form(query: "http.html_hash:#{body.dig(:mmh3)}")
148
+ body_link = body.empty? ? nil : uri.to_s
149
+
150
+ uri.query = URI.encode_www_form(q: "ssl.cert.serial:#{cert.dig(:serial)}")
151
+ cert_link = cert.empty? ? nil : uri.to_s
152
+
153
+ uri.query = URI.encode_www_form(query: "http.favicon.hash:#{favicon.dig(:mmh3)}")
154
+ favicon_link = favicon.empty? ? nil : uri.to_s
155
+
156
+ { body: body_link, cert: cert_link, favicon: favicon_link }.compact
157
+ end
158
+
159
+ def censys_link
160
+ uri = URI("https://censys.io/ipv4")
161
+ uri.query = URI.encode_www_form(q: body.dig(:sha256))
162
+ body_link = body.empty? ? nil : uri.to_s
163
+
164
+ uri.query = URI.encode_www_form(q: cert.dig(:sha256))
165
+ cert_link = cert.empty? ? nil : uri.to_s
166
+
167
+ { body: body_link, cert: cert_link }.compact
168
+ end
169
+
170
+ def links
171
+ {
172
+ shodan: shodan_link,
173
+ censys: censys_link
174
+ }
175
+ end
136
176
  end
137
177
  end
138
178
  end
@@ -1,34 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mem"
3
4
  require "ssh_scan"
5
+ require "uri"
4
6
 
5
7
  module Apullo
6
8
  module Fingerprint
7
9
  class SSH < Base
10
+ include Mem
11
+
8
12
  DEFAULT_OPTIONS = { "timeout" => 3 }.freeze
9
13
  DEFAULT_PORTS = [22, 2222].freeze
10
14
 
11
15
  private
12
16
 
13
17
  def build_results
14
- pluck_fingerprints
18
+ results = fingerprints
19
+ results = results.merge(meta: { links: links }) unless results.empty?
20
+ results
15
21
  end
16
22
 
17
- def pluck_fingerprints
23
+ def fingerprints
18
24
  result = scan
19
25
  keys = result.dig("keys") || {}
20
26
  keys.map do |cipher, data|
21
- raw = data.dig("raw")
22
27
  fingerprints = data.dig("fingerprints") || []
23
28
  normalized_fingerprints = fingerprints.map do |hash, value|
24
29
  [hash, value.delete(":")]
25
30
  end.to_h
26
31
  [
27
32
  cipher,
28
- { raw: raw, fingerprints: normalized_fingerprints }
33
+ normalized_fingerprints
29
34
  ]
30
35
  end.to_h
31
36
  end
37
+ memoize :fingerprints
32
38
 
33
39
  def _scan(target, port: 22)
34
40
  return nil unless target.host
@@ -47,6 +53,32 @@ module Apullo
47
53
  end
48
54
  {}
49
55
  end
56
+
57
+ def shodan_link
58
+ uri = URI("https://www.shodan.io/search")
59
+ fingerprint = fingerprints.dig("rsa", "md5") || fingerprints.dig("ecdsa-sha2-nistp256", "md5")
60
+ return nil unless fingerprint
61
+
62
+ fingerprint = fingerprint.to_s.chars.each_slice(2).map(&:join).join(":")
63
+ uri.query = URI.encode_www_form(query: "port:22 #{fingerprint}")
64
+ uri.to_s
65
+ end
66
+
67
+ def censys_link
68
+ uri = URI("https://censys.io/ipv4")
69
+ fingerprint = fingerprints.dig("ecdsa-sha2-nistp256", "sha256") || fingerprints.dig("rsa", "sha256")
70
+ return nil unless fingerprint
71
+
72
+ uri.query = URI.encode_www_form(q: fingerprint.to_s)
73
+ uri.to_s
74
+ end
75
+
76
+ def links
77
+ {
78
+ shodan: shodan_link,
79
+ censys: censys_link
80
+ }
81
+ end
50
82
  end
51
83
  end
52
84
  end
@@ -39,12 +39,6 @@ module Apullo
39
39
  uri && (ip? | domain?)
40
40
  end
41
41
 
42
- private
43
-
44
- def _url
45
- @_url ||= id.start_with?("http://", "https://") ? id : "http://#{id}"
46
- end
47
-
48
42
  def ip?
49
43
  IPAddr.new host
50
44
  true
@@ -58,6 +52,12 @@ module Apullo
58
52
  PublicSuffix.valid?(host, default_rule: nil)
59
53
  end
60
54
 
55
+ private
56
+
57
+ def _url
58
+ @_url ||= id.start_with?("http://", "https://") ? id : "http://#{id}"
59
+ end
60
+
61
61
  def resolve
62
62
  Resolv.getaddress uri&.host
63
63
  rescue Resolv::ResolvError => _e
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Apullo
4
- VERSION = "0.1.5"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apullo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-03 00:00:00.000000000 Z
11
+ date: 2020-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -156,14 +156,14 @@ dependencies:
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '3.0'
159
+ version: '3.2'
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '3.0'
166
+ version: '3.2'
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: parallel
169
169
  requirement: !ruby/object:Gem::Requirement