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 +4 -4
- data/README.md +131 -8
- data/apullo.gemspec +1 -1
- data/lib/apullo/fingerprints/domain.rb +14 -0
- data/lib/apullo/fingerprints/favicon.rb +1 -1
- data/lib/apullo/fingerprints/http.rb +41 -1
- data/lib/apullo/fingerprints/ssh.rb +36 -4
- data/lib/apullo/target.rb +6 -6
- data/lib/apullo/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e817b368f4df9a10f01670a5319264d9fd1378f16e1a22590e587c8f75aba52
|
4
|
+
data.tar.gz: 52aa9310b175ee65cd82b1c9d800382edbf58081031bb2b16f88e63c9eba237b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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":
|
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": "
|
62
|
+
"date": "Sat, 11 Jan 2020 10:47:09 GMT",
|
64
63
|
"etag": "\"3147526947+gzip\"",
|
65
|
-
"expires": "
|
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 (
|
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
|
-
"
|
80
|
-
"
|
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
|
data/apullo.gemspec
CHANGED
@@ -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.
|
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
|
@@ -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
|
-
|
18
|
+
results = fingerprints
|
19
|
+
results = results.merge(meta: { links: links }) unless results.empty?
|
20
|
+
results
|
15
21
|
end
|
16
22
|
|
17
|
-
def
|
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
|
-
|
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
|
data/lib/apullo/target.rb
CHANGED
@@ -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
|
data/lib/apullo/version.rb
CHANGED
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.
|
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-
|
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.
|
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.
|
166
|
+
version: '3.2'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: parallel
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|