-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# SPDX-License-Identifier: GPL-2.0-or-later | ||
# This file is part of Scapy | ||
# See https://scapy.net/ for more information | ||
# Copyright (C) Gabriel Potter | ||
|
||
""" | ||
[MS-DRSR] Directory Replication Service (DRS) Remote Protocol | ||
""" | ||
|
||
import uuid | ||
from scapy.packet import Packet | ||
from scapy.fields import LEIntField, FlagsField, UUIDField, UTCTimeField | ||
|
||
from scapy.layers.msrpce.raw.ms_drsr import UUID | ||
from scapy.layers.msrpce.raw.ms_drsr import * # noqa: F403,F401 | ||
|
||
# [MS-DRSR] sect 5.39 DRS_EXTENSIONS_INT | ||
|
||
|
||
class DRS_EXTENSIONS_INT(Packet): | ||
fields_desc = [ | ||
FlagsField( | ||
"dwFlags", | ||
0, | ||
-32, | ||
{ | ||
0x00000001: "BASE", | ||
0x00000002: "ASYNCREPL", | ||
0x00000004: "REMOVEAPI", | ||
0x00000008: "MOVEREQ_V2", | ||
0x00000010: "GETCHG_DEFLATE", | ||
0x00000020: "DCINFO_V1", | ||
0x00000040: "RESTORE_USN_OPTIMIZATION", | ||
0x00000080: "ADDENTRY", | ||
0x00000100: "KCC_EXECUTE", | ||
0x00000200: "ADDENTRY_V2", | ||
0x00000400: "LINKED_VALUE_REPLICATION", | ||
0x00000800: "DCINFO_V2", | ||
0x00001000: "INSTANCE_TYPE_NOT_REQ_ON_MOD", | ||
0x00002000: "CRYPTO_BIND", | ||
0x00004000: "GET_REPL_INFO", | ||
0x00008000: "STRONG_ENCRYPTION", | ||
0x00010000: "DCINFO_VFFFFFFFF", | ||
0x00020000: "TRANSITIVE_MEMBERSHIP", | ||
0x00040000: "ADD_SID_HISTORY", | ||
0x00080000: "POST_BETA3", | ||
0x00100000: "GETCHGREQ_V5", | ||
0x00200000: "GETMEMBERSHIPS2", | ||
0x00400000: "GETCHGREQ_V6", | ||
0x00800000: "NONDOMAIN_NCS", | ||
0x01000000: "GETCHGREQ_V8", | ||
0x02000000: "GETCHGREPLY_V5", | ||
0x04000000: "GETCHGREPLY_V6", | ||
0x08000000: "WHISTLER_BETA3", | ||
0x10000000: "W2K3_DEFLATE", | ||
0x20000000: "GETCHGREQ_V10", | ||
0x40000000: "R2", | ||
0x80000000: "R3", | ||
}, | ||
), | ||
UUIDField("SiteObjGuid", None, uuid_fmt=UUIDField.FORMAT_LE), | ||
LEIntField("Pid", 0), | ||
UTCTimeField("dwReplEpoch", None, fmt="<I"), | ||
FlagsField( | ||
"dwFlagsExt", | ||
0, | ||
-32, | ||
{ | ||
0x00000001: "ADAM", | ||
0x00000002: "LH_BETA2", | ||
0x00000004: "RECYCLE_BIN", | ||
0x00000100: "GETCHGREPLY_V9", | ||
0x00000400: "RPC_CORRELATIONID_1", | ||
}, | ||
), | ||
UUIDField("ConfigObjGuid", None, uuid_fmt=UUIDField.FORMAT_LE), | ||
LEIntField("dwExtCaps", 0), | ||
] | ||
|
||
|
||
# [MS-DRSR] sect 5.138 NTDSAPI_CLIENT_GUID | ||
|
||
NTDSAPI_CLIENT_GUID = UUID(uuid.UUID("{e24d201a-4fd6-11d1-a3da-0000f875ae0d}").bytes_le) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
# This file is part of Scapy | ||
# See https://scapy.net/ for more information | ||
# Copyright (C) Gabriel Potter | ||
|
||
""" | ||
Very partial RPC definitions for the following interfaces: | ||
- drsuapi (v4.0): e3514235-4b06-11d1-ab04-00c04fc2dcd2 | ||
""" | ||
|
||
from enum import IntEnum | ||
import uuid | ||
|
||
from scapy.fields import StrFixedLenField | ||
from scapy.layers.dcerpc import ( | ||
NDRPacket, | ||
DceRpcOp, | ||
NDRByteField, | ||
NDRConfFieldListField, | ||
NDRConfPacketListField, | ||
NDRConfStrLenField, | ||
NDRConfStrLenFieldUtf16, | ||
NDRConfVarFieldListField, | ||
NDRConfVarStrNullField, | ||
NDRConfVarStrNullFieldUtf16, | ||
NDRContextHandle, | ||
NDRFullPointerField, | ||
NDRInt3264EnumField, | ||
NDRIntField, | ||
NDRLongField, | ||
NDRPacketField, | ||
NDRRecursiveField, | ||
NDRRefEmbPointerField, | ||
NDRShortField, | ||
NDRSignedByteField, | ||
NDRSignedIntField, | ||
NDRSignedLongField, | ||
NDRUnionField, | ||
NDRVarStrLenField, | ||
NDRVarStrLenFieldUtf16, | ||
register_dcerpc_interface, | ||
) | ||
|
||
|
||
class UUID(NDRPacket): | ||
ALIGNMENT = (4, 4) | ||
fields_desc = [ | ||
NDRIntField("Data1", 0), | ||
NDRShortField("Data2", 0), | ||
NDRShortField("Data3", 0), | ||
StrFixedLenField("Data4", "", length=8), | ||
] | ||
|
||
|
||
class DRS_EXTENSIONS(NDRPacket): | ||
ALIGNMENT = (4, 8) | ||
DEPORTED_CONFORMANTS = ["rgb"] | ||
fields_desc = [ | ||
NDRIntField("cb", None, size_of="rgb"), | ||
NDRConfStrLenField( | ||
"rgb", "", size_is=lambda pkt: pkt.cb, conformant_in_struct=True | ||
), | ||
] | ||
|
||
|
||
class IDL_DRSBind_Request(NDRPacket): | ||
fields_desc = [ | ||
NDRFullPointerField(NDRPacketField("puuidClientDsa", UUID(), UUID)), | ||
NDRFullPointerField( | ||
NDRPacketField("pextClient", DRS_EXTENSIONS(), DRS_EXTENSIONS) | ||
), | ||
] | ||
|
||
|
||
class IDL_DRSBind_Response(NDRPacket): | ||
fields_desc = [ | ||
NDRFullPointerField( | ||
NDRPacketField("ppextServer", DRS_EXTENSIONS(), DRS_EXTENSIONS) | ||
), | ||
NDRPacketField("phDrs", NDRContextHandle(), NDRContextHandle), | ||
NDRIntField("status", 0), | ||
] | ||
|
||
|
||
class IDL_DRSUnbind_Request(NDRPacket): | ||
fields_desc = [NDRPacketField("phDrs", NDRContextHandle(), NDRContextHandle)] | ||
|
||
|
||
class IDL_DRSUnbind_Response(NDRPacket): | ||
fields_desc = [ | ||
NDRPacketField("phDrs", NDRContextHandle(), NDRContextHandle), | ||
NDRIntField("status", 0), | ||
] | ||
|
||
|
||
class DRS_MSG_CRACKREQ_V1(NDRPacket): | ||
ALIGNMENT = (4, 8) | ||
fields_desc = [ | ||
NDRIntField("CodePage", 0), | ||
NDRIntField("LocaleId", 0), | ||
NDRIntField("dwFlags", 0), | ||
NDRIntField("formatOffered", 0), | ||
NDRIntField("formatDesired", 0), | ||
NDRIntField("cNames", None, size_of="rpNames"), | ||
NDRFullPointerField( | ||
NDRConfFieldListField( | ||
"rpNames", | ||
[], | ||
NDRFullPointerField( | ||
NDRConfVarStrNullFieldUtf16("rpNames", ""), deferred=True | ||
), | ||
size_is=lambda pkt: pkt.cNames, | ||
), | ||
deferred=True, | ||
), | ||
] | ||
|
||
|
||
class PDS_NAME_RESULT_ITEMW(NDRPacket): | ||
ALIGNMENT = (4, 8) | ||
fields_desc = [ | ||
NDRIntField("status", 0), | ||
NDRFullPointerField(NDRConfVarStrNullFieldUtf16("pDomain", ""), deferred=True), | ||
NDRFullPointerField(NDRConfVarStrNullFieldUtf16("pName", ""), deferred=True), | ||
] | ||
|
||
|
||
class DS_NAME_RESULTW(NDRPacket): | ||
ALIGNMENT = (4, 8) | ||
fields_desc = [ | ||
NDRIntField("cItems", None, size_of="rItems"), | ||
NDRFullPointerField( | ||
NDRConfPacketListField( | ||
"rItems", | ||
[PDS_NAME_RESULT_ITEMW()], | ||
PDS_NAME_RESULT_ITEMW, | ||
size_is=lambda pkt: pkt.cItems, | ||
), | ||
deferred=True, | ||
), | ||
] | ||
|
||
|
||
class DRS_MSG_CRACKREPLY_V1(NDRPacket): | ||
ALIGNMENT = (4, 8) | ||
fields_desc = [ | ||
NDRFullPointerField( | ||
NDRPacketField("pResult", DS_NAME_RESULTW(), DS_NAME_RESULTW), deferred=True | ||
) | ||
] | ||
|
||
|
||
class IDL_DRSCrackNames_Request(NDRPacket): | ||
fields_desc = [ | ||
NDRPacketField("hDrs", NDRContextHandle(), NDRContextHandle), | ||
NDRIntField("dwInVersion", 0), | ||
NDRUnionField( | ||
[ | ||
( | ||
NDRPacketField( | ||
"pmsgIn", DRS_MSG_CRACKREQ_V1(), DRS_MSG_CRACKREQ_V1 | ||
), | ||
( | ||
(lambda pkt: getattr(pkt, "dwInVersion", None) == 1), | ||
(lambda _, val: val.tag == 1), | ||
), | ||
) | ||
], | ||
StrFixedLenField("pmsgIn", "", length=0), | ||
align=(4, 8), | ||
switch_fmt=("L", "L"), | ||
), | ||
] | ||
|
||
|
||
class IDL_DRSCrackNames_Response(NDRPacket): | ||
fields_desc = [ | ||
NDRIntField("pdwOutVersion", 0), | ||
NDRUnionField( | ||
[ | ||
( | ||
NDRPacketField( | ||
"pmsgOut", DRS_MSG_CRACKREPLY_V1(), DRS_MSG_CRACKREPLY_V1 | ||
), | ||
( | ||
(lambda pkt: getattr(pkt, "pdwOutVersion", None) == 1), | ||
(lambda _, val: val.tag == 1), | ||
), | ||
) | ||
], | ||
StrFixedLenField("pmsgOut", "", length=0), | ||
align=(4, 8), | ||
switch_fmt=("L", "L"), | ||
), | ||
NDRIntField("status", 0), | ||
] | ||
|
||
|
||
DRSUAPI_OPNUMS = { | ||
0: DceRpcOp(IDL_DRSBind_Request, IDL_DRSBind_Response), | ||
1: DceRpcOp(IDL_DRSUnbind_Request, IDL_DRSUnbind_Response), | ||
12: DceRpcOp(IDL_DRSCrackNames_Request, IDL_DRSCrackNames_Response), | ||
} | ||
register_dcerpc_interface( | ||
name="drsuapi", | ||
uuid=uuid.UUID("e3514235-4b06-11d1-ab04-00c04fc2dcd2"), | ||
version="4.0", | ||
opnums=DRSUAPI_OPNUMS, | ||
) |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
% MS-DRSR tests | ||
|
||
+ [MS-DRSR] test vectors | ||
|
||
+ Dissect DRSR Crack_Names exchange | ||
|
||
= [EXCH] - Load MSDRSR exchange and decrypt (SPNEGOSSP/NTLMSSP) | ||
|
||
load_layer("msrpce") | ||
bind_layers(TCP, DceRpc5, sport=49685) # the DCE/RPC port | ||
bind_layers(TCP, DceRpc5, dport=49685) | ||
|
||
conf.dcerpc_session_enable = True | ||
conf.winssps_passive = [ | ||
SPNEGOSSP( | ||
[ | ||
NTLMSSP( | ||
IDENTITIES={ | ||
"Administrator": MD4le("Password123!"), | ||
}, | ||
) | ||
] | ||
) | ||
] | ||
pkts = sniff(offline=scapy_path('test/pcaps/dcerpc_msdrsr_cracknames.pcapng.gz'), session=TCPSession) | ||
conf.dcerpc_session_enable = False | ||
|
||
= [EXCH] - Check IDL_DRSBind_Request | ||
|
||
from scapy.layers.msrpce.msdrsr import DRS_EXTENSIONS_INT | ||
|
||
bindreq = pkts[7] | ||
assert IDL_DRSBind_Request in bindreq | ||
ext = DRS_EXTENSIONS_INT(bindreq[IDL_DRSBind_Request].valueof("pextClient").rgb) | ||
assert ext.Pid == 1234 | ||
assert ext.dwReplEpoch == 1729468809 | ||
|
||
= [EXCH] - Check IDL_DRSBind_Response | ||
|
||
import uuid | ||
|
||
bindresp = pkts[8] | ||
assert IDL_DRSBind_Response in bindresp | ||
assert bindresp[IDL_DRSBind_Response].phDrs.uuid == b'\xf4$I\xf5\xde\x0c\xfcO\x8b\xfa\xb0Y\x87\xf4\x11i' | ||
ext = DRS_EXTENSIONS_INT(bindresp[IDL_DRSBind_Response].valueof("ppextServer").rgb) | ||
assert ext.dwFlags.GETCHGREQ_V10 | ||
assert ext.dwFlags == 0x3fffff7f | ||
assert ext.Pid == 696 | ||
assert ext.ConfigObjGuid == uuid.UUID('14ea64e0-3470-48e6-9ace-77012d8d474f') | ||
|
||
= [EXCH] - Check IDL_DRSCrackNames_Request | ||
|
||
cnreq = pkts[9] | ||
assert IDL_DRSCrackNames_Request in cnreq | ||
|
||
crackreq = cnreq[IDL_DRSCrackNames_Request].valueof("pmsgIn") | ||
assert crackreq.formatOffered == 11 | ||
assert crackreq.formatDesired == 0xfffffff2 | ||
|
||
assert crackreq.valueof("rpNames") == [ | ||
b'S-1-5-21-1924137214-3718646274-40215721-522', | ||
b'S-1-5-21-1924137214-3718646274-40215721-498', | ||
b'S-1-5-21-1924137214-3718646274-40215721-516', | ||
b'S-1-5-21-1924137214-3718646274-40215721-526', | ||
b'S-1-5-21-1924137214-3718646274-40215721-527', | ||
b'S-1-5-21-1924137214-3718646274-40215721-512', | ||
b'S-1-5-21-1924137214-3718646274-40215721-519', | ||
b'S-1-5-21-1924137214-3718646274-40215721-513', | ||
] | ||
|
||
= [EXCH] - Check IDL_DRSCrackNames_Response | ||
|
||
cnresp = pkts[10] | ||
assert IDL_DRSCrackNames_Response in cnresp | ||
|
||
crackresp = cnresp[IDL_DRSCrackNames_Response].valueof("pmsgOut") | ||
assert [x.valueof("pName") for x in crackresp.valueof("pResult").valueof("rItems")] == [ | ||
b'Cloneable Domain Controllers@DOMAIN', | ||
b'Enterprise Read-only Domain Controllers@DOMAIN', | ||
b'Domain Controllers@DOMAIN', | ||
b'Key Admins@DOMAIN', | ||
b'Enterprise Key Admins@DOMAIN', | ||
b'Domain Admins@DOMAIN', | ||
b'Enterprise Admins@DOMAIN', | ||
b'Domain Users@DOMAIN', | ||
] | ||
|