apullo 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +42 -97
- data/apullo.gemspec +4 -3
- data/lib/apullo/cli.rb +2 -1
- data/lib/apullo/fingerprints/base.rb +18 -0
- data/lib/apullo/fingerprints/domain.rb +3 -3
- data/lib/apullo/fingerprints/http.rb +28 -15
- data/lib/apullo/fingerprints/ssh.rb +12 -8
- data/lib/apullo/version.rb +1 -1
- metadata +22 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3fef54d32890b574081af9e64c6d76dc01287651779bb43eaecc046df9763e43
|
|
4
|
+
data.tar.gz: 07f3676d94fd54345a40a547c0a6b82ffa5d599ff34a21b7cf59270e608f2df1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5bd0f54aebb6c6f7515fbc2979c22c3af2a3553535665f5a3ca7af5bd1358f0e5372b33a2db03c181e115d9aac87d7b819f57b49c281a8362c78860d175c2545
|
|
7
|
+
data.tar.gz: d5ac2f8806e242005d2bd6ee1d03de9126eed3b01b93a19583fe387e5842cce1b5a99ff05dcbfc6a3b58ba5b4d5ae38e11a48a68872953b03e47dcf2417d5e45
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
|
@@ -31,6 +31,7 @@ Commands:
|
|
|
31
31
|
It takes basic network fingerprints of a target.
|
|
32
32
|
|
|
33
33
|
- Hashes of an HTTP response body
|
|
34
|
+
- Headers of an HTTP response
|
|
34
35
|
- Hashes of an SSL certificate
|
|
35
36
|
- Hashes of a favicon image
|
|
36
37
|
- Hashes of an SSH host key
|
|
@@ -54,9 +55,46 @@ $ apullo check https://example.com
|
|
|
54
55
|
"sha256": "9250711c54de546f4370e0c3d3a3ec45bc96092a25a4a71a1afa396af7047eb8"
|
|
55
56
|
},
|
|
56
57
|
"favicon": {
|
|
58
|
+
},
|
|
59
|
+
"headers": {
|
|
60
|
+
"accept-ranges": "bytes",
|
|
61
|
+
"cache-control": "max-age=604800",
|
|
62
|
+
"content-type": "text/html; charset=UTF-8",
|
|
63
|
+
"date": "Thu, 07 Nov 2019 23:21:43 GMT",
|
|
64
|
+
"etag": "\"3147526947+gzip\"",
|
|
65
|
+
"expires": "Thu, 14 Nov 2019 23:21:43 GMT",
|
|
66
|
+
"last-modified": "Thu, 17 Oct 2019 07:18:26 GMT",
|
|
67
|
+
"server": "ECS (sec/9739)",
|
|
68
|
+
"vary": "Accept-Encoding",
|
|
69
|
+
"x-cache": "HIT",
|
|
70
|
+
"content-length": "648"
|
|
71
|
+
},
|
|
72
|
+
"meta": {
|
|
73
|
+
"url": "https://example.com"
|
|
57
74
|
}
|
|
58
75
|
},
|
|
59
76
|
"domain": {
|
|
77
|
+
"dns": {
|
|
78
|
+
"ns": [
|
|
79
|
+
"b.iana-servers.net",
|
|
80
|
+
"a.iana-servers.net"
|
|
81
|
+
],
|
|
82
|
+
"cname": [
|
|
83
|
+
|
|
84
|
+
],
|
|
85
|
+
"soa": [
|
|
86
|
+
"noc.dns.icann.org"
|
|
87
|
+
],
|
|
88
|
+
"mx": [
|
|
89
|
+
|
|
90
|
+
],
|
|
91
|
+
"a": [
|
|
92
|
+
"93.184.216.34"
|
|
93
|
+
],
|
|
94
|
+
"aaaa": [
|
|
95
|
+
"2606:2800:220:1:248:1893:25C8:1946"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
60
98
|
"whois": {
|
|
61
99
|
"registrant_contacts": [
|
|
62
100
|
{
|
|
@@ -84,27 +122,6 @@ $ apullo check https://example.com
|
|
|
84
122
|
"technical_contacts": [
|
|
85
123
|
|
|
86
124
|
]
|
|
87
|
-
},
|
|
88
|
-
"dns": {
|
|
89
|
-
"ns": [
|
|
90
|
-
"a.iana-servers.net",
|
|
91
|
-
"b.iana-servers.net"
|
|
92
|
-
],
|
|
93
|
-
"cname": [
|
|
94
|
-
|
|
95
|
-
],
|
|
96
|
-
"soa": [
|
|
97
|
-
"noc.dns.icann.org"
|
|
98
|
-
],
|
|
99
|
-
"mx": [
|
|
100
|
-
|
|
101
|
-
],
|
|
102
|
-
"a": [
|
|
103
|
-
"93.184.216.34"
|
|
104
|
-
],
|
|
105
|
-
"aaaa": [
|
|
106
|
-
"2606:2800:220:1:248:1893:25C8:1946"
|
|
107
|
-
]
|
|
108
125
|
}
|
|
109
126
|
},
|
|
110
127
|
"ssh": {
|
|
@@ -113,84 +130,12 @@ $ apullo check https://example.com
|
|
|
113
130
|
"target": "https://example.com"
|
|
114
131
|
}
|
|
115
132
|
}
|
|
133
|
+
```
|
|
116
134
|
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
"http": {
|
|
120
|
-
"body": {
|
|
121
|
-
"md5": "74ad15c4ab3f67eee1d546e22248931f",
|
|
122
|
-
"mmh3": -330759974,
|
|
123
|
-
"sha1": "c0280893956852b0c07ae4da752ee5d776d248b8",
|
|
124
|
-
"sha256": "28fa3b0beaf188d48b32557fa4df8f0aa451bd10f8e8bb26e919009d2d41b8fb"
|
|
125
|
-
},
|
|
126
|
-
"cert": {
|
|
127
|
-
},
|
|
128
|
-
"favicon": {
|
|
129
|
-
"md5": "ad184c25a1a01d97696dcb59a1ffef74",
|
|
130
|
-
"mmh3": 111036816,
|
|
131
|
-
"sha1": "cb4842a54c3e96408765290cb810793302c17f0b",
|
|
132
|
-
"sha256": "6949c58f841fa21a89e2e2375ae5645e1db62385f89a0218766f2b0a9c490fb8",
|
|
133
|
-
"meta": {
|
|
134
|
-
"url": "https://www.post.japanpost.jp/img/common/touch-icon.png"
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
"domain": {
|
|
139
|
-
"whois": {
|
|
140
|
-
"registrant_contacts": [
|
|
141
|
-
|
|
142
|
-
],
|
|
143
|
-
"admin_contacts": [
|
|
144
|
-
|
|
145
|
-
],
|
|
146
|
-
"technical_contacts": [
|
|
147
|
-
|
|
148
|
-
]
|
|
149
|
-
},
|
|
150
|
-
"dns": {
|
|
151
|
-
"ns": [
|
|
152
|
-
"ns1.bdydns.cn",
|
|
153
|
-
"ns2.bdydns.cn"
|
|
154
|
-
],
|
|
155
|
-
"cname": [
|
|
156
|
-
|
|
157
|
-
],
|
|
158
|
-
"soa": [
|
|
159
|
-
"sa.dudns.com"
|
|
160
|
-
],
|
|
161
|
-
"mx": [
|
|
135
|
+
## Notes
|
|
162
136
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"193.148.69.12"
|
|
166
|
-
],
|
|
167
|
-
"aaaa": [
|
|
168
|
-
|
|
169
|
-
]
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
"ssh": {
|
|
173
|
-
"rsa": {
|
|
174
|
-
"md5": "960bb068dbfb9aa9f9d6899c15844fca",
|
|
175
|
-
"sha1": "d36555028decde1f931b47c90e469fc52e8f364a",
|
|
176
|
-
"sha256": "cf3c7ea7b9442f71423f2253a9c0e448fd0d619e1abc7e519499cd789fac6e74"
|
|
177
|
-
},
|
|
178
|
-
"ecdsa-sha2-nistp256": {
|
|
179
|
-
"md5": "551222e53a38c10817653a723e6caf0c",
|
|
180
|
-
"sha1": "cd6044db29b30d35f32e26e74d66258570cd6527",
|
|
181
|
-
"sha256": "0664dbea7580f9430da6d0ba13e7a4bba0f1efd449c895a6adcc147abc958ce6"
|
|
182
|
-
},
|
|
183
|
-
"ed25519": {
|
|
184
|
-
"md5": "6da2245d9a211731c2d229ea7cce829b",
|
|
185
|
-
"sha1": "d86afd8fca1a052249ef3a0ee26a24f6cc644485",
|
|
186
|
-
"sha256": "7f0d4b642ea2c236eca4018a2dadff3b8a03c37745f9a9f741d9d246a420f358"
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
"meta": {
|
|
190
|
-
"target": "jppost-be.top"
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
```
|
|
137
|
+
- `mmh3` is a 32 bit signed int value of MurmurHash3.
|
|
138
|
+
- Keys of `http.headers` are downcased.
|
|
194
139
|
|
|
195
140
|
## License
|
|
196
141
|
|
data/apullo.gemspec
CHANGED
|
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
25
|
spec.require_paths = ["lib"]
|
|
26
26
|
|
|
27
|
-
spec.add_development_dependency "bundler", "~> 2.
|
|
27
|
+
spec.add_development_dependency "bundler", "~> 2.1"
|
|
28
28
|
spec.add_development_dependency "coveralls", "~> 0.8"
|
|
29
29
|
spec.add_development_dependency "rake", "~> 13.0"
|
|
30
30
|
spec.add_development_dependency "rspec", "~> 3.9"
|
|
@@ -35,10 +35,11 @@ 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", "~>
|
|
38
|
+
spec.add_dependency "oga", "~> 3.0"
|
|
39
|
+
spec.add_dependency "parallel", "~> 1.19"
|
|
39
40
|
spec.add_dependency "public_suffix", "~> 4.0"
|
|
40
41
|
spec.add_dependency "ssh_scan", "~> 0.0"
|
|
41
|
-
spec.add_dependency "thor", "~> 0
|
|
42
|
+
spec.add_dependency "thor", "~> 1.0"
|
|
42
43
|
spec.add_dependency "whois", "~> 5.0"
|
|
43
44
|
spec.add_dependency "whois-parser", "~> 1.2"
|
|
44
45
|
end
|
data/lib/apullo/cli.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "parallel"
|
|
4
5
|
require "thor"
|
|
5
6
|
|
|
6
7
|
module Apullo
|
|
@@ -26,7 +27,7 @@ module Apullo
|
|
|
26
27
|
}
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
Apullo.fingerprints
|
|
30
|
+
Parallel.map(Apullo.fingerprints) do |klass|
|
|
30
31
|
fingerprint = klass.new(target)
|
|
31
32
|
fingerprint.headers = headers if fingerprint.respond_to?(:headers=)
|
|
32
33
|
|
|
@@ -7,6 +7,7 @@ module Apullo
|
|
|
7
7
|
|
|
8
8
|
def initialize(target)
|
|
9
9
|
@target = target
|
|
10
|
+
@results = nil
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def name
|
|
@@ -14,6 +15,23 @@ module Apullo
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def results
|
|
18
|
+
return @results if @results
|
|
19
|
+
|
|
20
|
+
with_error_handling do
|
|
21
|
+
@results ||= build_results
|
|
22
|
+
end
|
|
23
|
+
@results
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def with_error_handling
|
|
29
|
+
yield
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
@results = { error: e.to_s }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build_results
|
|
17
35
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
|
18
36
|
end
|
|
19
37
|
|
|
@@ -15,15 +15,15 @@ module Apullo
|
|
|
15
15
|
Resolv::DNS::Resource::IN::AAAA,
|
|
16
16
|
].freeze
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def build_results
|
|
19
21
|
{
|
|
20
22
|
dns: resources,
|
|
21
23
|
whois: contacts,
|
|
22
24
|
}
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
private
|
|
26
|
-
|
|
27
27
|
def dns
|
|
28
28
|
@dns ||= Resolv::DNS.new
|
|
29
29
|
end
|
|
@@ -10,23 +10,25 @@ module Apullo
|
|
|
10
10
|
attr_writer :headers
|
|
11
11
|
|
|
12
12
|
def initialize(target)
|
|
13
|
-
|
|
13
|
+
super target
|
|
14
|
+
|
|
14
15
|
@headers = {}
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def build_results
|
|
21
|
+
get(target.uri.path)
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
body: body,
|
|
25
|
+
cert: cert,
|
|
26
|
+
favicon: favicon,
|
|
27
|
+
headers: response_headers,
|
|
28
|
+
meta: {
|
|
29
|
+
url: target.url
|
|
28
30
|
}
|
|
29
|
-
|
|
31
|
+
}
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def cert
|
|
@@ -61,7 +63,9 @@ module Apullo
|
|
|
61
63
|
favicon.results
|
|
62
64
|
end
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
def response_headers
|
|
67
|
+
@response_headers || {}
|
|
68
|
+
end
|
|
65
69
|
|
|
66
70
|
def headers
|
|
67
71
|
@headers.compact
|
|
@@ -71,10 +75,18 @@ module Apullo
|
|
|
71
75
|
"#{target.uri.scheme}://#{target.uri.host}:#{target.uri.port}/favicon.ico"
|
|
72
76
|
end
|
|
73
77
|
|
|
78
|
+
def build_doc
|
|
79
|
+
Oga.parse_html(@body)
|
|
80
|
+
rescue ArgumentError, LL::ParserError => _e
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
74
84
|
def favicon_url
|
|
75
85
|
return nil unless @body
|
|
76
86
|
|
|
77
|
-
doc =
|
|
87
|
+
doc = build_doc
|
|
88
|
+
return nil unless doc
|
|
89
|
+
|
|
78
90
|
icon = doc.at_css("link[rel='shortcut icon']") || doc.at_css("link[rel='icon']")
|
|
79
91
|
return default_favicon_url unless icon
|
|
80
92
|
|
|
@@ -101,6 +113,7 @@ module Apullo
|
|
|
101
113
|
else
|
|
102
114
|
@peer_cert = http.peer_cert
|
|
103
115
|
@body = response.body
|
|
116
|
+
@response_headers = response.each_header.to_h
|
|
104
117
|
@path = path
|
|
105
118
|
end
|
|
106
119
|
rescue Errno::ECONNREFUSED, Net::HTTPError, OpenSSL::OpenSSLError, Timeout::Error => _e
|
|
@@ -8,26 +8,30 @@ module Apullo
|
|
|
8
8
|
DEFAULT_OPTIONS = { "timeout" => 3 }.freeze
|
|
9
9
|
DEFAULT_PORT = 22
|
|
10
10
|
|
|
11
|
-
def results
|
|
12
|
-
@results ||= pluck
|
|
13
|
-
end
|
|
14
|
-
|
|
15
11
|
private
|
|
16
12
|
|
|
17
|
-
def
|
|
13
|
+
def build_results
|
|
14
|
+
pluck_fingerprints
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pluck_fingerprints
|
|
18
18
|
result = scan
|
|
19
19
|
keys = result.dig("keys") || []
|
|
20
20
|
keys.map do |cipher, data|
|
|
21
|
+
raw = data.dig("raw")
|
|
21
22
|
fingerprints = data.dig("fingerprints") || []
|
|
22
|
-
|
|
23
|
+
normalized_fingerprints = fingerprints.map do |hash, value|
|
|
23
24
|
[hash, value.delete(":")]
|
|
24
25
|
end.to_h
|
|
25
|
-
[
|
|
26
|
+
[
|
|
27
|
+
cipher,
|
|
28
|
+
{ raw: raw, fingerprints: normalized_fingerprints }
|
|
29
|
+
]
|
|
26
30
|
end.to_h
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
def scan
|
|
30
|
-
return {} unless target.
|
|
34
|
+
return {} unless target.host
|
|
31
35
|
|
|
32
36
|
engine = SSHScan::ScanEngine.new
|
|
33
37
|
dest = "#{target.host}:#{DEFAULT_PORT}"
|
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.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Manabu Niseki
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-12-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '2.
|
|
19
|
+
version: '2.1'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '2.
|
|
26
|
+
version: '2.1'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: coveralls
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -156,14 +156,28 @@ dependencies:
|
|
|
156
156
|
requirements:
|
|
157
157
|
- - "~>"
|
|
158
158
|
- !ruby/object:Gem::Version
|
|
159
|
-
version: '
|
|
159
|
+
version: '3.0'
|
|
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: '
|
|
166
|
+
version: '3.0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: parallel
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - "~>"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '1.19'
|
|
174
|
+
type: :runtime
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - "~>"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '1.19'
|
|
167
181
|
- !ruby/object:Gem::Dependency
|
|
168
182
|
name: public_suffix
|
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -198,14 +212,14 @@ dependencies:
|
|
|
198
212
|
requirements:
|
|
199
213
|
- - "~>"
|
|
200
214
|
- !ruby/object:Gem::Version
|
|
201
|
-
version: '0
|
|
215
|
+
version: '1.0'
|
|
202
216
|
type: :runtime
|
|
203
217
|
prerelease: false
|
|
204
218
|
version_requirements: !ruby/object:Gem::Requirement
|
|
205
219
|
requirements:
|
|
206
220
|
- - "~>"
|
|
207
221
|
- !ruby/object:Gem::Version
|
|
208
|
-
version: '0
|
|
222
|
+
version: '1.0'
|
|
209
223
|
- !ruby/object:Gem::Dependency
|
|
210
224
|
name: whois
|
|
211
225
|
requirement: !ruby/object:Gem::Requirement
|