ruby-nmap 0.6.0 → 0.7.0
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 +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +13 -0
- data/ChangeLog.md +24 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +1 -1
- data/README.md +11 -9
- data/Rakefile +20 -24
- data/gemspec.yml +1 -3
- data/lib/nmap/cpe.rb +2 -0
- data/lib/nmap/cpe/cpe.rb +45 -0
- data/lib/nmap/cpe/url.rb +78 -0
- data/lib/nmap/hop.rb +20 -0
- data/lib/nmap/host.rb +69 -15
- data/lib/nmap/hostname.rb +20 -0
- data/lib/nmap/os.rb +2 -17
- data/lib/nmap/os_class.rb +65 -1
- data/lib/nmap/port.rb +10 -0
- data/lib/nmap/run_stat.rb +20 -0
- data/lib/nmap/scan_task.rb +4 -19
- data/lib/nmap/sequence.rb +6 -18
- data/lib/nmap/service.rb +76 -0
- data/lib/nmap/tcp_sequence.rb +1 -1
- data/lib/nmap/traceroute.rb +67 -0
- data/lib/nmap/uptime.rb +20 -0
- data/lib/nmap/version.rb +1 -1
- data/lib/nmap/xml.rb +134 -17
- data/spec/address_spec.rb +14 -0
- data/spec/cpe/url_spec.rb +99 -0
- data/spec/cpe_examples.rb +11 -0
- data/spec/hop_spec.rb +14 -0
- data/spec/host_spec.rb +138 -55
- data/spec/hostname_spec.rb +15 -0
- data/spec/ip_id_sequence_spec.rb +24 -10
- data/spec/os_class_spec.rb +31 -0
- data/spec/os_match_spec.rb +15 -0
- data/spec/os_spec.rb +23 -20
- data/spec/port_spec.rb +14 -15
- data/spec/run_stat_spec.rb +21 -0
- data/spec/scan.xml +137 -0
- data/spec/scan_spec.rb +28 -0
- data/spec/scan_task_spec.rb +35 -0
- data/spec/scanner_spec.rb +24 -0
- data/spec/scripts_examples.rb +10 -0
- data/spec/sequence_examples.rb +10 -0
- data/spec/service_spec.rb +55 -18
- data/spec/spec_helper.rb +30 -3
- data/spec/status_spec.rb +15 -0
- data/spec/tcp_sequence_spec.rb +32 -19
- data/spec/tcp_ts_sequence_spec.rb +24 -10
- data/spec/traceroute_spec.rb +31 -0
- data/spec/uptime_spec.rb +15 -0
- data/spec/xml_spec.rb +172 -31
- metadata +50 -54
- data/.gemtest +0 -0
- data/spec/helpers/nse.xml +0 -94
- data/spec/helpers/scan.xml +0 -241
- data/spec/helpers/xml.rb +0 -5
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nmap/scanner'
|
3
|
+
|
4
|
+
describe Scanner do
|
5
|
+
describe "#to_s" do
|
6
|
+
let(:name) { 'nmap' }
|
7
|
+
let(:version) { '6.01' }
|
8
|
+
let(:args) { 'nmap -v -sS -sU -A -O -oX spec/scan.xml scanme.nmap.org' }
|
9
|
+
let(:start_time) { Time.new('Sat Jul 20 23:55:27 2013') }
|
10
|
+
|
11
|
+
subject do
|
12
|
+
described_class.new(
|
13
|
+
name,
|
14
|
+
version,
|
15
|
+
args,
|
16
|
+
start_time
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return the scanner command" do
|
21
|
+
subject.to_s.should == "#{name} #{args}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/service_spec.rb
CHANGED
@@ -1,40 +1,77 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require '
|
2
|
+
require 'cpe_examples'
|
3
3
|
|
4
4
|
require 'nmap/xml'
|
5
5
|
require 'nmap/service'
|
6
6
|
|
7
7
|
describe Service do
|
8
|
-
|
8
|
+
subject { @xml.hosts.first.ports.first.service }
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
describe "#name" do
|
11
|
+
it "should parse the name" do
|
12
|
+
subject.name.should == 'ssh'
|
13
|
+
end
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
+
describe "#ssl?" do
|
17
|
+
it "should check the tunnel attribute" do
|
18
|
+
pending "need a service that uses SSL"
|
19
|
+
end
|
20
|
+
end
|
16
21
|
|
17
|
-
|
18
|
-
|
22
|
+
describe "#protocol" do
|
23
|
+
it "should parse the proto attribute" do
|
24
|
+
pending "need a service with the proto attribute"
|
25
|
+
end
|
19
26
|
end
|
20
27
|
|
21
|
-
|
22
|
-
|
28
|
+
describe "#product" do
|
29
|
+
it "should parse the product name attribute" do
|
30
|
+
subject.product.should == 'OpenSSH'
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
|
-
|
26
|
-
|
34
|
+
describe "#version" do
|
35
|
+
it "should parse the version attribute" do
|
36
|
+
subject.version.should == '5.3p1 Debian 3ubuntu7'
|
37
|
+
end
|
27
38
|
end
|
28
39
|
|
29
|
-
|
30
|
-
|
40
|
+
describe "#extra_info" do
|
41
|
+
it "should parse the extrainfo attribute" do
|
42
|
+
subject.extra_info.should == 'protocol 2.0'
|
43
|
+
end
|
44
|
+
end
|
31
45
|
|
32
|
-
|
33
|
-
|
46
|
+
describe "#hostname" do
|
47
|
+
it "should parse the hostname attribute" do
|
48
|
+
pending "need a service with the hostname attribute"
|
34
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#os_type" do
|
53
|
+
it "should parse the ostype attribute" do
|
54
|
+
subject.os_type.should == 'Linux'
|
55
|
+
end
|
56
|
+
end
|
35
57
|
|
36
|
-
|
37
|
-
|
58
|
+
describe "#device_type" do
|
59
|
+
it "should parse the devicetype attribute" do
|
60
|
+
pending "need a service with the devicetype attribute"
|
38
61
|
end
|
39
62
|
end
|
63
|
+
|
64
|
+
describe "#fingerprint_method" do
|
65
|
+
it "should parse the method attribute" do
|
66
|
+
subject.fingerprint_method.should == :probed
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#confidence" do
|
71
|
+
it "should parse the conf attribute" do
|
72
|
+
subject.confidence.should be_between(0,10)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it_should_behave_like "CPE"
|
40
77
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,39 @@
|
|
1
|
-
gem 'rspec', '~> 2.4'
|
2
1
|
require 'rspec'
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start
|
3
4
|
|
4
5
|
require 'nmap/version'
|
5
6
|
require 'nmap/xml'
|
6
7
|
include Nmap
|
7
8
|
|
8
|
-
|
9
|
+
RSpec::Matchers.define :be_between do |min,max|
|
10
|
+
match do |value|
|
11
|
+
(value >= min) && (value <= max)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec::Matchers.define :all_be_between do |min,max|
|
16
|
+
match do |values|
|
17
|
+
values.all? { |value| (value >= min) && (value <= max) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec::Matchers.define :be_one_of do |*values|
|
22
|
+
match do |value|
|
23
|
+
values.include?(value)
|
24
|
+
end
|
25
|
+
|
26
|
+
description { "be one of: #{expected.join(', ')}" }
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec::Matchers.define :all_be_kind_of do |base_class|
|
30
|
+
match do |values|
|
31
|
+
values.all? { |value| value.kind_of?(base_class) }
|
32
|
+
end
|
33
|
+
end
|
9
34
|
|
10
35
|
RSpec.configure do |spec|
|
11
|
-
spec.
|
36
|
+
spec.before(:all) do
|
37
|
+
@xml = XML.new('spec/scan.xml')
|
38
|
+
end
|
12
39
|
end
|
data/spec/status_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nmap/status'
|
3
|
+
|
4
|
+
describe Status do
|
5
|
+
describe "#to_s" do
|
6
|
+
let(:state) { :up }
|
7
|
+
let(:reason) { 'syn-ack' }
|
8
|
+
|
9
|
+
subject { described_class.new(state,reason) }
|
10
|
+
|
11
|
+
it "should return the state" do
|
12
|
+
subject.to_s.should == state.to_s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/tcp_sequence_spec.rb
CHANGED
@@ -1,31 +1,44 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'sequence_examples'
|
3
|
+
|
2
4
|
require 'nmap/tcp_sequence'
|
3
5
|
|
4
6
|
describe TcpSequence do
|
5
|
-
|
6
|
-
|
7
|
-
subject { xml.hosts.first.tcp_sequence }
|
7
|
+
subject { @xml.hosts.first.tcp_sequence }
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
describe "#index" do
|
10
|
+
it "should parse the index" do
|
11
|
+
subject.index.should be > 0
|
12
|
+
end
|
11
13
|
end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
describe "#description" do
|
16
|
+
it "should parse the difficulty description" do
|
17
|
+
subject.difficulty.should == "Good luck!"
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
describe "#to_s" do
|
22
|
+
let(:index_regexp) do
|
23
|
+
/\d+/
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:difficulty_regexp) do
|
27
|
+
/"(Good luck!)"/
|
28
|
+
end
|
20
29
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
let(:values_regexp) do
|
31
|
+
/\[\d+(, \d+){5}\]/
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:regexp) do
|
35
|
+
/^index=#{index_regexp} difficulty=#{difficulty_regexp} values=#{values_regexp}$/
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should contain the description and values" do
|
39
|
+
subject.to_s.should =~ regexp
|
40
|
+
end
|
30
41
|
end
|
42
|
+
|
43
|
+
it_should_behave_like "Sequence"
|
31
44
|
end
|
@@ -1,20 +1,34 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'sequence_examples'
|
3
|
+
|
2
4
|
require 'nmap/tcp_ts_sequence'
|
3
5
|
|
4
6
|
describe TcpTsSequence do
|
5
|
-
|
6
|
-
|
7
|
-
subject { xml.hosts.first.tcp_ts_sequence }
|
7
|
+
subject { @xml.hosts.first.tcp_ts_sequence }
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
describe "#description" do
|
10
|
+
it "should parse the description" do
|
11
|
+
subject.description.should == "1000HZ"
|
12
|
+
end
|
11
13
|
end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
describe "#to_s" do
|
16
|
+
let(:description_regexp) do
|
17
|
+
/"[^"]+"/
|
18
|
+
end
|
16
19
|
|
17
|
-
|
18
|
-
|
20
|
+
let(:values_regexp) do
|
21
|
+
/\[\d+(, \d+){5}\]/
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:regexp) do
|
25
|
+
/^description=#{description_regexp} values=#{values_regexp}$/
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should contain the description and values" do
|
29
|
+
subject.to_s.should =~ regexp
|
30
|
+
end
|
19
31
|
end
|
32
|
+
|
33
|
+
it_should_behave_like "Sequence"
|
20
34
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nmap/traceroute'
|
3
|
+
|
4
|
+
describe Traceroute do
|
5
|
+
subject { @xml.hosts.first.traceroute }
|
6
|
+
|
7
|
+
describe "#port" do
|
8
|
+
subject { super().port }
|
9
|
+
|
10
|
+
it { should be_kind_of(Integer) }
|
11
|
+
it { should be > 0 }
|
12
|
+
it { should be < 65535 }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#protocol" do
|
16
|
+
subject { super().protocol }
|
17
|
+
|
18
|
+
it { should be_kind_of(Symbol) }
|
19
|
+
it { should be_one_of(:tcp, :udp) }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#each" do
|
23
|
+
subject { super().each.first }
|
24
|
+
|
25
|
+
it { should be_kind_of(Hop) }
|
26
|
+
|
27
|
+
its(:addr) { should be_kind_of(String) }
|
28
|
+
its(:ttl) { should be_kind_of(String) }
|
29
|
+
its(:rtt) { should be_kind_of(String) }
|
30
|
+
end
|
31
|
+
end
|
data/spec/uptime_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nmap/uptime'
|
3
|
+
|
4
|
+
describe Uptime do
|
5
|
+
describe "#to_s" do
|
6
|
+
let(:seconds) { 920430 }
|
7
|
+
let(:last_boot) { Time.parse("2013-07-10 08:34:03 -0700") }
|
8
|
+
|
9
|
+
subject { described_class.new(seconds,last_boot) }
|
10
|
+
|
11
|
+
it "should convert the uptipe to a String" do
|
12
|
+
subject.to_s.should == "uptime: #{seconds} (#{last_boot})"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/xml_spec.rb
CHANGED
@@ -2,34 +2,88 @@ require 'spec_helper'
|
|
2
2
|
require 'nmap/xml'
|
3
3
|
|
4
4
|
describe XML do
|
5
|
-
|
5
|
+
let(:path) { File.expand_path('spec/scan.xml') }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
subject { described_class.new(path) }
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
context "when given a Nokogiri::XML::Document" do
|
11
|
+
let(:document) { Nokogiri::XML(File.read(path)) }
|
12
|
+
|
13
|
+
it "should use the document" do
|
14
|
+
described_class.new(document).version.should == subject.version
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when given an IO object" do
|
19
|
+
let(:io) { File.new(path) }
|
20
|
+
|
21
|
+
it "should parse the IO object" do
|
22
|
+
described_class.new(io).version.should == subject.version
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when given a String" do
|
27
|
+
it "should parse the file at the path" do
|
28
|
+
described_class.new(path).version.should == subject.version
|
29
|
+
end
|
30
|
+
end
|
9
31
|
end
|
10
32
|
|
11
|
-
|
12
|
-
|
33
|
+
describe "load" do
|
34
|
+
it "should parse the given text" do
|
35
|
+
subject.version.should == described_class.load(File.read(path)).version
|
36
|
+
end
|
13
37
|
end
|
14
38
|
|
15
|
-
|
16
|
-
|
39
|
+
describe "open" do
|
40
|
+
it "should parse the given file" do
|
41
|
+
subject.version.should == described_class.open(path).version
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should set the path" do
|
45
|
+
subject.path.should == path
|
46
|
+
end
|
17
47
|
end
|
18
48
|
|
19
|
-
|
20
|
-
|
49
|
+
describe "#version" do
|
50
|
+
it "should have a version" do
|
51
|
+
subject.version.should == '1.04'
|
52
|
+
end
|
21
53
|
end
|
22
54
|
|
23
|
-
|
24
|
-
|
55
|
+
describe "#scanner" do
|
56
|
+
it "should parse the scanner version" do
|
57
|
+
subject.scanner.version == '4.68'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should parse the scanner name" do
|
61
|
+
subject.scanner.name.should == 'nmap'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should parse the scanner arguments" do
|
65
|
+
subject.scanner.arguments.should == 'nmap -v -sS -sU -A -O -oX spec/scan.xml scanme.nmap.org'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should parse the scanner start time" do
|
69
|
+
subject.scanner.start_time.should be_kind_of(Time)
|
70
|
+
end
|
25
71
|
end
|
26
72
|
|
27
|
-
|
28
|
-
|
73
|
+
describe "#scan_info" do
|
74
|
+
subject { super().scan_info.first }
|
75
|
+
|
76
|
+
it "should parse the type" do
|
77
|
+
subject.type.should == :syn
|
78
|
+
end
|
29
79
|
|
30
|
-
|
31
|
-
|
32
|
-
|
80
|
+
it "should parse the protocol" do
|
81
|
+
subject.protocol.should == :tcp
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should parse the services" do
|
85
|
+
subject.services.should_not be_empty
|
86
|
+
end
|
33
87
|
end
|
34
88
|
|
35
89
|
it "should parse the verbose level" do
|
@@ -40,31 +94,118 @@ describe XML do
|
|
40
94
|
subject.debugging.should == 0
|
41
95
|
end
|
42
96
|
|
43
|
-
|
44
|
-
|
97
|
+
describe "#each_run_stat" do
|
98
|
+
subject { super().each_run_stat.first }
|
45
99
|
|
46
|
-
|
100
|
+
it "should yield RunStat objects" do
|
101
|
+
subject.should be_kind_of(RunStat)
|
102
|
+
end
|
47
103
|
|
48
|
-
|
49
|
-
|
50
|
-
|
104
|
+
it "should parse the end time" do
|
105
|
+
subject.end_time.should be_kind_of(Time)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should parse the time elapsed" do
|
109
|
+
subject.elapsed.should_not be_nil
|
110
|
+
end
|
51
111
|
|
52
|
-
|
112
|
+
it "should parse the summary" do
|
113
|
+
subject.summary.should_not be_empty
|
114
|
+
end
|
53
115
|
|
54
|
-
|
55
|
-
|
116
|
+
it "should parse the exit status" do
|
117
|
+
subject.exit_status.should be_one_of('success', 'failure')
|
56
118
|
end
|
57
119
|
end
|
58
120
|
|
59
|
-
|
60
|
-
subject.
|
121
|
+
describe "#run_stats" do
|
122
|
+
subject { super().run_stats }
|
123
|
+
|
124
|
+
it { should_not be_empty }
|
125
|
+
it { should all_be_kind_of(RunStat) }
|
61
126
|
end
|
62
127
|
|
63
|
-
|
64
|
-
subject
|
128
|
+
describe "#each_task" do
|
129
|
+
subject { super().each_task.first }
|
130
|
+
|
131
|
+
it "should parse task name" do
|
132
|
+
subject.name.should == 'Ping Scan'
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should parse the start time" do
|
136
|
+
subject.start_time.should be_kind_of(Time)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should parse the end time" do
|
140
|
+
subject.end_time.should be_kind_of(Time)
|
141
|
+
subject.end_time.should > subject.start_time
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should parse the extrainfo" do
|
145
|
+
subject.extrainfo.should_not be_empty
|
146
|
+
end
|
65
147
|
end
|
66
148
|
|
67
|
-
|
68
|
-
subject.
|
149
|
+
describe "#tasks" do
|
150
|
+
subject { super().tasks }
|
151
|
+
|
152
|
+
it { should_not be_empty }
|
153
|
+
it { should all_be_kind_of(ScanTask) }
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#each_host" do
|
157
|
+
subject { super().each_host.first }
|
158
|
+
|
159
|
+
it "should yield Host objects" do
|
160
|
+
subject.should be_kind_of(Host)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "#hosts" do
|
165
|
+
subject { super().hosts }
|
166
|
+
|
167
|
+
it { should_not be_empty }
|
168
|
+
it { subject.should all_be_kind_of(Host) }
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "#each_up_host" do
|
172
|
+
subject { super().each_up_host.first }
|
173
|
+
|
174
|
+
it "should yield Host objects" do
|
175
|
+
subject.should be_kind_of(Host)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should be up" do
|
179
|
+
subject.status.state.should be == :up
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "#up_hosts" do
|
184
|
+
subject { super().up_hosts }
|
185
|
+
|
186
|
+
it { should_not be_empty }
|
187
|
+
it { should all_be_kind_of(Host) }
|
188
|
+
|
189
|
+
it "should contain only up hosts" do
|
190
|
+
subject.all? { |host| host.status.state == :up }.should be_true
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#each" do
|
195
|
+
it "should iterate over each up host" do
|
196
|
+
subject.each.all? { |host| host.status.state == :up }.should == true
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#to_s" do
|
201
|
+
it "should convert to a String" do
|
202
|
+
subject.to_s.should == path
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "#inspect" do
|
207
|
+
it "should include the class and path" do
|
208
|
+
subject.inspect.should == "#<#{described_class}: #{path}>"
|
209
|
+
end
|
69
210
|
end
|
70
211
|
end
|