Skip to content

Commit d55cece

Browse files
committed
rpcserver: only answer to packets on the currently bound interface
1 parent 13fdbbf commit d55cece

3 files changed

Lines changed: 50 additions & 6 deletions

File tree

doc/scapy/layers/dcerpc.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,6 @@ To start an endpoint mapper (this should be a separate process from your RPC ser
393393
)
394394
395395
396-
.. note:: Currently, a DCERPC_Server will let a client bind on all interfaces that Scapy has registered (imported). Supposedly though, you know which RPCs are going to be queried.
397-
398396
Debugging with extended error information (eerr)
399397
------------------------------------------------
400398

scapy/layers/dcerpc.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,9 +1305,12 @@ def register_dcerpc_interface(name, uuid, version, opnums):
13051305
if_version,
13061306
opnums,
13071307
)
1308+
13081309
# bind for build
13091310
for opnum, operations in opnums.items():
13101311
bind_top_down(DceRpc5Request, operations.request, opnum=opnum)
1312+
operations.request.opnum = opnum
1313+
operations.request.intf = uuid
13111314

13121315

13131316
def find_dcerpc_interface(name) -> DceRpcInterface:

scapy/layers/msrpce/rpcserver.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99

1010
import socket
11+
import uuid
1112
import threading
1213
from collections import deque
1314

@@ -27,13 +28,15 @@
2728
DceRpc5Bind,
2829
DceRpc5BindAck,
2930
DceRpc5BindNak,
31+
DceRpc5Fault,
3032
DceRpc5PortAny,
3133
DceRpc5Request,
3234
DceRpc5Response,
3335
DceRpc5Result,
3436
DceRpc5TransferSyntax,
3537
DceRpcInterface,
3638
DceRpcSession,
39+
NDRPacket,
3740
RPC_C_AUTHN_LEVEL,
3841
)
3942

@@ -49,11 +52,17 @@
4952
# Typing
5053
from typing import (
5154
Dict,
55+
Callable,
5256
Optional,
57+
Tuple,
5358
)
5459

5560

5661
class _DCERPC_Server_metaclass(type):
62+
# This value is calculated for each DCE/RPC server, and contains
63+
# the callables sorted by interface+opnum
64+
dcerpc_commands: Dict[Tuple[uuid.UUID, int], Callable] = {}
65+
5766
def __new__(cls, name, bases, dct):
5867
dct.setdefault(
5968
"dcerpc_commands",
@@ -108,7 +117,14 @@ def answer(reqcls):
108117
"""
109118

110119
def deco(func):
111-
func.dcerpc_command = reqcls
120+
if not issubclass(reqcls, NDRPacket):
121+
raise ValueError("Cannot answer a non NDRPacket class !")
122+
try:
123+
func.dcerpc_command = reqcls.intf, reqcls.opnum
124+
except AttributeError:
125+
raise ValueError(
126+
"NDRPacket class isn't registered or isn't a request !"
127+
)
112128
return func
113129

114130
return deco
@@ -120,10 +136,17 @@ def extend(self, server_cls):
120136
self.dcerpc_commands.update(server_cls.dcerpc_commands)
121137

122138
def make_reply(self, req):
123-
cls = req[DceRpc5Request].payload.__class__
124-
if cls in self.dcerpc_commands:
139+
"""
140+
Make a response to the DCE/RPC request.
141+
142+
This finds whether a callback has been registered for this particular packet,
143+
and call it if available.
144+
"""
145+
opnum = req[DceRpc5Request].opnum
146+
intf = self.session.rpc_bind_interface.uuid
147+
if (intf, opnum) in self.dcerpc_commands:
125148
# call handler
126-
return self.dcerpc_commands[cls](self, req)
149+
return self.dcerpc_commands[(intf, opnum)](self, req)
127150
return None
128151

129152
@classmethod
@@ -408,6 +431,26 @@ def recv(self, data):
408431
">> RESPONSE: %s" % (resp.__class__.__name__)
409432
)
410433
)
434+
else:
435+
# Unimplemented request !
436+
if self.verb:
437+
print(
438+
conf.color_theme.fail(
439+
"! RPC request not implemented by server."
440+
)
441+
)
442+
req.show()
443+
444+
# Return a Fault
445+
hdr.pfc_flags += "PFC_DID_NOT_EXECUTE"
446+
self.queue.extend(
447+
hdr
448+
/ DceRpc5Fault(
449+
# nca_s_op_rng_error
450+
status=0x1C010002,
451+
cont_id=req.cont_id,
452+
)
453+
)
411454
# If there was padding, process the second frag
412455
if pad is not None:
413456
self.recv(pad)

0 commit comments

Comments
 (0)