librex 0.0.32 → 0.0.33

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.
@@ -3,7 +3,7 @@
3
3
  A non-official re-packaging of the Rex library as a gem for easy of usage of the Metasploit REX framework in a non Metasploit application. I received permission from HDM to create this package.
4
4
 
5
5
  Currently based on:
6
- SVN Revision: 12612
6
+ SVN Revision: 12724
7
7
 
8
8
  # Credits
9
9
  The Metasploit development team <http://www.metasploit.com>
@@ -20,6 +20,7 @@ module Exploitation
20
20
  # Checksum code merged to Egghunter by jduck
21
21
  # Conversion to use Metasm by jduck
22
22
  # Startreg code added by corelanc0d3r
23
+ # Added routine to disable DEP for discovered egg (for win, added by corelanc0d3r)
23
24
  #
24
25
  ###
25
26
  class Egghunter
@@ -57,7 +58,95 @@ class Egghunter
57
58
  end
58
59
  startstub << "\n\t" if startstub.length > 0
59
60
 
61
+ getpointer = ''
62
+ getsize = ''
63
+ getpc = ''
64
+ jmppayload = "jmp edi"
65
+
66
+ apireg = (opts[:depreg] || 'esi').downcase
67
+ apidest = opts[:depdest]
68
+ depsize = opts[:depsize]
69
+
70
+ freeregs = [ "esi", "ebp", "ecx", "ebx" ]
71
+
72
+ if opts[:depmethod]
73
+
74
+ if freeregs.index(apireg) == nil
75
+ getpointer << "mov #{freeregs[0]},#{apireg}\n\t"
76
+ apireg = freeregs[0]
77
+ end
78
+ freeregs.delete(apireg)
79
+
80
+ if opts[:depmethod].downcase == "copy" || opts[:depmethod].downcase == "copy_size"
81
+ if apidest
82
+ if freeregs.index(apidest) == nil
83
+ getpointer << "mov #{freeregs[0]},#{apidest}\n\t"
84
+ apidest = freeregs[0]
85
+ end
86
+ else
87
+ getpc = "fldpi\n\tfstenv [esp-0xc]\n\tpop #{freeregs[0]}\n\t"
88
+ apidest = freeregs[0]
89
+ end
90
+ freeregs.delete(apidest)
91
+ end
92
+
93
+
94
+ sizereg = freeregs[0]
95
+
96
+ if not depsize
97
+ depsize = payload.length * 2
98
+ if opts[:depmethod]
99
+ if opts[:depmethod].downcase == "copy_size"
100
+ depsize = payload.length
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+ blockcnt = 0
107
+ vpsize = 0
108
+ blocksize = depsize
109
+ while blocksize >= 127
110
+ blocksize = blocksize / 2
111
+ blockcnt += 1
112
+ end
113
+ if blockcnt > 0
114
+ getsize << "xor #{sizereg},#{sizereg}\n\tadd #{sizereg},0x%02x\n\t" % blocksize
115
+ vpsize = blocksize
116
+ depblockcnt = 0
117
+ while depblockcnt < blockcnt
118
+ getsize << "add #{sizereg},#{sizereg}\n\t"
119
+ vpsize += vpsize
120
+ depblockcnt += 1
121
+ end
122
+ delta = depsize - vpsize
123
+ if delta > 0
124
+ getsize << "add #{sizereg},0x%02x\n\t" % delta
125
+ end
126
+ else
127
+ getsize << "xor #{sizereg},#{sizereg}\n\tadd #{sizereg},0x%02x\n\t" % depsize
128
+ end
129
+
130
+
131
+ case opts[:depmethod].downcase
132
+ when "virtualprotect"
133
+ jmppayload = "push esp\n\tpush 0x40\n\t"
134
+ jmppayload << getsize
135
+ jmppayload << "push #{sizereg}\n\tpush edi\n\tpush edi\n\tpush #{apireg}\n\tret"
136
+ when "copy"
137
+ jmppayload = getpc
138
+ jmppayload << "push edi\n\tpush #{apidest}\n\tpush #{apidest}\n\tpush #{apireg}\n\tmov edi,#{apidest}\n\tret"
139
+ when "copy_size"
140
+ jmppayload = getpc
141
+ jmppayload << getsize
142
+ jmppayload << "push #{sizereg}\n\tpush edi\n\tpush #{apidest}\n\tpush #{apidest}\n\tpush #{apireg}\n\tmov edi,#{apidest}\n\tret"
143
+ end
144
+ end
145
+
146
+ jmppayload << "\n" if jmppayload.length > 0
147
+
60
148
  assembly = <<EOS
149
+ #{getpointer}
61
150
  #{startstub}
62
151
  check_readable:
63
152
  or dx,0xfff
@@ -84,7 +173,7 @@ check_for_tag:
84
173
  #{checksum}
85
174
 
86
175
  ; jump to the payload
87
- jmp edi
176
+ #{jmppayload}
88
177
  EOS
89
178
 
90
179
  assembled_code = Metasm::Shellcode.assemble(Metasm::Ia32.new, assembly).encode_string
@@ -636,6 +636,12 @@ function getVersion(){
636
636
  os_flavor = "XP";
637
637
  os_sp = "SP3";
638
638
  break;
639
+ case "576000":
640
+ // IE 7.0.6000.16386, Vista Ultimate SP0 English
641
+ ua_version = "7.0";
642
+ os_flavor = "Vista";
643
+ os_sp = "SP0";
644
+ break;
639
645
  case "5822960":
640
646
  // IE 8.0.6001.18702, XP Professional SP3 Greek
641
647
  case "5818702":
@@ -650,6 +656,8 @@ function getVersion(){
650
656
  case "5816385":
651
657
  // IE 8.0.7600.16385, Windows 7 English
652
658
  case "5816475":
659
+ case "5816762":
660
+ // IE 8.0.7600.16385, Windows 7 English
653
661
  ua_version = "8.0";
654
662
  os_flavor = "7";
655
663
  os_sp = "SP0";
@@ -816,7 +824,7 @@ function ua_ver_cmp(ver_a, ver_b) {
816
824
 
817
825
  a = ver_a.split(".");
818
826
  b = ver_b.split(".");
819
- for (i = 0; i < Math.max(a.length, b.length); i++) {
827
+ for (var i = 0; i < Math.max(a.length, b.length); i++) {
820
828
  // 3.0 == 3
821
829
  if (!b[i]) { b[i] = "0"; }
822
830
  if (!a[i]) { a[i] = "0"; }
@@ -0,0 +1,134 @@
1
+
2
+ $:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
3
+
4
+ require 'test/unit'
5
+ require 'rex/socket'
6
+ require 'rex/io/ring_buffer'
7
+
8
+ #
9
+ # TODO: Mock up the socket so this test doesn't take so long
10
+ #
11
+ class Rex::IO::RingBuffer::UnitTest < Test::Unit::TestCase
12
+
13
+ def setup
14
+ server = Rex::Socket.create_tcp_server('LocalPort' => 0)
15
+ lport = server.getsockname[2]
16
+ @client = Rex::Socket.create_tcp('PeerHost' => '127.0.0.1', 'PeerPort' => lport)
17
+ conn = server.accept
18
+ #server.close
19
+
20
+ @r = Rex::IO::RingBuffer.new(conn, {:size => 64})
21
+ @r.start_monitor
22
+ end
23
+
24
+ def teardown
25
+ begin
26
+ @client.close
27
+ @r.stop_monitor
28
+ rescue ::Exception
29
+ end
30
+ end
31
+
32
+ def test_single_read_data
33
+ @client.put("123")
34
+ @r.wait(0)
35
+ s,d = @r.read_data
36
+
37
+ assert_equal("123", d)
38
+ end
39
+
40
+ def test_sequential_read_data
41
+ @r.clear_data
42
+
43
+ s = nil
44
+ 0.upto(10) do |num|
45
+ @client.put(num.to_s)
46
+ @r.wait(s)
47
+ s,d = @r.read_data(s)
48
+ assert_equal(num.to_s, d)
49
+ end
50
+ end
51
+
52
+ def test_wrap
53
+ @r.clear_data
54
+ 0.upto(@r.size - 1) {
55
+ @client.put("a")
56
+ # Need to sleep so the socket doesn't get all the data in one read()
57
+ sleep 0.05
58
+ }
59
+ s,d = @r.read_data
60
+
61
+ @client.put("b")
62
+ sleep 0.01
63
+ s,d = @r.read_data(s)
64
+
65
+ assert_equal("b", d)
66
+
67
+ end
68
+
69
+ end
70
+ =begin
71
+ client.put("4")
72
+ client.put("5")
73
+ client.put("6")
74
+ s,d = r.read_data(s)
75
+
76
+ client.put("7")
77
+ client.put("8")
78
+ client.put("9")
79
+ s,d = r.read_data(s)
80
+
81
+ client.put("0")
82
+ s,d = r.read_data(s)
83
+
84
+ test_counter = 11
85
+ 1.upto(100) do
86
+ client.put( "X" )
87
+ test_counter += 1
88
+ end
89
+
90
+ sleep(1)
91
+
92
+ s,d = r.read_data
93
+ p s
94
+ p d
95
+
96
+ fdata = ''
97
+ File.open("/bin/ls", "rb") do |fd|
98
+ fdata = fd.read(fd.stat.size)
99
+ fdata = fdata * 10
100
+ client.put(fdata)
101
+ end
102
+
103
+ sleep(1)
104
+
105
+ s,vdata = r.read_data(s)
106
+
107
+ if vdata != fdata
108
+ puts "DATA FAILED"
109
+ else
110
+ puts "DATA VERIFIED"
111
+ end
112
+
113
+ r.clear_data
114
+
115
+ a = r.create_stream
116
+ b = r.create_stream
117
+
118
+ client.put("ABC123")
119
+ sleep(1)
120
+
121
+ p a.read
122
+ p b.read
123
+
124
+ client.put("$$$$$$")
125
+ sleep(1)
126
+
127
+ p a.read
128
+ p b.read
129
+
130
+ c = r.create_stream
131
+ p c.read
132
+
133
+ end
134
+ =end
@@ -1,3 +1,5 @@
1
+ require 'thread'
2
+
1
3
  module Rex
2
4
  module IO
3
5
 
@@ -61,6 +63,7 @@ module StreamServer
61
63
  #
62
64
  def start
63
65
  self.clients = []
66
+ self.client_waiter = ::Queue.new
64
67
 
65
68
  self.listener_thread = Rex::ThreadFactory.spawn("StreamServerListener", false) {
66
69
  monitor_listener
@@ -128,6 +131,7 @@ module StreamServer
128
131
 
129
132
  attr_accessor :clients # :nodoc:
130
133
  attr_accessor :listener_thread, :clients_thread # :nodoc:
134
+ attr_accessor :client_waiter
131
135
 
132
136
  protected
133
137
 
@@ -151,6 +155,9 @@ protected
151
155
 
152
156
  # Initialize the connection processing
153
157
  on_client_connect(cli)
158
+
159
+ # Notify the client monitor
160
+ self.client_waiter.push(cli)
154
161
 
155
162
  # Skip exceptions caused by accept() [ SSL ]
156
163
  rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
@@ -170,12 +177,14 @@ protected
170
177
  #
171
178
  def monitor_clients
172
179
  begin
180
+
181
+ # Wait for a notify if our client list is empty
173
182
  if (clients.length == 0)
174
- Rex::ThreadSafe::sleep(0.25)
183
+ self.client_waiter.pop
175
184
  next
176
185
  end
177
186
 
178
- sd = Rex::ThreadSafe.select(clients)
187
+ sd = Rex::ThreadSafe.select(clients, nil, nil, nil)
179
188
 
180
189
  sd[0].each { |cfd|
181
190
  begin
@@ -17,7 +17,8 @@ class NessusXMLStreamParser
17
17
  def reset_state
18
18
  @host = {'hname' => nil, 'addr' => nil, 'mac' => nil, 'os' => nil, 'ports' => [
19
19
  'port' => {'port' => nil, 'svc_name' => nil, 'proto' => nil, 'severity' => nil,
20
- 'nasl' => nil, 'description' => nil, 'cve' => [], 'bid' => [], 'xref' => [], 'msf' => nil } ] }
20
+ 'nasl' => nil, 'nasl_name' => nil, 'description' => nil,
21
+ 'cve' => [], 'bid' => [], 'xref' => [], 'msf' => nil } ] }
21
22
  @state = :generic_state
22
23
  end
23
24
 
@@ -46,7 +47,8 @@ class NessusXMLStreamParser
46
47
  @bid = Array.new
47
48
  @xref = Array.new
48
49
  @x = Hash.new
49
- @x['nasl'] = [attributes['pluginID'],attributes['pluginName']].join(" ")
50
+ @x['nasl'] = attributes['pluginID']
51
+ @x['nasl_name'] = attributes['pluginName']
50
52
  @x['port'] = attributes['port']
51
53
  @x['proto'] = attributes['protocol']
52
54
  @x['svc_name'] = attributes['svc_name']
@@ -13,8 +13,16 @@ class NexposeXMLStreamParser
13
13
 
14
14
  def reset_state
15
15
  @state = :generic_state
16
- @host = { "status" => nil, "endpoints" => [], "names" => [], "vulns" => {} }
17
- @vuln = { "refs" => [] }
16
+ @only_vuln_states_needed = true
17
+ @current_vuln_id = nil
18
+ @vulnerable_markers = ['vulnerable-exploited', 'vulnerable-version', 'potential']
19
+ @host = {"status" => nil, "endpoints" => [], "names" => [], "vulns" => {}}
20
+ @vuln = {"refs" => [], "description" => [], "solution" => []}
21
+ end
22
+
23
+ # If all vuln states are required set this to false
24
+ def parse_vulnerable_states_only only_vuln_states_needed
25
+ @only_vuln_states_needed = only_vuln_states_needed
18
26
  end
19
27
 
20
28
  def tag_start(name, attributes)
@@ -48,19 +56,31 @@ class NexposeXMLStreamParser
48
56
  if @state == :in_service
49
57
  @host["endpoints"].last.merge!(attributes)
50
58
  end
51
- when "test"
52
- if attributes["status"] == "vulnerable-exploited" or attributes["status"] == "vulnerable-version"
53
- @host["vulns"][attributes["id"]] = attributes.dup
54
- if attributes["key"]
55
- @host["notes"] ||= []
56
- @host["notes"] << [attributes["id"], attributes["key"]]
59
+ when "test"
60
+ if (not @only_vuln_states_needed) or (@vulnerable_markers.include? attributes["status"].to_s.chomp and @only_vuln_states_needed)
61
+ @state = :in_test
62
+ @current_vuln_id = attributes["id"]
63
+ @host["vulns"][@current_vuln_id] = attributes.dup
64
+ # Append the endpoint info for how the vuln was discovered
65
+ unless @host["endpoints"].empty?
66
+ @host["vulns"][@current_vuln_id].merge!("endpoint_data" => @host["endpoints"].last)
67
+ end
68
+ if attributes["key"]
69
+ @host["notes"] ||= []
70
+ @host["notes"] << [@current_vuln_id, attributes["key"]]
71
+ end
57
72
  end
58
- end
59
- when "vulnerability"
60
- @vuln.merge! attributes
61
- when "reference"
62
- @state = :in_reference
63
- @vuln["refs"].push attributes
73
+ when "vulnerability"
74
+ @vuln.merge! attributes
75
+ when "reference"
76
+ @state = :in_reference
77
+ @vuln["refs"].push attributes
78
+ when "solution"
79
+ @state = :in_solution
80
+ when "description"
81
+ @state = :in_description
82
+ when "URLLink"
83
+ @vuln["solution"] << attributes
64
84
  end
65
85
  end
66
86
 
@@ -70,7 +90,17 @@ class NexposeXMLStreamParser
70
90
  @host["names"].push str
71
91
  when :in_reference
72
92
  @vuln["refs"].last["value"] = str
73
- end
93
+ when :in_solution
94
+ @vuln["solution"] << str
95
+ when :in_description
96
+ @vuln["description"] << str
97
+ when :in_test
98
+ if @host["vulns"][@current_vuln_id]
99
+ proof = @host["vulns"][@current_vuln_id]["proof"] || []
100
+ proof << str
101
+ @host["vulns"][@current_vuln_id]["proof"] = proof
102
+ end
103
+ end
74
104
  end
75
105
 
76
106
  def tag_end(name)
@@ -0,0 +1,385 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)),"nokogiri_doc_mixin")
2
+
3
+ module Rex
4
+ module Parser
5
+
6
+ # If Nokogiri is available, define Nmap document class.
7
+ load_nokogiri && class NmapDocument < Nokogiri::XML::SAX::Document
8
+
9
+ include NokogiriDocMixin
10
+
11
+ def determine_port_state(v)
12
+ case v
13
+ when "open"
14
+ Msf::ServiceState::Open
15
+ when "closed"
16
+ Msf::ServiceState::Closed
17
+ when "filtered"
18
+ Msf::ServiceState::Filtered
19
+ when "unknown"
20
+ Msf::ServiceState::Unknown
21
+ end
22
+ end
23
+
24
+ # Compare OS fingerprinting data
25
+ def better_os_match(orig_hash,new_hash)
26
+ return false unless new_hash.has_key? "accuracy"
27
+ return true unless orig_hash.has_key? "accuracy"
28
+ new_hash["accuracy"].to_i > orig_hash["accuracy"].to_i
29
+ end
30
+
31
+ # Triggered every time a new element is encountered. We keep state
32
+ # ourselves with the @state variable, turning things on when we
33
+ # get here (and turning things off when we exit in end_element()).
34
+ def start_element(name=nil,attrs=[])
35
+ attrs = normalize_attrs(attrs)
36
+ block = @block
37
+ @state[:current_tag][name] = true
38
+ case name
39
+ when "host"
40
+ @state[:in_host] = true
41
+ when "os"
42
+ if @state[:in_host]
43
+ @state[:in_os] = true
44
+ end
45
+ when "status"
46
+ record_host_status(attrs)
47
+ when "address"
48
+ record_address(attrs)
49
+ when "osclass"
50
+ record_host_osclass(attrs)
51
+ when "osmatch"
52
+ record_host_osmatch(attrs)
53
+ when "uptime"
54
+ record_host_uptime(attrs)
55
+ when "hostname"
56
+ record_hostname(attrs)
57
+ when "port"
58
+ record_port(attrs)
59
+ when "state"
60
+ record_port_state(attrs)
61
+ when "service"
62
+ record_port_service(attrs)
63
+ when "script" # Not actually used in import?
64
+ record_port_script(attrs)
65
+ record_host_script(attrs)
66
+ # Ignoring post scripts completely
67
+ when "trace"
68
+ record_host_trace(attrs)
69
+ when "hop"
70
+ record_host_hop(attrs)
71
+ end
72
+ end
73
+
74
+ # We can certainly get fancier with self.send() magic, but
75
+ # leaving this pretty simple for now.
76
+
77
+ def record_host_hop(attrs)
78
+ return unless @state[:in_host]
79
+ return unless @state[:in_trace]
80
+ hops = attr_hash(attrs)
81
+ hops["name"] = hops.delete "host"
82
+ @state[:trace][:hops] << hops
83
+ end
84
+
85
+ def record_host_trace(attrs)
86
+ return unless @state[:in_host]
87
+ @state[:in_trace] = true
88
+ @state[:trace] = attr_hash(attrs)
89
+ @state[:trace][:hops] = []
90
+ end
91
+
92
+ def record_host_uptime(attrs)
93
+ return unless @state[:in_host]
94
+ @state[:uptime] = attr_hash(attrs)
95
+ end
96
+
97
+ def record_host_osmatch(attrs)
98
+ return unless @state[:in_host]
99
+ return unless @state[:in_os]
100
+ temp_hash = attr_hash(attrs)
101
+ if temp_hash["accuracy"].to_i == 100
102
+ @state[:os]["osmatch"] = temp_hash["name"]
103
+ end
104
+ end
105
+
106
+ def record_host_osclass(attrs)
107
+ return unless @state[:in_host]
108
+ return unless @state[:in_os]
109
+ @state[:os] ||= {}
110
+ temp_hash = attr_hash(attrs)
111
+ if better_os_match(@state[:os],temp_hash)
112
+ @state[:os] = temp_hash
113
+ end
114
+ end
115
+
116
+ def record_hostname(attrs)
117
+ return unless @state[:in_host]
118
+ if attr_hash(attrs)["type"] == "PTR"
119
+ @state[:hostname] = attr_hash(attrs)["name"]
120
+ end
121
+ end
122
+
123
+ def record_host_script(attrs)
124
+ return unless @state[:in_host]
125
+ return if @state[:in_port]
126
+ temp_hash = attr_hash(attrs)
127
+ @state[:hostscripts] ||= {}
128
+ @state[:hostscripts].merge! temp_hash
129
+ temp_hash[:addresses] = @state[:addresses]
130
+ db.emit(:host_script,temp_hash,&block) if block
131
+ end
132
+
133
+ def record_port_script(attrs)
134
+ return unless @state[:in_host]
135
+ return unless @state[:in_port]
136
+ temp_hash = attr_hash(attrs)
137
+ @state[:portscripts] ||= {}
138
+ @state[:portscripts].merge! temp_hash
139
+ temp_hash[:addresses] = @state[:addresses]
140
+ temp_hash[:port] = @state[:port]
141
+ db.emit(:port_script,temp_hash,&block) if block
142
+ end
143
+
144
+ def record_port_service(attrs)
145
+ return unless @state[:in_host]
146
+ return unless @state[:in_port]
147
+ svc = attr_hash(attrs)
148
+ if svc["name"] && @args[:fix_services]
149
+ svc["name"] = db.nmap_msf_service_map(svc["name"])
150
+ end
151
+ @state[:port] = @state[:port].merge(svc)
152
+ end
153
+
154
+ def record_port_state(attrs)
155
+ return unless @state[:in_host]
156
+ return unless @state[:in_port]
157
+ temp_hash = attr_hash(attrs)
158
+ @state[:port] = @state[:port].merge(temp_hash)
159
+ end
160
+
161
+ def record_port(attrs)
162
+ return unless @state[:in_host]
163
+ @state[:in_port] = true
164
+ @state[:port] ||= {}
165
+ svc = attr_hash(attrs)
166
+ @state[:port] = @state[:port].merge(svc)
167
+ end
168
+
169
+ def record_host_status(attrs)
170
+ return unless @state[:in_host]
171
+ attrs.each do |k,v|
172
+ next unless k == "state"
173
+ @state[:host_alive] = (v == "up")
174
+ end
175
+ end
176
+
177
+ def record_address(attrs)
178
+ return unless @state[:in_host]
179
+ @state[:addresses] ||= {}
180
+ address = nil
181
+ type = nil
182
+ attrs.each do |k,v|
183
+ if k == "addr"
184
+ address = v
185
+ elsif k == "addrtype"
186
+ type = v
187
+ end
188
+ end
189
+ @state[:addresses][type] = address
190
+ end
191
+
192
+ # When we exit a tag, this is triggered.
193
+ def end_element(name=nil)
194
+ block = @block
195
+ @state[:current_tag].delete name
196
+ case name
197
+ when "os"
198
+ collect_os_data
199
+ @state[:in_os] = false
200
+ @state[:os] = {}
201
+ when "port"
202
+ collect_port_data
203
+ @state[:in_port] = false
204
+ @state[:port] = {}
205
+ when "script"
206
+ if @state[:in_host]
207
+ if @state[:in_port]
208
+ @state[:portscripts] = {}
209
+ else
210
+ @state[:hostscripts] = {}
211
+ end
212
+ end
213
+ when "trace"
214
+ @state[:in_trace] = false
215
+ when "host" # Roll everything up now
216
+ collect_host_data
217
+ host_object = report_host &block
218
+ if host_object
219
+ db.report_import_note(@args[:wspace],host_object)
220
+ report_services(host_object,&block)
221
+ report_fingerprint(host_object)
222
+ report_uptime(host_object)
223
+ report_traceroute(host_object)
224
+ end
225
+ @state.delete_if {|k| k != :current_tag}
226
+ end
227
+ end
228
+
229
+ def end_document
230
+ block = @block
231
+ unless @state[:current_tag].empty?
232
+ missing_ends = @state[:current_tag].keys.map {|x| "'#{x}'"}.join(", ")
233
+ msg = "Warning, the provided file is incomplete, and there may be missing\n"
234
+ msg << "data. The following tags were not closed: #{missing_ends}."
235
+ db.emit(:warning,msg,&block)
236
+ end
237
+ end
238
+
239
+ def collect_os_data
240
+ return unless @state[:in_host]
241
+ if @state[:os]
242
+ @report_data[:os_fingerprint] = {
243
+ :type => "host.os.nmap_fingerprint",
244
+ :data => {
245
+ :os_vendor => @state[:os]["vendor"],
246
+ :os_family => @state[:os]["osfamily"],
247
+ :os_version => @state[:os]["osgen"],
248
+ :os_accuracy => @state[:os]["accuracy"].to_i
249
+ }
250
+ }
251
+ if @state[:os].has_key? "osmatch"
252
+ @report_data[:os_fingerprint][:data][:os_match] = @state[:os]["osmatch"]
253
+ end
254
+ end
255
+ end
256
+
257
+ def collect_host_data
258
+ if @state[:host_alive]
259
+ @report_data[:state] = Msf::HostState::Alive
260
+ else
261
+ @report_data[:state] = Msf::HostState::Dead
262
+ end
263
+ if @state[:addresses]
264
+ if @state[:addresses].has_key? "ipv4"
265
+ @report_data[:host] = @state[:addresses]["ipv4"]
266
+ elsif @state[:addresses].has_key? "ipv6"
267
+ @report_data[:host] = @state[:addresses]["ipv6"]
268
+ end
269
+ end
270
+ if @state[:addresses] and @state[:addresses].has_key?("mac")
271
+ @report_data[:mac] = @state[:addresses]["mac"]
272
+ end
273
+ if @state[:hostname]
274
+ @report_data[:name] = @state[:hostname]
275
+ end
276
+ if @state[:uptime]
277
+ @report_data[:last_boot] = @state[:uptime]["lastboot"]
278
+ end
279
+ if @state[:trace] and @state[:trace].has_key?(:hops)
280
+ @report_data[:traceroute] = @state[:trace]
281
+ end
282
+ end
283
+
284
+ def collect_port_data(&block)
285
+ return unless @state[:in_host]
286
+ if @args[:fix_services]
287
+ if @state[:port]["state"] == "filtered"
288
+ return
289
+ end
290
+ end
291
+ @report_data[:ports] ||= []
292
+ port_hash = {}
293
+ extra = []
294
+ @state[:port].each do |k,v|
295
+ case k
296
+ when "protocol"
297
+ port_hash[:protocol] = v
298
+ when "portid"
299
+ port_hash[:port] = v
300
+ when "state"
301
+ port_hash[:state] = determine_port_state(v)
302
+ when "name"
303
+ port_hash[:name] = v
304
+ when "reason"
305
+ port_hash[:reason] = v
306
+ when "product"
307
+ extra[0] = v
308
+ when "version"
309
+ extra[1] = v
310
+ when "extrainfo"
311
+ extra[2] = v
312
+ end
313
+ end
314
+ port_hash[:info] = extra.compact.join(" ") unless extra.empty?
315
+ # Skip localhost port results when they're unknown
316
+ if( port_hash[:reason] == "localhost-response" &&
317
+ port_hash[:state] == Msf::ServiceState::Unknown )
318
+ @report_data[:ports]
319
+ else
320
+ @report_data[:ports] << port_hash
321
+ end
322
+ end
323
+
324
+ def report_traceroute(host_object)
325
+ return unless host_object.kind_of? ::Msf::DBManager::Host
326
+ return unless @report_data[:traceroute]
327
+ db.report_note(
328
+ :workspace => host_object.workspace,
329
+ :host => host_object,
330
+ :type => "host.nmap.traceroute",
331
+ :data => {
332
+ 'port' => @report_data[:traceroute]["port"].to_i,
333
+ 'proto' => @report_data[:traceroute]["proto"].to_s,
334
+ 'hops' => @report_data[:traceroute][:hops]
335
+ }
336
+ )
337
+ end
338
+
339
+ def report_uptime(host_object)
340
+ return unless host_object.kind_of? ::Msf::DBManager::Host
341
+ return unless @report_data[:last_boot]
342
+ db.report_note(
343
+ :workspace => host_object.workspace,
344
+ :host => host_object,
345
+ :type => "host.last_boot",
346
+ :data => { :time => @report_data[:last_boot] }
347
+ )
348
+ end
349
+
350
+ def report_fingerprint(host_object)
351
+ return unless host_object.kind_of? ::Msf::DBManager::Host
352
+ return unless @report_data[:os_fingerprint]
353
+ db.report_note(
354
+ @report_data[:os_fingerprint].merge(
355
+ :workspace => host_object.workspace,
356
+ :host => host_object
357
+ )
358
+ )
359
+ end
360
+
361
+ def report_host(&block)
362
+ if host_is_okay
363
+ host_object = db.report_host( @report_data.merge(
364
+ :workspace => @args[:wspace] ) )
365
+ db.emit(:address,@report_data[:host],&block) if block
366
+ host_object
367
+ end
368
+ end
369
+
370
+ def report_services(host_object,&block)
371
+ return unless host_object.kind_of? ::Msf::DBManager::Host
372
+ return unless @report_data[:ports]
373
+ return if @report_data[:ports].empty?
374
+ reported = []
375
+ @report_data[:ports].each do |svc|
376
+ reported << db.report_service(svc.merge(:host => host_object))
377
+ end
378
+ reported
379
+ end
380
+
381
+ end
382
+
383
+ end
384
+ end
385
+