module Rex
module Proto
module DCERPC
class Packet

require 'rex/proto/dcerpc/uuid'
require 'rex/proto/dcerpc/response'
require 'rex/text'
		
	UUID = Rex::Proto::DCERPC::UUID

	# Create a standard DCERPC BIND request packet
	def self.make_bind(uuid, vers)	
		
		# Process the version strings ("1.0", 1.0, "1", 1)
		bind_vers_maj, bind_vers_min = UUID.vers_to_nums(vers)
		xfer_vers_maj, xfer_vers_min = UUID.vers_to_nums(UUID.xfer_syntax_vers)

		# Create the bind request packet
		buff = 
		[
			5,      # major version 5
			0,      # minor version 0
			11,     # bind type
			3,      # flags
			0x10000000,  # data representation
			72,     # frag length
			0,      # auth length
			0,      # call id
			5840,   # max xmit frag
			5840,   # max recv frag
			0,      # assoc group
			1,      # num ctx items
			0,      # context id
			1,      # num trans items
			UUID.uuid_pack(uuid),   # interface uuid
			bind_vers_maj,       # interface major version
			bind_vers_min,       # interface minor version
			UUID.xfer_syntax_uuid,  # transfer syntax
			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 self.make_bind_fake_multi(uuid, vers, bind_head=0, bind_tail=0)

		bind_head = rand(6)+10 if bind_head == 0
		bind_tail = rand(4)+1 if bind_head == 0

		u = Rex::Proto::DCERPC::UUID
		
		# Process the version strings ("1.0", 1.0, "1", 1)
		bind_vers_maj, bind_vers_min = UUID.vers_to_nums(vers)
		xfer_vers_maj, xfer_vers_min = UUID.vers_to_nums(UUID.xfer_syntax_vers)
		
		bind_total = bind_head + bind_tail + 1
		bind_size  = (bind_total * 44) + 28
		real_ctx, ctx = 0, 0

		# Create the header of the bind request
		data = 
		[
			5,      # major version 5
			0,      # minor version 0
			11,     # bind type
			3,      # flags
			0x10000000,  # data representation
			bind_size,   # frag length
			0,      # auth length
			0,      # call id
			5840,   # max xmit frag
			5840,   # max recv frag
			0,      # assoc group
			bind_total,  # num ctx items
		].pack('CCCCNvvVvvVV')
		
		# Generate the fake UUIDs prior to the real one
		1.upto(bind_head) do ||
			# Generate some random UUID and versions
			rand_uuid = Rex::Text.rand_text(16)
			rand_imaj = rand(6)			
			rand_imin = rand(4)
			
			data += 
			[
				ctx,        # context id
				1,          # num trans items		
				rand_uuid,  # interface uuid
				rand_imaj,  # interface major version
				rand_imin,  # interface minor version
				UUID.xfer_syntax_uuid,  # transfer syntax
				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,      # context id
			1,        # num trans items		
			UUID.uuid_pack(uuid),   # interface uuid
			bind_vers_maj,       # interface major version
			bind_vers_min,       # interface minor version
			UUID.xfer_syntax_uuid,  # transfer syntax
			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
			rand_uuid = Rex::Text.rand_text(16)
			rand_imaj = rand(6)			
			rand_imin = rand(4)
			
			data += 
			[
				ctx,        # context id
				1,          # num trans items		
				rand_uuid,  # interface uuid
				rand_imaj,  # interface major version
				rand_imin,  # interface minor version
				UUID.xfer_syntax_uuid,  # transfer syntax
				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 self.make_alter_context(uuid, vers)	
		u = Rex::Proto::DCERPC::UUID
		
		# Process the version strings ("1.0", 1.0, "1", 1)
		bind_vers_maj, bind_vers_min = UUID.vers_to_nums(vers)
		xfer_vers_maj, xfer_vers_min = UUID.vers_to_nums(UUID.xfer_syntax_vers)

		buff = 
		[
			5,      # major version 5
			0,      # minor version 0
			14,     # alter context
			3,      # flags
			0x10000000,     # data representation
			72,     # frag length
			0,      # auth length
			0,      # call id
			5840,   # max xmit frag
			5840,   # max recv frag
			0,      # assoc group
			1,      # num ctx items
			0,      # context id
			1,      # num trans items
			UUID.uuid_pack(uuid),   # interface uuid
			bind_vers_maj,       # interface major version
			bind_vers_min,       # interface minor version
			UUID.xfer_syntax_uuid,  # transfer syntax
			xfer_vers_maj,       # syntax major version
			xfer_vers_min,       # syntax minor version 
		].pack('CCCCNvvVvvVVvvA16vvA16vv')
	end
	

	# Used to create a piece of a DCERPC REQUEST packet
	def self.make_request_chunk(flags=3, opnum=0, data="", ctx=0, object_id = '')

		dlen = data.length
		flen = dlen + 24

		use_object = 0

		object_str = ''

		if object_id.size > 0
			flags |= 0x80
			flen = flen + 16
			object_str = UUID.uuid_pack(object_id)
		end

		buff = 
		[
			5,      # major version 5
			0,      # minor version 0
			0,      # request type
			flags,  # flags
			0x10000000,     # data representation
			flen,   # frag length
			0,      # auth length
			0,      # call id
			dlen,   # alloc hint
			ctx,    # context id
			opnum,  # operation number
		].pack('CCCCNvvVVvv') + object_str + data
	end	

	# Used to create standard DCERPC REQUEST packet(s)
	def self.make_request(opnum=0, data="", size=data.length, ctx=0, object_id = '')

		if size > 4000
			size = 4000
		end

		chunks, frags = [], []
		ptr = 0
		
		# Break the request into fragments of 'size' bytes
		while ptr < data.length
			chunks.push( data[ ptr, size ] )
			ptr += size
		end
		
		# Process requests with no stub data
		if chunks.length == 0
			frags.push( make_request_chunk(3, opnum, '', ctx, object_id) )
			return frags
		end
		
		# Process requests with only one fragment
		if chunks.length == 1
			frags.push( make_request_chunk(3, opnum, chunks[0], ctx, object_id) )
			return frags
		end

		# Create the first fragment of the request
		frags.push( make_request_chunk(1, opnum, chunks.shift, ctx, object_id) )
		
		# Create all of the middle fragments
		while chunks.length != 1
			frags.push( make_request_chunk(0, opnum, chunks.shift, ctx, object_id) )
		end
		
		# Create the last fragment of the request
		frags.push( make_request_chunk(2, opnum, chunks.shift, ctx, object_id) )

		return frags
	end		
	
end
end
end
end
