From 50498964544b179195954ef71c9743ed6b977a7a Mon Sep 17 00:00:00 2001 From: HD Moore Date: Sun, 17 Jul 2005 23:28:28 +0000 Subject: [PATCH] Fixes, tweaks, etc git-svn-id: file:///home/svn/incoming/trunk@2783 4d416f70-5f16-0410-b530-b9f4589650da --- lib/rex/proto/dcerpc.rb | 46 +++++++++------------ lib/rex/proto/dcerpc/response.rb | 71 ++++++++++++++++++++++---------- lib/rex/proto/dcerpc/uuid.rb | 9 +++- 3 files changed, 76 insertions(+), 50 deletions(-) diff --git a/lib/rex/proto/dcerpc.rb b/lib/rex/proto/dcerpc.rb index 0c2e7e2d73..a53a67c853 100644 --- a/lib/rex/proto/dcerpc.rb +++ b/lib/rex/proto/dcerpc.rb @@ -15,34 +15,30 @@ require 'rex/proto/dcerpc/uuid' require 'rex/proto/dcerpc/response' require 'rex/text' - # # Process a DCERPC response packet from a socket - # def read_response (socket) + head = socket.timed_read(10, 5) if (! head or head.length() != 10) return end - + resp = Rex::Proto::DCERPC::Response.new(head) if (! resp.frag_len) return resp end - - body = socket.timed_read(resp.frag_len, 10) - if (! body or body.length() != resp.frag_len) + + body = socket.timed_read(resp.frag_len - 10, 10) + if (body.nil? or body.length() != resp.frag_len - 10) return resp end - + resp.parse(body) return resp end - - # # Create a standard DCERPC BIND request packet - # def make_bind (uuid, vers) u = Rex::Proto::DCERPC::UUID.new() @@ -74,12 +70,12 @@ require 'rex/text' xfer_vers_maj, # syntax major version xfer_vers_min, # syntax minor version ].pack('CCCCNvvVvvVVvvA16vvA16vv') + + return buff, 0 end - # # Create an obfuscated DCERPC BIND request packet - # - def make_bind_fake_multi(uuid, vers, bind_head=rand(6)+10, bind_tail=rand(3)+1) + def make_bind_fake_multi(uuid, vers, bind_head=rand(6)+10, bind_tail=rand(4)) u = Rex::Proto::DCERPC::UUID.new() # Process the version strings ("1.0", 1.0, "1", 1) @@ -87,7 +83,7 @@ require 'rex/text' xfer_vers_maj, xfer_vers_min = u.vers_to_nums(u.xfer_syntax_vers) bind_total = bind_head + bind_tail + 1 - bind_size = (bind_total * 40) + 32 + bind_size = (bind_total * 44) + 28 real_ctx, ctx = 0, 0 # Create the header of the bind request @@ -104,8 +100,7 @@ require 'rex/text' 5840, # max xmit frag 5840, # max recv frag 0, # assoc group - 1, # num ctx items - bind_total, # context id + bind_total, # num ctx items ].pack('CCCCNvvVvvVV') # Generate the fake UUIDs prior to the real one @@ -117,7 +112,7 @@ require 'rex/text' data += [ - ctx += 1, # context id + ctx, # context id 1, # num trans items rand_uuid, # interface uuid rand_imaj, # interface major version @@ -126,13 +121,14 @@ require 'rex/text' xfer_vers_maj, # syntax major version xfer_vers_min, # syntax minor version ].pack('vvA16vvA16vv') + ctx += 1 end # Stuff the real UUID onto the end of the buffer real_ctx = ctx; data += [ - ctx += 1, # context id + ctx, # context id 1, # num trans items u.uuid_pack(uuid), # interface uuid bind_vers_maj, # interface major version @@ -141,7 +137,9 @@ require 'rex/text' xfer_vers_maj, # syntax major version xfer_vers_min, # syntax minor version ].pack('vvA16vvA16vv') + ctx += 1 + # Generate the fake UUIDs after the real one 1.upto(bind_tail) do || # Generate some random UUID and versions @@ -151,7 +149,7 @@ require 'rex/text' data += [ - ctx += 1, # context id + ctx, # context id 1, # num trans items rand_uuid, # interface uuid rand_imaj, # interface major version @@ -160,15 +158,14 @@ require 'rex/text' xfer_vers_maj, # syntax major version xfer_vers_min, # syntax minor version ].pack('vvA16vvA16vv') + ctx += 1 end - + # Return both the bind packet and the real context_id return data, real_ctx end - # # Create a standard DCERPC ALTER_CONTEXT request packet - # def make_alter_context (uuid, vers) u = Rex::Proto::DCERPC::UUID.new() @@ -202,9 +199,7 @@ require 'rex/text' end - # # Used to create a piece of a DCERPC REQUEST packet - # def make_request_chunk (flags=3, opnum=0, data="", ctx=0) dlen = data.length @@ -226,9 +221,7 @@ require 'rex/text' ].pack('CCCCNvvVVvv') + data end - # # Used to create standard DCERPC REQUEST packet(s) - # def make_request (opnum=0, data="", size=data.length, ctx=0) dlen = data.length @@ -253,7 +246,6 @@ require 'rex/text' return frags end - # Create the first fragment of the request frags.push( make_request_chunk(1, opnum, chunks.shift, ctx) ) diff --git a/lib/rex/proto/dcerpc/response.rb b/lib/rex/proto/dcerpc/response.rb index 5300f95a95..51f6683f98 100644 --- a/lib/rex/proto/dcerpc/response.rb +++ b/lib/rex/proto/dcerpc/response.rb @@ -15,23 +15,29 @@ class DCERPC::Response attr_accessor :frag_len, :auth_len, :type, :vers_major, :vers_minor attr_accessor :flags, :data_rep, :call_id, :max_frag_xmit, :max_frag_recv - attr_accessor :assoc_group, :sec_addr_len, :sec_addr, :num_results, :ack_result - attr_accessor :ack_reason, :xfer_syntax_uuid, :xfer_syntax_vers - + attr_accessor :assoc_group, :sec_addr_len, :sec_addr, :num_results + attr_accessor :nack_reason, :xfer_syntax_uuid, :xfer_syntax_vers + attr_accessor :ack_reason, :ack_result, :ack_xfer_syntax_uuid, :ack_xfer_syntax_vers attr_accessor :alloc_hint, :context_id, :cancel_cnt, :status, :stub_data + # Create a new DCERPC::Response object, using the first 10 bytes of the packet def initialize (head) - self.frag_len = head[8,2].unpack('v') + self.frag_len = head[8,2].unpack('v')[0] self.raw = head + self.ack_result = [] + self.ack_reason = [] + self.ack_xfer_syntax_uuid = [] + self.ack_xfer_syntax_vers = [] end + # Parse the contents of a DCERPC response packet and fill out all the fields def parse (body) self.raw = self.raw + body - self.type = self.raw[2,1].unpack('C') + self.type = self.raw[2,1].unpack('C')[0] uuid = Rex::Proto::DCERPC::UUID.new() data = self.raw - + # BIND_ACK == 12, ALTER_CONTEXT_RESP == 15 if (self.type == 12 or self.type == 15) @@ -49,29 +55,51 @@ class DCERPC::Response self.assoc_group, self.sec_addr_len = data.unpack('CCCCNvvVvvVv') + # Keep an offset into the packet handy + x = 0 + # XXX This is still somewhat broken (4 digit ports) self.sec_addr = data[26, self.sec_addr_len] # Move the pointer into the packet forward - data = data[26 + self.sec_addr_len, 0xffff] + x += 26 + self.sec_addr_len + 2 - self.num_results = data[2,1].unpack('C') - self.ack_result = data[6,2].unpack('v') + # Figure out how many results we have (multiple-context binds) + self.num_results = data[ x, 4 ].unpack('V')[0] + + # Move the pointer to the ack_result[0] offset + x += 4 + + # Initialize the ack_result index + ack = 0 - if (self.ack_result != 0) - self.ack_reason = data[8,2].unpack('v') - data = data[2, 0xffff] + # Scan through all results and add them to the result arrays + while ack < self.num_results + self.ack_result[ack] = data[ x + 0, 2 ].unpack('v')[0] + self.ack_reason[ack] = data[ x + 2, 2 ].unpack('v')[0] + self.ack_xfer_syntax_uuid[ack] = uuid.uuid_unpack(data[ x + 4, 16 ]) + self.ack_xfer_syntax_vers[ack] = data[ x + 20, 4 ].unpack('V')[0] + x += 24 + ack += 1 end - # Move it even further - data = data[10, 0xffff] - - self.xfer_syntax_uuid = uuid.uuid_unpack(data[0,16]) - self.xfer_syntax_vers = data[16,4].unpack('V') - # End of BIND_ACK || ALTER_CONTEXT_RESP end - + + # BIND_NACK == 13 + if (self.type == 13) + + # Decode most of the DCERPC header + self.vers_major, + self.vers_minor, + trash, + self.flags, + self.data_rep, + self.frag_len, + self.auth_len, + self.call_id, + self.nack_reason = data.unpack('CCCCNvvVv') + end # RESPONSE == 2 if (self.type == 2) @@ -91,7 +119,7 @@ class DCERPC::Response # Put the application data into self.stub_data self.stub_data = data[data.length - self.alloc_hint, 0xffff] - + # End of RESPONSE end @@ -114,8 +142,7 @@ class DCERPC::Response self.status = data.unpack('CCCCNvvVVvCCV') # Put the application data into self.stub_data - self.stub_data = data[data.length - self.alloc_hint, 0xffff] - + self.stub_data = data[data.length - self.alloc_hint, 0xffff] # End of FAULT end diff --git a/lib/rex/proto/dcerpc/uuid.rb b/lib/rex/proto/dcerpc/uuid.rb index 623502a202..2f384f8a38 100644 --- a/lib/rex/proto/dcerpc/uuid.rb +++ b/lib/rex/proto/dcerpc/uuid.rb @@ -24,7 +24,8 @@ class DCERPC::UUID 'SVCCTL' => [ '367abb81-9844-35f1-ad32-98f038001003', '2.0' ] } end - + + # Convert a UUID in binary format to the string representation def uuid_unpack(uuid_bin) sprintf("%.8x-%.4x-%.4x-%.4x-%s", uuid_bin[ 0, 4].unpack('V')[0], @@ -35,31 +36,37 @@ class DCERPC::UUID ) end + # Convert a UUID in string format to the binary representation def uuid_pack (uuid_str) parts = uuid_str.split('-') [ parts[0].hex, parts[1].hex, parts[2].hex, parts[3].hex ].pack('Vvvn') + [ parts[4] ].pack('H*') end + # Provide the common TransferSyntax UUID in packed format def xfer_syntax_uuid () self.uuid_pack('8a885d04-1ceb-11c9-9fe8-08002b104860') end + # Provide the common TransferSyntax version number def xfer_syntax_vers () '2.0' end + # Determine the UUID string for the DCERPC service with this name def uuid_by_name (name) if @known_uuids.key?(name) @known_uuids[name][0] end end + # Determine the common version number for the DCERPC service with this name def vers_by_name (name) if @known_uuids.key?(name) @known_uuids[name][1] end end + # Convert a string or number in float format to two unique numbers 2.0 => [2, 0] def vers_to_nums (vers) vers_maj = vers.to_i vers_min = ((vers.to_f - vers.to_i) * 10).to_i