# Copyright (c) 2003-2006 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# $Id: dcerpc_v4.py,v 1.10 2006/05/23 22:26:51 gera Exp $
#
# Description:
# Handle basic DCE/RPC protocol, version 4.
#
import array
import socket
import struct
from impacket import ImpactPacket
from impacket import uuid
import dcerpc, conv
class MSRPCHeader(ImpactPacket.Header):
__SIZE = 80
def __init__(self, aBuffer = None):
ImpactPacket.Header.__init__(self, MSRPCHeader.__SIZE)
self.set_version(4)
self.set_type(dcerpc.MSRPC_REQUEST)
self.set_flags((0x08, 0x00))
self.set_representation((0x10, 0x00, 0x00))
self.set_serial((0, 0))
## self.set_if_version(3)
self.set_seq_num(0)
self.set_if_hint(0xFFFF)
self.set_activity_hint(0xFFFF)
if aBuffer: self.load_header(aBuffer)
def get_version(self):
return self.get_byte(0)
def set_version(self, version):
self.set_byte(0, version)
def get_type(self):
return self.get_byte(1)
def set_type(self, type):
self.set_byte(1, type)
def get_flags(self):
""" This method returns a tuple in (flags1, flags2) form."""
return (self.get_byte(2), self.get_byte(3))
def set_flags(self, flags):
""" This method takes a tuple in (flags1, flags2) form."""
self.set_byte(2, flags[0])
self.set_byte(3, flags[1])
def get_representation(self):
""" This method returns a tuple in (major, minor) form."""
return (self.get_byte(4), self.get_byte(5), self.get_byte(6))
def set_representation(self, representation):
""" This method takes a tuple in (major, minor) form."""
self.set_byte(4, representation[0])
self.set_byte(5, representation[1])
self.set_byte(6, representation[1])
def get_serial(self):
""" This method returns a tuple in (high, low) form."""
return (self.get_byte(7), self.get_byte(79))
def set_serial(self, serial):
""" This method takes a tuple in (high, low) form."""
self.set_byte(7, serial[0])
self.set_byte(79, serial[1])
def get_obj_binuuid(self):
return self.get_bytes().tolist()[8:8+16]
def set_obj_binuuid(self, binuuid):
assert 16 == len(binuuid)
self.get_bytes()[8:8+16] = array.array('B', binuuid)
def get_if_binuuid(self):
return self.get_bytes().tolist()[24:24+16]
def set_if_binuuid(self, binuuid):
assert 16 == len(binuuid)
self.get_bytes()[24:24+16] = array.array('B', binuuid)
def get_activity_binuuid(self):
return self.get_bytes().tolist()[40:40+16]
def set_activity_binuuid(self, binuuid):
assert 16 == len(binuuid)
self.get_bytes()[40:40+16] = array.array('B', binuuid)
def get_server_boottime(self):
return self.get_long(56, '<')
def set_server_boottime(self, time):
self.set_long(56, time, '<')
def get_if_version(self):
return self.get_long(60, '<')
def set_if_version(self, version):
self.set_long(60, version, '<')
def get_seq_num(self):
return self.get_long(64, '<')
def set_seq_num(self, num):
self.set_long(64, num, '<')
def get_op_num(self):
return self.get_word(68, '<')
def set_op_num(self, op):
self.set_word(68, op, '<')
def get_if_hint(self):
return self.get_word(70, '<')
def set_if_hint(self, hint):
self.set_word(70, hint, '<')
def get_activity_hint(self):
return self.get_word(72, '<')
def set_activity_hint(self, hint):
self.set_word(72, hint, '<')
def get_frag_len(self):
return self.get_word(74, '<')
def set_frag_len(self, len):
self.set_word(74, len, '<')
def get_frag_num(self):
return self.get_word(76, '<')
def set_frag_num(self, num):
self.set_word(76, num, '<')
def get_auth_proto(self):
return self.get_byte(78)
def set_auth_proto(self, proto):
self.set_byte(78, proto)
def get_header_size(self):
return MSRPCHeader.__SIZE
def contains(self, aHeader):
ImpactPacket.Header.contains(self, aHeader)
if self.child():
contents_size = self.child().get_size()
self.set_op_num(self.child().OP_NUM)
self.set_frag_len(contents_size)
def get_ctx_id(self):
# return self.get_word(20, '<')
return 0
def set_ctx_id(self, id):
# self.set_word(20, id, '<')
pass
class DCERPC_v4(dcerpc.DCERPC):
DEFAULT_FRAGMENT_SIZE = 1392
def __init__(self, transport):
dcerpc.DCERPC.__init__(self, transport)
self.__activity_uuid = uuid.generate()
self.__seq_num = 0
self._bind = 0 # Don't attempt binding unless it explicitly requested.
self.set_idempotent(0)
def set_default_max_fragment_size(self):
self.set_max_fragment_size(DCERPC_v4.DEFAULT_FRAGMENT_SIZE)
def bind(self, uuid, bogus_binds = ''):
"""If idempotent is non-zero, the package will be sent with
that flag enabled. Certain services react by skiping the CONV
phase during the binding.
"""
self._bind = 1 # Will bind later, when the first packet is transferred.
self.__if_uuid = uuid[:16]
self.__if_version = struct.unpack('<L', uuid[16:20])[0]
def get_idempotent(self):
return self.__idempotent
def set_idempotent(self, flag):
self.__idempotent = flag
def conv_bind(self):
# Receive CONV handshake.
# ImpactDecode: this block.
data = self._transport.recv()
rpc = MSRPCHeader(data)
activity_uuid = rpc.get_activity_binuuid()
_conv = conv.WhoAreYou(data[rpc.get_header_size():])
# ImpactDecode
rpc = MSRPCHeader()
rpc.set_type(dcerpc.MSRPC_RESPONSE)
rpc.set_if_binuuid(conv.MSRPC_UUID_CONV)
flags = rpc.get_flags()
rpc.set_flags((flags[0], 0x04))
rpc.set_activity_binuuid(activity_uuid)
_conv = conv.WhoAreYou2()
rpc.contains(_conv)
# The CONV response must be sent to the endpoint from where the request was received.
old_address = self._transport.get_addr()
peer_address = self._transport.get_recv_addr()
self._transport.set_addr(peer_address)
self._transport.send(rpc.get_packet())
self._transport.set_addr(old_address)
def send(self, data):
packet = data.get_packet()
frag_num = 0
rpc = MSRPCHeader()
self.set_ctx_id(self._ctx)
rpc.set_if_binuuid(self.__if_uuid)
rpc.set_if_version(self.__if_version)
rpc.set_activity_binuuid(self.__activity_uuid)
rpc.set_seq_num(self.__seq_num)
frag = dcerpc.DCERPC_RawCall(data.OP_NUM)
if self._max_frag:
offset = 0
while 1:
toSend = packet[offset:offset+self._max_frag]
if not toSend: break
flags = dcerpc.MSRPC_NOTAFRAG | dcerpc.MSRPC_RECRESPOND
if self.__idempotent: flags |= dcerpc.MSRPC_NOTFORIDEMP
offset += len(toSend)
if offset == len(packet): flags |= dcerpc.MSRPC_LASTFRAG
rpc.set_flags((flags, 0))
frag.setData(toSend)
rpc.contains(frag)
rpc.set_frag_num(frag_num)
self._transport.send(rpc.get_packet())
frag_num += 1
if self._bind and not self.__idempotent:
self._bind = 0
self.conv_bind()
self.recv() # Discard RPC_ACK.
else:
if self.__idempotent:
rpc.set_flags((dcerpc.MSRPC_NOTFORIDEMP, 0))
rpc.contains(data)
self._transport.send(rpc.get_packet())
if self._bind and not self.__idempotent:
self._bind = 0
self.conv_bind()
self.recv() # Discard RPC_ACK.
self.__seq_num += 1
def recv(self):
data = self._transport.recv()
rpc = MSRPCHeader(data)
off = rpc.get_header_size()
return data[off:]
syntax highlighted by Code2HTML, v. 0.9.1