265 lines
7.4 KiB
Ruby
265 lines
7.4 KiB
Ruby
# -*- coding: binary -*-
|
|
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, xfer_syntax_uuid=UUID.xfer_syntax_uuid, xfer_syntax_vers=UUID.xfer_syntax_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(xfer_syntax_vers)
|
|
|
|
if UUID.is? xfer_syntax_uuid
|
|
xfer_syntax_uuid = UUID.uuid_pack(xfer_syntax_uuid)
|
|
end
|
|
|
|
# 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
|
|
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 = bind_head.to_i
|
|
bind_tail = bind_tail.to_i
|
|
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 = '')
|
|
|
|
flags = flags.to_i
|
|
opnum = opnum.to_i
|
|
ctx = ctx.to_i
|
|
|
|
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 = '')
|
|
|
|
opnum = opnum.to_i
|
|
size = [4000, size.to_i].min
|
|
ctx = ctx.to_i
|
|
|
|
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
|