Skip to content
This repository
Browse code

Merge branch 'release/20111219000001' into stable

  • Loading branch information...
commit 14270fe49fabf7511eed3e593ab93a6d2af5e9e8 2 parents 4259168 + ed4c6de
Jonathan Cran authored December 27, 2011
1  lib/rex/proto/tftp.rb
@@ -10,3 +10,4 @@
10 10
 
11 11
 require 'rex/proto/tftp/constants'
12 12
 require 'rex/proto/tftp/server'
  13
+require 'rex/proto/tftp/client'
343  lib/rex/proto/tftp/client.rb
... ...
@@ -0,0 +1,343 @@
  1
+require 'rex/socket'
  2
+require 'rex/proto/tftp'
  3
+require 'tempfile'
  4
+
  5
+module Rex
  6
+module Proto
  7
+module TFTP
  8
+
  9
+#
  10
+# TFTP Client class
  11
+#
  12
+# Note that TFTP has blocks, and so does Ruby. Watch out with the variable names!
  13
+#
  14
+# The big gotcha right now is that setting the mode between octet, netascii, or
  15
+# anything else doesn't actually do anything other than declare it to the
  16
+# server.
  17
+#
  18
+# Also, since TFTP clients act as both clients and servers, we use two
  19
+# threads to handle transfers, regardless of the direction. For this reason,
  20
+# the transfer actions are nonblocking; if you need to see the
  21
+# results of a transfer before doing something else, check the boolean complete
  22
+# attribute and any return data in the :status attribute. It's a little
  23
+# weird like that.
  24
+#
  25
+# Finally, most (all?) clients will alter the data in netascii mode in order
  26
+# to try to conform to the RFC standard for what "netascii" means, but there are
  27
+# ambiguities in implementations on things like if nulls are allowed, what
  28
+# to do with Unicode, and all that. For this reason, "octet" is default, and
  29
+# if you want to send "netascii" data, it's on you to fix up your source data
  30
+# prior to sending it.
  31
+#
  32
+class Client
  33
+
  34
+	attr_accessor :local_host, :local_port, :peer_host, :peer_port
  35
+	attr_accessor :threads, :context, :server_sock, :client_sock
  36
+	attr_accessor :local_file, :remote_file, :mode, :action
  37
+	attr_accessor :complete, :recv_tempfile, :status
  38
+	attr_accessor :block_size # This definitely breaks spec, should only use for fuzz/sploit.
  39
+
  40
+	# Returns an array of [code, type, msg]. Data packets
  41
+	# specifically will /not/ unpack, since that would drop any trailing spaces or nulls.
  42
+	def parse_tftp_response(str)
  43
+		return nil unless str.length >= 4
  44
+		ret = str.unpack("nnA*")
  45
+		ret[2] = str[4,str.size] if ret[0] == OpData
  46
+		return ret
  47
+	end
  48
+
  49
+	def initialize(params)
  50
+		self.threads = []
  51
+		self.local_host = params["LocalHost"] || "0.0.0.0"
  52
+		self.local_port = params["LocalPort"] || (1025 + rand(0xffff-1025))
  53
+		self.peer_host = params["PeerHost"] || (raise ArgumentError, "Need a peer host.")
  54
+		self.peer_port = params["PeerPort"] || 69
  55
+		self.context = params["Context"] || {}
  56
+		self.local_file = params["LocalFile"]
  57
+		self.remote_file = params["RemoteFile"] || ::File.split(self.local_file).last
  58
+		self.mode = params["Mode"] || "octet"
  59
+		self.action = params["Action"] || (raise ArgumentError, "Need an action.")
  60
+		self.block_size = params["BlockSize"] || 512
  61
+	end
  62
+
  63
+	#
  64
+	# Methods for both upload and download
  65
+	#
  66
+	
  67
+	def start_server_socket
  68
+		self.server_sock = Rex::Socket::Udp.create(
  69
+			'LocalHost' => local_host,
  70
+			'LocalPort' => local_port,
  71
+			'Context'   => context
  72
+		)
  73
+		if self.server_sock and block_given?
  74
+			yield "Started TFTP client listener on #{local_host}:#{local_port}"
  75
+		end
  76
+		self.threads << Rex::ThreadFactory.spawn("TFTPServerMonitor", false) {
  77
+			if block_given?
  78
+				monitor_server_sock {|msg| yield msg}
  79
+			else
  80
+				monitor_server_sock
  81
+			end
  82
+		}
  83
+	end
  84
+
  85
+	def monitor_server_sock
  86
+		yield "Listening for incoming ACKs" if block_given?
  87
+		res = self.server_sock.recvfrom(65535)
  88
+		if res and res[0]
  89
+			code, type, data = parse_tftp_response(res[0])
  90
+			if code == OpAck and self.action == :upload
  91
+				if block_given?
  92
+					yield "WRQ accepted, sending the file." if type == 0
  93
+					send_data(res[1], res[2]) {|msg| yield msg}
  94
+				else
  95
+					send_data(res[1], res[2])
  96
+				end
  97
+			elsif code == OpData and self.action == :download
  98
+				if block_given?
  99
+					recv_data(res[1], res[2], data) {|msg| yield msg}
  100
+				else
  101
+					recv_data(res[1], res[2], data)
  102
+				end
  103
+			elsif code == OpError
  104
+				yield("Aborting, got error type:%d, message:'%s'" % [type, data]) if block_given?
  105
+				self.status = {:error => [code, type, data]}
  106
+			else
  107
+				yield("Aborting, got code:%d, type:%d, message:'%s'" % [code, type, data]) if block_given?
  108
+				self.status = {:error => [code, type, data]}
  109
+			end
  110
+		end
  111
+		stop
  112
+	end
  113
+
  114
+	def monitor_client_sock
  115
+		res = self.client_sock.recvfrom(65535)
  116
+		if res[1] # Got a response back, so that's never good; Acks come back on server_sock.
  117
+			code, type, data = parse_tftp_response(res[0])
  118
+			yield("Aborting, got code:%d, type:%d, message:'%s'" % [code, type, data]) if block_given?
  119
+			self.status = {:error => [code, type, data]}
  120
+			stop
  121
+		end
  122
+	end
  123
+
  124
+	def stop
  125
+		self.complete = true
  126
+		begin
  127
+			self.server_sock.close
  128
+			self.client_sock.close
  129
+			self.server_sock = nil
  130
+			self.client_sock = nil
  131
+			self.threads.each {|t| t.kill}
  132
+		rescue
  133
+			nil
  134
+		end
  135
+	end
  136
+
  137
+	#
  138
+	# Methods for download
  139
+	#
  140
+	
  141
+	def rrq_packet
  142
+		req = [OpRead, self.remote_file, self.mode]
  143
+		packstr = "na#{self.remote_file.length+1}a#{self.mode.length+1}"
  144
+		req.pack(packstr)
  145
+	end
  146
+
  147
+	def ack_packet(blocknum=0)
  148
+		req = [OpAck, blocknum].pack("nn")
  149
+	end
  150
+
  151
+	def send_read_request(&block)
  152
+		self.status = nil
  153
+		self.complete = false
  154
+		if block_given?
  155
+			start_server_socket {|msg| yield msg}
  156
+		else
  157
+			start_server_socket
  158
+		end
  159
+		self.client_sock = Rex::Socket::Udp.create(
  160
+			'PeerHost'  => peer_host,
  161
+			'PeerPort'  => peer_port,
  162
+			'LocalHost' => local_host,
  163
+			'LocalPort' => local_port,
  164
+			'Context'   => context
  165
+		)
  166
+		self.client_sock.sendto(rrq_packet, peer_host, peer_port)
  167
+		self.threads << Rex::ThreadFactory.spawn("TFTPClientMonitor", false) {
  168
+			if block_given?
  169
+				monitor_client_sock {|msg| yield msg}
  170
+			else
  171
+				monitor_client_sock
  172
+			end
  173
+		}
  174
+		until self.complete
  175
+			return self.status
  176
+		end
  177
+	end
  178
+
  179
+	def recv_data(host, port, first_block)
  180
+		self.recv_tempfile = Rex::Quickfile.new('msf-tftp')
  181
+		recvd_blocks = 1
  182
+		if block_given?
  183
+			yield "Source file: #{self.remote_file}, destination file: #{self.local_file}"
  184
+			yield "Received and acknowledged #{first_block.size} in block #{recvd_blocks}"
  185
+		end
  186
+		if block_given?
  187
+			write_and_ack_data(first_block,1,host,port) {|msg| yield msg}
  188
+		else
  189
+			write_and_ack_data(first_block,1,host,port)
  190
+		end
  191
+		current_block = first_block
  192
+		while current_block.size == 512
  193
+			res = self.server_sock.recvfrom(65535)
  194
+			if res and res[0]
  195
+				code, block_num, current_block = parse_tftp_response(res[0])
  196
+				if code == 3
  197
+					if block_given?
  198
+						write_and_ack_data(current_block,block_num,host,port) {|msg| yield msg}
  199
+					else
  200
+						write_and_ack_data(current_block,block_num,host,port)
  201
+					end
  202
+					recvd_blocks += 1
  203
+				else
  204
+					yield("Aborting, got code:%d, type:%d, message:'%s'" % [code, type, msg]) if block_given?
  205
+					stop
  206
+				end
  207
+			end
  208
+		end
  209
+		if block_given?
  210
+			yield("Transferred #{self.recv_tempfile.size} bytes in #{recvd_blocks} blocks, download complete!")
  211
+		end
  212
+		self.status = {:success => [
  213
+			self.local_file,
  214
+			self.remote_file,
  215
+			self.recv_tempfile.size,
  216
+			recvd_blocks.size]
  217
+		}
  218
+		self.recv_tempfile.close
  219
+		stop
  220
+	end
  221
+
  222
+	def write_and_ack_data(data,blocknum,host,port)
  223
+		self.recv_tempfile.write(data)
  224
+		self.recv_tempfile.flush
  225
+		req = ack_packet(blocknum)
  226
+		self.server_sock.sendto(req, host, port)
  227
+		yield "Received and acknowledged #{data.size} in block #{blocknum}" if block_given?
  228
+	end
  229
+
  230
+	#
  231
+	# Methods for upload
  232
+	#
  233
+	
  234
+	def wrq_packet
  235
+		req = [OpWrite, self.remote_file, self.mode]
  236
+		packstr = "na#{self.remote_file.length+1}a#{self.mode.length+1}"
  237
+		req.pack(packstr)
  238
+	end
  239
+
  240
+	# Note that the local filename for uploading need not be a real filename --
  241
+	# if it begins with DATA: it can be any old string of bytes. If it's missing
  242
+	# completely, then just quit.
  243
+	def blockify_file_or_data
  244
+		if self.local_file =~ /^DATA:(.*)/m
  245
+			data = $1
  246
+		elsif ::File.file?(self.local_file) and ::File.readable?(self.local_file)
  247
+			data = ::File.open(self.local_file, "rb") {|f| f.read f.stat.size} rescue []
  248
+		else
  249
+			return []
  250
+		end
  251
+		data_blocks = data.scan(/.{1,#{block_size}}/m)
  252
+		# Drop any trailing empty blocks
  253
+		if data_blocks.size > 1 and data_blocks.last.empty?
  254
+			data_blocks.pop
  255
+		end
  256
+		return data_blocks
  257
+	end
  258
+
  259
+	def send_write_request(&block)
  260
+		self.status = nil
  261
+		self.complete = false
  262
+		if block_given?
  263
+			start_server_socket {|msg| yield msg}
  264
+		else
  265
+			start_server_socket
  266
+		end
  267
+		self.client_sock = Rex::Socket::Udp.create(
  268
+			'PeerHost'  => peer_host,
  269
+			'PeerPort'  => peer_port,
  270
+			'LocalHost' => local_host,
  271
+			'LocalPort' => local_port,
  272
+			'Context'   => context
  273
+		)
  274
+		self.client_sock.sendto(wrq_packet, peer_host, peer_port)
  275
+		self.threads << Rex::ThreadFactory.spawn("TFTPClientMonitor", false) {
  276
+			if block_given?
  277
+				monitor_client_sock {|msg| yield msg}
  278
+			else
  279
+				monitor_client_sock
  280
+			end
  281
+		}
  282
+		until self.complete
  283
+			return self.status
  284
+		end
  285
+	end
  286
+
  287
+	def send_data(host,port)
  288
+		self.status = {:write_allowed => true}
  289
+		data_blocks = blockify_file_or_data()
  290
+		if data_blocks.empty?
  291
+			yield "Closing down since there is no data to send." if block_given?
  292
+			self.status = {:success => [self.local_file, self.local_file, 0, 0]}
  293
+			return nil
  294
+		end
  295
+		sent_data = 0
  296
+		sent_blocks = 0
  297
+		expected_blocks = data_blocks.size
  298
+		expected_size = data_blocks.join.size
  299
+		if block_given?
  300
+			yield "Source file: #{self.local_file =~ /^DATA:/ ? "(Data)" : self.remote_file}, destination file: #{self.remote_file}"
  301
+			yield "Sending #{expected_size} bytes (#{expected_blocks} blocks)"
  302
+		end
  303
+		data_blocks.each_with_index do |data_block,idx|
  304
+			req = [OpData, (idx + 1), data_block].pack("nnA*")
  305
+			if self.server_sock.sendto(req, host, port) > 0
  306
+				sent_data += data_block.size
  307
+			end
  308
+			res = self.server_sock.recvfrom(65535)
  309
+			if res
  310
+				code, type, msg = parse_tftp_response(res[0])
  311
+				if code == 4
  312
+					sent_blocks += 1
  313
+					yield "Sent #{data_block.size} bytes in block #{sent_blocks}" if block_given?
  314
+				else
  315
+					if block_given?
  316
+						yield "Got an unexpected response: Code:%d, Type:%d, Message:'%s'. Aborting." % [code, type, msg]
  317
+					end
  318
+					break
  319
+				end
  320
+			end
  321
+		end
  322
+		if block_given?
  323
+			if(sent_data == expected_size)
  324
+				yield("Transferred #{sent_data} bytes in #{sent_blocks} blocks, upload complete!")
  325
+			else
  326
+				yield "Upload complete, but with errors."
  327
+			end
  328
+		end
  329
+		if sent_data == expected_size
  330
+		self.status = {:success => [
  331
+				self.local_file,
  332
+				self.remote_file,
  333
+				sent_data,
  334
+				sent_blocks
  335
+			] }
  336
+		end
  337
+	end
  338
+
  339
+end
  340
+
  341
+end
  342
+end
  343
+end
209  modules/auxiliary/admin/tftp/tftp_transfer_util.rb
... ...
@@ -0,0 +1,209 @@
  1
+##
  2
+# This file is part of the Metasploit Framework and may be subject to
  3
+# redistribution and commercial restrictions. Please see the Metasploit
  4
+# Framework web site for more information on licensing and terms of use.
  5
+# http://metasploit.com/framework/
  6
+##
  7
+
  8
+
  9
+require 'msf/core'
  10
+
  11
+class Metasploit3 < Msf::Auxiliary
  12
+
  13
+	include Rex::Proto::TFTP
  14
+	include Msf::Auxiliary::Report
  15
+
  16
+	def initialize
  17
+		super(
  18
+			'Name'        => 'TFTP File Transfer Utility',
  19
+			'Description' => %q{
  20
+					This module will transfer a file to or from a remote TFTP server.
  21
+					Note that the target must be able to connect back to the Metasploit system,
  22
+					and NAT traversal for TFTP is often unsupported.
  23
+
  24
+					Two actions are supported: "Upload" and "Download," which behave as one might
  25
+					expect -- use 'set action Actionname' to use either mode of operation.
  26
+
  27
+					If "Download" is selected, at least one of FILENAME or REMOTE_FILENAME
  28
+					must be set. If "Upload" is selected, either FILENAME must be set to a valid path to
  29
+					a source file, or FILEDATA must be populated. FILENAME may be a fully qualified path,
  30
+					or the name of a file in the Msf::Config.local_directory or Msf::Config.data_directory.
  31
+				},
  32
+			'Author'      => [ 'todb' ],
  33
+			'References'  =>
  34
+				[
  35
+					['URL', 'http://www.faqs.org/rfcs/rfc1350.html'],
  36
+					['URL', 'http://www.networksorcery.com/enp/protocol/tftp.htm']
  37
+				],
  38
+			'Actions' => [
  39
+				[ 'Download', {'Description' => "Download REMOTE_FILENAME as FILENAME from the server."}],
  40
+				[ 'Upload',   {'Description' => "Upload FILENAME as REMOTE_FILENAME to the server."}]
  41
+				],
  42
+			'DefaultAction' => 'Upload',
  43
+			'License'     => MSF_LICENSE
  44
+		)
  45
+		register_options([
  46
+			OptString.new( 'FILENAME', [false, "The local filename" ]),
  47
+			OptString.new( 'FILEDATA', [false, "Data to upload in lieu of a real local file." ]),
  48
+			OptString.new( 'REMOTE_FILENAME', [false, "The remote filename"]),
  49
+			OptAddress.new('RHOST',    [true, "The remote TFTP server"]),
  50
+			OptPort.new(   'LPORT',    [false, "The local port the TFTP client should listen on (default is random)" ]),
  51
+			OptAddress.new('LHOST',    [false, "The local address the TFTP client should bind to"]),
  52
+			OptBool.new(   'VERBOSE',  [false, "Display verbose details about the transfer", false]),
  53
+			OptString.new( 'MODE',     [false, "The TFTP mode; usual choices are netascii and octet.", "octet"]),
  54
+			Opt::RPORT(69)
  55
+		], self.class)
  56
+	end
  57
+
  58
+	def mode
  59
+		datastore['MODE'] || "octect"
  60
+	end
  61
+
  62
+	def remote_file
  63
+		datastore['REMOTE_FILENAME'] || ::File.split(datastore['FILENAME']).last
  64
+	end
  65
+
  66
+	def rport
  67
+		datastore['RPORT'] || 69
  68
+	end
  69
+
  70
+	def rhost
  71
+		datastore['RHOST']
  72
+	end
  73
+
  74
+	# Used only to store loot, doesn't actually have any semantic meaning
  75
+	# for the TFTP protocol.
  76
+	def datatype
  77
+		case datastore['MODE']
  78
+		when "netascii"
  79
+			"text/plain"
  80
+		else
  81
+			"application/octet-stream"
  82
+		end
  83
+	end
  84
+
  85
+	def file
  86
+		if action.name == "Upload"
  87
+			fdata = datastore['FILEDATA'].to_s
  88
+			fname = datastore['FILENAME'].to_s
  89
+			if not fdata.empty?
  90
+				fdata_decorated = "DATA:#{datastore['FILEDATA']}"
  91
+			elsif ::File.readable? fname
  92
+				fname
  93
+			else
  94
+				fname_local = ::File.join(Msf::Config.local_directory,fname)
  95
+				fname_data  = ::File.join(Msf::Config.data_directory,fname)
  96
+				return fname_local if ::File.file?(fname_local) and ::File.readable?(fname_local)
  97
+				return fname_data  if ::File.file?(fname_data)  and ::File.readable?(fname_data)
  98
+				return nil # Couldn't find it, giving up.
  99
+			end
  100
+		else # "Download"
  101
+			fname = ::File.split(datastore['FILENAME'] || datastore['REMOTE_FILENAME']).last rescue nil
  102
+		end
  103
+	end
  104
+
  105
+	# Experimental message prepending thinger. Might make it up into the
  106
+	# standard Metasploit lib like vprint_status and friends.
  107
+	def rtarget(ip=nil)
  108
+		if (ip or rhost) and rport
  109
+			[(ip || rhost),rport].map {|x| x.to_s}.join(":") << " "
  110
+		elsif (ip or rhost)
  111
+			"#{rhost} "
  112
+		else
  113
+			""
  114
+		end
  115
+	end
  116
+
  117
+	# This all happens before run(), and should give an idea on how to use
  118
+	# the TFTP client mixin. Essentially, you create an instance of the
  119
+	# Rex::Proto::TFTP::Client class, fill it up with the relevant host and
  120
+	# file data, set it to either :upload or :download, then kick off the
  121
+	# transfer as you like.
  122
+	def setup
  123
+		@lport = datastore['LPORT'] || (1025 + rand(0xffff-1025))
  124
+		@lhost = datastore['LHOST'] || "0.0.0.0"
  125
+		@local_file = file
  126
+		@remote_file = remote_file
  127
+
  128
+		@tftp_client = Rex::Proto::TFTP::Client.new(
  129
+			"LocalHost"  => @lhost,
  130
+			"LocalPort"  => @lport,
  131
+			"PeerHost"   => rhost,
  132
+			"PeerPort"   => rport,
  133
+			"LocalFile"  => @local_file,
  134
+			"RemoteFile" => @remote_file,
  135
+			"Mode"       => mode,
  136
+			"Action"     => action.name.to_s.downcase.intern
  137
+		)
  138
+	end
  139
+
  140
+	def run
  141
+		run_upload()   if action.name == 'Upload'
  142
+		run_download() if action.name == 'Download'
  143
+		while not @tftp_client.complete
  144
+			select(nil,nil,nil,1)
  145
+			print_status [rtarget,"TFTP transfer operation complete."].join
  146
+			save_downloaded_file() if action.name == 'Download'
  147
+			break
  148
+		end
  149
+	end
  150
+
  151
+	# Run in case something untoward happend with the connection and the
  152
+	# client object didn't get stopped on its own. This can happen with
  153
+	# transfers that got interrupted or malformed (like sending a 0 byte
  154
+	# file).
  155
+	def cleanup
  156
+		if @tftp_client and @tftp_client.respond_to? :complete
  157
+			while not @tftp_client.complete
  158
+				select(nil,nil,nil,1)
  159
+				vprint_status "Cleaning up the TFTP client ports and threads."
  160
+				@tftp_client.stop
  161
+			end
  162
+		end
  163
+	end
  164
+
  165
+	def run_upload
  166
+		print_status "Sending '#{file}' to #{rhost}:#{rport} as '#{remote_file}'"
  167
+		ret = @tftp_client.send_write_request { |msg| print_tftp_status(msg) }
  168
+	end
  169
+
  170
+	def run_download
  171
+		print_status "Receiving '#{remote_file}' from #{rhost}:#{rport} as '#{file}'"
  172
+		ret = @tftp_client.send_read_request { |msg| print_tftp_status(msg) }
  173
+	end
  174
+
  175
+	def save_downloaded_file
  176
+		print_status "Saving #{remote_file} as '#{file}'"
  177
+		fh = @tftp_client.recv_tempfile
  178
+		data = File.open(fh,"rb") {|f| f.read f.stat.size} rescue nil
  179
+		if data and not data.empty?
  180
+			unless framework.db.active
  181
+				print_status "No database connected, so not actually saving the data:"
  182
+				print_line data
  183
+			end
  184
+			this_service = report_service(
  185
+				:host => rhost,
  186
+				:port => rport,
  187
+				:name => "tftp",
  188
+				:proto => "udp"
  189
+			)
  190
+			store_loot("tftp.file",datatype,rhost,data,file,remote_file,this_service)
  191
+		else
  192
+			print_status [rtarget,"Did not find any data, so nothing to save."].join
  193
+		end
  194
+		fh.unlink rescue nil # Windows often complains about unlinking tempfiles
  195
+	end
  196
+
  197
+	def print_tftp_status(msg)
  198
+		case msg
  199
+		when /Aborting/, /errors.$/
  200
+			print_error [rtarget,msg].join
  201
+		when /^WRQ accepted/, /^Sending/, /complete!$/
  202
+			print_good [rtarget,msg].join
  203
+		else
  204
+			vprint_status [rtarget,msg].join
  205
+		end
  206
+	end
  207
+
  208
+end
  209
+
60  modules/auxiliary/gather/checkpoint_hostname.rb
... ...
@@ -1,36 +1,34 @@
1 1
 ##
2  
-# $Id$
3  
-##
4  
-
5  
-##
6 2
 # This file is part of the Metasploit Framework and may be subject to
7 3
 # redistribution and commercial restrictions. Please see the Metasploit
8 4
 # Framework web site for more information on licensing and terms of use.
9 5
 # http://metasploit.com/framework/
10 6
 ##
11 7
 
12  
-
13 8
 require 'msf/core'
14 9
 
15  
-
16 10
 class Metasploit3 < Msf::Auxiliary
17 11
 
18 12
 	include Msf::Exploit::Remote::Tcp
19 13
 
20 14
 	def initialize(info = {})
21 15
 		super(update_info(info,
22  
-			'Name'           => 'CheckPoint Firewall-1 Topology Service Hostname Disclosure',
  16
+			'Name'           => 'CheckPoint Firewall-1 SecuRemote Topology Service Hostname Disclosure',
23 17
 			'Description'    => %q{
24  
-				This module sends a query to the TCP port 264 on CheckPoint
  18
+				This module sends a query to the port 264/TCP on CheckPoint Firewall-1
25 19
 				firewalls to obtain the firewall name and management station
26  
-				(such as SmartCenter) name.
  20
+				(such as SmartCenter) name via a pre-authentication topology request.
  21
+				Note that the SecuriTeam reference listed here is not the same vulnerabilty, but it
  22
+				does discus the same protocol and is somewhat related to this information
  23
+				disclosure.
27 24
 			},
28 25
 			'Author'         => [ 'patrick' ],
29  
-			'Version'        => '$Revision$',
  26
+			'DisclosureDate' => 'Dec 14 2011', # Looks like this module is first real reference
30 27
 			'References'     =>
31 28
 				[
32 29
 					# patrickw - None? Stumbled across, probably an old bug/feature but unsure.
33  
-					[ 'URL', 'http://www.osisecurity.com.au/advisories/' ],
  30
+					[ 'URL', 'http://www.osisecurity.com.au/advisories/' ], # Advisory coming soon, placeholder
  31
+					[ 'URL', 'http://www.securiteam.com/securitynews/5HP0D2A4UC.html' ] # Related-ish
34 32
 				]
35 33
 		))
36 34
 
@@ -45,25 +43,53 @@ def autofilter
45 43
 	end
46 44
 
47 45
 	def run
48  
-		print_status("Attempting to contact Checkpoint FW1 Topology service...")
  46
+		print_status("Attempting to contact Checkpoint FW1 SecuRemote Topology service...")
  47
+		fw_hostname = nil
  48
+		sc_hostname = nil
  49
+
49 50
 		connect
50 51
 
51 52
 		sock.put("\x51\x00\x00\x00")
52 53
 		sock.put("\x00\x00\x00\x21")
53  
-		res = sock.get(4)
  54
+		res = sock.get_once(4)
54 55
 		if (res == "Y\x00\x00\x00")
55 56
 			print_good("Appears to be a CheckPoint Firewall...")
56 57
 			sock.put("\x00\x00\x00\x0bsecuremote\x00")
57 58
 			res = sock.get_once
58  
-			if (res =~ /CN\=(.+),O\=(.+)\./i)
59  
-				print_good("Firewall Host: #{$1}")
60  
-				print_good("SmartCenter Host: #{$2}")
  59
+			if (res =~ /CN=(.+),O=(.+)\./i)
  60
+				fw_hostname = $1
  61
+				sc_hostname = $2
  62
+				print_good("Firewall Host: #{fw_hostname}")
  63
+				print_good("SmartCenter Host: #{sc_hostname}")
61 64
 			end
62 65
 		else
63  
-			print_error("Unexpected response:\r\n#{res}")
  66
+			print_error("Unexpected response: '#{res.inspect}'")
64 67
 		end
65 68
 
  69
+		report_info(fw_hostname,sc_hostname)
  70
+
66 71
 		disconnect
67 72
 	end
68 73
 
  74
+	# Only trust that it's real if we have a hostname. If you get a funny
  75
+	# response, it might not be what we think it is.
  76
+	def report_info(fw_hostname,sc_hostname)
  77
+		return unless fw_hostname
  78
+		host_info = {
  79
+			:host => datastore['RHOST'],
  80
+			:os_name => "Checkpoint Firewall-1",
  81
+			:purpose => "firewall"
  82
+		}
  83
+		host_info[:name] = fw_hostname
  84
+		host_info[:info] = "SmartCenter Host: #{sc_hostname}" if sc_hostname
  85
+		report_host(host_info)
  86
+		svc_info = {
  87
+			:host => datastore['RHOST'],
  88
+			:port => datastore['RPORT'],
  89
+			:proto => "tcp",
  90
+			:name => "securemote"
  91
+		}
  92
+		report_service(svc_info)
  93
+	end
  94
+
69 95
 end
4  modules/exploits/windows/browser/imgeviewer_tifmergemultifiles.rb
@@ -73,10 +73,6 @@ def check_dependencies
73 73
 		use_zlib
74 74
 	end
75 75
 
76  
-	def junk(n=4)
77  
-		return rand_text_alpha(n).unpack("L")[0].to_i
78  
-	end
79  
-
80 76
 	def on_request_uri(cli, request)
81 77
 
82 78
 		# Set target manually or automatically

0 notes on commit 14270fe

Please sign in to comment.
Something went wrong with that request. Please try again.