diff --git a/scapy/layers/kerberos.py b/scapy/layers/kerberos.py index a282e80998b..a187c39fa3b 100644 --- a/scapy/layers/kerberos.py +++ b/scapy/layers/kerberos.py @@ -146,7 +146,6 @@ ) from scapy.layers.inet import TCP, UDP from scapy.layers.smb import _NV_VERSION -from scapy.layers.smb2 import STATUS_ERREF from scapy.layers.tls.cert import ( Cert, CertList, @@ -161,6 +160,7 @@ Hash_SHA512, ) from scapy.layers.tls.crypto.groups import _ffdh_groups +from scapy.layers.windows.erref import STATUS_ERREF from scapy.layers.x509 import ( _CMS_ENCAPSULATED, CMS_ContentInfo, diff --git a/scapy/layers/ldap.py b/scapy/layers/ldap.py index cdb540ec7da..923c54d9281 100644 --- a/scapy/layers/ldap.py +++ b/scapy/layers/ldap.py @@ -99,7 +99,7 @@ NETLOGON, NETLOGON_SAM_LOGON_RESPONSE_EX, ) -from scapy.layers.smb2 import STATUS_ERREF +from scapy.layers.windows.erref import STATUS_ERREF # Typing imports from typing import ( diff --git a/scapy/layers/msrpce/msnrpc.py b/scapy/layers/msrpce/msnrpc.py index 5933889c2d5..20e2355c18c 100644 --- a/scapy/layers/msrpce/msnrpc.py +++ b/scapy/layers/msrpce/msnrpc.py @@ -37,8 +37,8 @@ from scapy.layers.msrpce.rpcclient import ( DCERPC_Client, DCERPC_Transport, - STATUS_ERREF, ) +from scapy.layers.windows.erref import STATUS_ERREF from scapy.layers.msrpce.raw.ms_nrpc import ( NetrServerAuthenticate3_Request, NetrServerAuthenticate3_Response, @@ -610,7 +610,7 @@ def __init__( def connect(self, host, **kwargs): """ - This calls DCERPC_Client's connect_and_bind to bind the 'logon' interface. + This calls DCERPC_Client's connect to bind the 'logon' interface. """ super(NetlogonClient, self).connect( host=host, diff --git a/scapy/layers/msrpce/mspac.py b/scapy/layers/msrpce/mspac.py index 6185673c804..1a96a9afd13 100644 --- a/scapy/layers/msrpce/mspac.py +++ b/scapy/layers/msrpce/mspac.py @@ -68,7 +68,7 @@ _NTLMPayloadField, _NTLMPayloadPacket, ) -from scapy.layers.smb2 import WINNT_SID +from scapy.layers.windows.security import WINNT_SID # sect 2.4 diff --git a/scapy/layers/msrpce/raw/ms_rrp.py b/scapy/layers/msrpce/raw/ms_rrp.py new file mode 100644 index 00000000000..617b4f555d5 --- /dev/null +++ b/scapy/layers/msrpce/raw/ms_rrp.py @@ -0,0 +1,747 @@ +# SPDX-License-Identifier: GPL-2.0-only +# This file is part of Scapy RPC +# See https://scapy.net/ for more information +# Copyright (C) Gabriel Potter + +# [ms-rrp] v39.0 (Mon, 21 Oct 2024) + +""" +RPC definitions for the following interfaces: +- winreg (v1.0): 338CD001-2244-31F1-AAAA-900038001003 +This file is auto-generated by midl-to-scapy, do not modify. +""" + +import uuid + +from scapy.fields import PacketListField +from scapy.layers.dcerpc import ( + NDRPacket, + DceRpcOp, + NDRByteField, + NDRConfStrLenField, + NDRConfVarPacketListField, + NDRConfVarStrLenField, + NDRConfVarStrLenFieldUtf16, + NDRContextHandle, + NDRFullEmbPointerField, + NDRFullPointerField, + NDRIntField, + NDRPacketField, + NDRShortField, + register_dcerpc_interface, +) + + +class OpenClassesRoot_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenClassesRoot_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class OpenCurrentUser_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenCurrentUser_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class OpenLocalMachine_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenLocalMachine_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class OpenPerformanceData_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenPerformanceData_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class OpenUsers_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenUsers_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class BaseRegCloseKey_Request(NDRPacket): + fields_desc = [NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle)] + + +class BaseRegCloseKey_Response(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class RPC_UNICODE_STRING(NDRPacket): + ALIGNMENT = (4, 8) + fields_desc = [ + NDRShortField("Length", None, size_of="Buffer", adjust=lambda _, x: (x * 2)), + NDRShortField( + "MaximumLength", None, size_of="Buffer", adjust=lambda _, x: (x * 2) + ), + NDRFullEmbPointerField( + NDRConfVarStrLenFieldUtf16( + "Buffer", + "", + size_is=lambda pkt: (pkt.MaximumLength // 2), + length_is=lambda pkt: (pkt.Length // 2), + ) + ), + ] + + +class RPC_SECURITY_DESCRIPTOR(NDRPacket): + ALIGNMENT = (4, 8) + fields_desc = [ + NDRFullEmbPointerField( + NDRConfVarStrLenField( + "lpSecurityDescriptor", + "", + size_is=lambda pkt: pkt.cbInSecurityDescriptor, + length_is=lambda pkt: pkt.cbOutSecurityDescriptor, + ) + ), + NDRIntField("cbInSecurityDescriptor", None, size_of="lpSecurityDescriptor"), + NDRIntField("cbOutSecurityDescriptor", None, size_of="lpSecurityDescriptor"), + ] + + +class PRPC_SECURITY_ATTRIBUTES(NDRPacket): + ALIGNMENT = (4, 8) + fields_desc = [ + NDRIntField("nLength", 0), + NDRPacketField( + "RpcSecurityDescriptor", RPC_SECURITY_DESCRIPTOR(), RPC_SECURITY_DESCRIPTOR + ), + NDRByteField("bInheritHandle", 0), + ] + + +class BaseRegCreateKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRPacketField("lpClass", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRIntField("dwOptions", 0), + NDRIntField("samDesired", 0), + NDRFullPointerField( + NDRPacketField( + "lpSecurityAttributes", + PRPC_SECURITY_ATTRIBUTES(), + PRPC_SECURITY_ATTRIBUTES, + ) + ), + NDRFullPointerField(NDRIntField("lpdwDisposition", 0)), + ] + + +class BaseRegCreateKey_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phkResult", NDRContextHandle(), NDRContextHandle), + NDRFullPointerField(NDRIntField("lpdwDisposition", 0)), + NDRIntField("status", 0), + ] + + +class BaseRegDeleteKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + ] + + +class BaseRegDeleteKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegDeleteValue_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpValueName", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + ] + + +class BaseRegDeleteValue_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class PFILETIME(NDRPacket): + ALIGNMENT = (4, 4) + fields_desc = [NDRIntField("dwLowDateTime", 0), NDRIntField("dwHighDateTime", 0)] + + +class PRPC_UNICODE_STRING(NDRPacket): + ALIGNMENT = (4, 8) + fields_desc = [ + NDRShortField("Length", None, size_of="Buffer", adjust=lambda _, x: (x * 2)), + NDRShortField( + "MaximumLength", None, size_of="Buffer", adjust=lambda _, x: (x * 2) + ), + NDRFullEmbPointerField( + NDRConfVarStrLenFieldUtf16( + "Buffer", + "", + size_is=lambda pkt: (pkt.MaximumLength // 2), + length_is=lambda pkt: (pkt.Length // 2), + ) + ), + ] + + +class BaseRegEnumKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("dwIndex", 0), + NDRPacketField("lpNameIn", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRFullPointerField( + NDRPacketField("lpClassIn", RPC_UNICODE_STRING(), RPC_UNICODE_STRING) + ), + NDRFullPointerField( + NDRPacketField("lpftLastWriteTime", PFILETIME(), PFILETIME) + ), + ] + + +class BaseRegEnumKey_Response(NDRPacket): + fields_desc = [ + NDRPacketField("lpNameOut", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRFullPointerField( + NDRPacketField("lplpClassOut", PRPC_UNICODE_STRING(), PRPC_UNICODE_STRING) + ), + NDRFullPointerField( + NDRPacketField("lpftLastWriteTime", PFILETIME(), PFILETIME) + ), + NDRIntField("status", 0), + ] + + +class BaseRegEnumValue_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("dwIndex", 0), + NDRPacketField("lpValueNameIn", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRFullPointerField(NDRIntField("lpType", 0)), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpData", + "", + size_is=lambda pkt: (pkt.lpcbData if pkt.lpcbData else 0), + max_is=lambda pkt: 67108864, + length_is=lambda pkt: (pkt.lpcbLen if pkt.lpcbLen else 0), + ) + ), + NDRFullPointerField(NDRIntField("lpcbData", 0)), + NDRFullPointerField(NDRIntField("lpcbLen", 0)), + ] + + +class BaseRegEnumValue_Response(NDRPacket): + fields_desc = [ + NDRPacketField("lpValueNameOut", PRPC_UNICODE_STRING(), PRPC_UNICODE_STRING), + NDRFullPointerField(NDRIntField("lpType", 0)), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpData", + "", + size_is=lambda pkt: (pkt.lpcbData if pkt.lpcbData else 0), + max_is=lambda pkt: 67108864, + length_is=lambda pkt: (pkt.lpcbLen if pkt.lpcbLen else 0), + ) + ), + NDRFullPointerField(NDRIntField("lpcbData", 0)), + NDRFullPointerField(NDRIntField("lpcbLen", 0)), + NDRIntField("status", 0), + ] + + +class BaseRegFlushKey_Request(NDRPacket): + fields_desc = [NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle)] + + +class BaseRegFlushKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class PRPC_SECURITY_DESCRIPTOR(NDRPacket): + ALIGNMENT = (4, 8) + fields_desc = [ + NDRFullEmbPointerField( + NDRConfVarStrLenField( + "lpSecurityDescriptor", + "", + size_is=lambda pkt: pkt.cbInSecurityDescriptor, + length_is=lambda pkt: pkt.cbOutSecurityDescriptor, + ) + ), + NDRIntField("cbInSecurityDescriptor", None, size_of="lpSecurityDescriptor"), + NDRIntField("cbOutSecurityDescriptor", None, size_of="lpSecurityDescriptor"), + ] + + +class BaseRegGetKeySecurity_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("SecurityInformation", 0), + NDRPacketField( + "pRpcSecurityDescriptorIn", + PRPC_SECURITY_DESCRIPTOR(), + PRPC_SECURITY_DESCRIPTOR, + ), + ] + + +class BaseRegGetKeySecurity_Response(NDRPacket): + fields_desc = [ + NDRPacketField( + "pRpcSecurityDescriptorOut", + PRPC_SECURITY_DESCRIPTOR(), + PRPC_SECURITY_DESCRIPTOR, + ), + NDRIntField("status", 0), + ] + + +class BaseRegLoadKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRPacketField("lpFile", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + ] + + +class BaseRegLoadKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegOpenKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRIntField("dwOptions", 0), + NDRIntField("samDesired", 0), + ] + + +class BaseRegOpenKey_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phkResult", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class BaseRegQueryInfoKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpClassIn", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + ] + + +class BaseRegQueryInfoKey_Response(NDRPacket): + fields_desc = [ + NDRPacketField("lpClassOut", PRPC_UNICODE_STRING(), PRPC_UNICODE_STRING), + NDRIntField("lpcSubKeys", 0), + NDRIntField("lpcbMaxSubKeyLen", 0), + NDRIntField("lpcbMaxClassLen", 0), + NDRIntField("lpcValues", 0), + NDRIntField("lpcbMaxValueNameLen", 0), + NDRIntField("lpcbMaxValueLen", 0), + NDRIntField("lpcbSecurityDescriptor", 0), + NDRPacketField("lpftLastWriteTime", PFILETIME(), PFILETIME), + NDRIntField("status", 0), + ] + + +class BaseRegQueryValue_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpValueName", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRFullPointerField(NDRIntField("lpType", 0)), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpData", + "", + size_is=lambda pkt: (pkt.lpcbData if pkt.lpcbData else 0), + max_is=lambda pkt: 67108864, + length_is=lambda pkt: (pkt.lpcbLen if pkt.lpcbLen else 0), + ) + ), + NDRFullPointerField(NDRIntField("lpcbData", 0)), + NDRFullPointerField(NDRIntField("lpcbLen", 0)), + ] + + +class BaseRegQueryValue_Response(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRIntField("lpType", 0)), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpData", + "", + size_is=lambda pkt: (pkt.lpcbData if pkt.lpcbData else 0), + max_is=lambda pkt: 67108864, + length_is=lambda pkt: (pkt.lpcbLen if pkt.lpcbLen else 0), + ) + ), + NDRFullPointerField(NDRIntField("lpcbData", 0)), + NDRFullPointerField(NDRIntField("lpcbLen", 0)), + NDRIntField("status", 0), + ] + + +class BaseRegReplaceKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRPacketField("lpNewFile", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRPacketField("lpOldFile", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + ] + + +class BaseRegReplaceKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegRestoreKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpFile", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRIntField("Flags", 0), + ] + + +class BaseRegRestoreKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegSaveKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpFile", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRFullPointerField( + NDRPacketField( + "pSecurityAttributes", + PRPC_SECURITY_ATTRIBUTES(), + PRPC_SECURITY_ATTRIBUTES, + ) + ), + ] + + +class BaseRegSaveKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegSetKeySecurity_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("SecurityInformation", 0), + NDRPacketField( + "pRpcSecurityDescriptor", + PRPC_SECURITY_DESCRIPTOR(), + PRPC_SECURITY_DESCRIPTOR, + ), + ] + + +class BaseRegSetKeySecurity_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegSetValue_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpValueName", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRIntField("dwType", 0), + NDRConfStrLenField("lpData", "", size_is=lambda pkt: pkt.cbData), + NDRIntField("cbData", None, size_of="lpData"), + ] + + +class BaseRegSetValue_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegUnLoadKey_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + ] + + +class BaseRegUnLoadKey_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class BaseRegGetVersion_Request(NDRPacket): + fields_desc = [NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle)] + + +class BaseRegGetVersion_Response(NDRPacket): + fields_desc = [NDRIntField("lpdwVersion", 0), NDRIntField("status", 0)] + + +class OpenCurrentConfig_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenCurrentConfig_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class PRVALENT(NDRPacket): + ALIGNMENT = (4, 8) + fields_desc = [ + NDRFullEmbPointerField( + NDRPacketField("ve_valuename", PRPC_UNICODE_STRING(), PRPC_UNICODE_STRING) + ), + NDRIntField("ve_valuelen", 0), + NDRFullEmbPointerField(NDRIntField("ve_valueptr", 0)), + NDRIntField("ve_type", 0), + ] + + +class BaseRegQueryMultipleValues_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRConfVarPacketListField( + "val_listIn", + [], + PRVALENT, + size_is=lambda pkt: pkt.num_vals, + length_is=lambda pkt: pkt.num_vals, + ), + NDRIntField("num_vals", None, size_of="val_listIn"), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpvalueBuf", + "", + size_is=lambda pkt: pkt.ldwTotsize, + length_is=lambda pkt: pkt.ldwTotsize, + ) + ), + NDRIntField("ldwTotsize", None, size_of="lpvalueBuf"), + ] + + +class BaseRegQueryMultipleValues_Response(NDRPacket): + fields_desc = [ + NDRConfVarPacketListField( + "val_listOut", + [], + PRVALENT, + size_is=lambda pkt: pkt.num_vals, + length_is=lambda pkt: pkt.num_vals, + ), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpvalueBuf", + "", + size_is=lambda pkt: pkt.ldwTotsize, + length_is=lambda pkt: pkt.ldwTotsize, + ) + ), + NDRIntField("ldwTotsize", None, size_of="lpvalueBuf"), + NDRIntField("status", 0), + ] + + +class BaseRegSaveKeyEx_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpFile", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRFullPointerField( + NDRPacketField( + "pSecurityAttributes", + PRPC_SECURITY_ATTRIBUTES(), + PRPC_SECURITY_ATTRIBUTES, + ) + ), + NDRIntField("Flags", 0), + ] + + +class BaseRegSaveKeyEx_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +class OpenPerformanceText_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenPerformanceText_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class OpenPerformanceNlsText_Request(NDRPacket): + fields_desc = [ + NDRFullPointerField(NDRShortField("ServerName", 0)), + NDRIntField("samDesired", 0), + ] + + +class OpenPerformanceNlsText_Response(NDRPacket): + fields_desc = [ + NDRPacketField("phKey", NDRContextHandle(), NDRContextHandle), + NDRIntField("status", 0), + ] + + +class BaseRegQueryMultipleValues2_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRConfVarPacketListField( + "val_listIn", + [], + PRVALENT, + size_is=lambda pkt: pkt.num_vals, + length_is=lambda pkt: pkt.num_vals, + ), + NDRIntField("num_vals", None, size_of="val_listIn"), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpvalueBuf", + "", + size_is=lambda pkt: pkt.ldwTotsize, + length_is=lambda pkt: pkt.ldwTotsize, + ) + ), + NDRIntField("ldwTotsize", None, size_of="lpvalueBuf"), + ] + + +class BaseRegQueryMultipleValues2_Response(NDRPacket): + fields_desc = [ + NDRConfVarPacketListField( + "val_listOut", + [], + PRVALENT, + size_is=lambda pkt: pkt.num_vals, + length_is=lambda pkt: pkt.num_vals, + ), + NDRFullPointerField( + NDRConfVarStrLenField( + "lpvalueBuf", + "", + size_is=lambda pkt: pkt.ldwTotsize, + length_is=lambda pkt: pkt.ldwTotsize, + ) + ), + NDRIntField("ldwRequiredSize", 0), + NDRIntField("status", 0), + ] + + +class BaseRegDeleteKeyEx_Request(NDRPacket): + fields_desc = [ + NDRPacketField("hKey", NDRContextHandle(), NDRContextHandle), + NDRPacketField("lpSubKey", RPC_UNICODE_STRING(), RPC_UNICODE_STRING), + NDRIntField("AccessMask", 0), + NDRIntField("Reserved", 0), + ] + + +class BaseRegDeleteKeyEx_Response(NDRPacket): + fields_desc = [NDRIntField("status", 0)] + + +WINREG_OPNUMS = { + 0: DceRpcOp(OpenClassesRoot_Request, OpenClassesRoot_Response), + 1: DceRpcOp(OpenCurrentUser_Request, OpenCurrentUser_Response), + 2: DceRpcOp(OpenLocalMachine_Request, OpenLocalMachine_Response), + 3: DceRpcOp(OpenPerformanceData_Request, OpenPerformanceData_Response), + 4: DceRpcOp(OpenUsers_Request, OpenUsers_Response), + 5: DceRpcOp(BaseRegCloseKey_Request, BaseRegCloseKey_Response), + 6: DceRpcOp(BaseRegCreateKey_Request, BaseRegCreateKey_Response), + 7: DceRpcOp(BaseRegDeleteKey_Request, BaseRegDeleteKey_Response), + 8: DceRpcOp(BaseRegDeleteValue_Request, BaseRegDeleteValue_Response), + 9: DceRpcOp(BaseRegEnumKey_Request, BaseRegEnumKey_Response), + 10: DceRpcOp(BaseRegEnumValue_Request, BaseRegEnumValue_Response), + 11: DceRpcOp(BaseRegFlushKey_Request, BaseRegFlushKey_Response), + 12: DceRpcOp(BaseRegGetKeySecurity_Request, BaseRegGetKeySecurity_Response), + 13: DceRpcOp(BaseRegLoadKey_Request, BaseRegLoadKey_Response), + # 14: Opnum14NotImplemented, + 15: DceRpcOp(BaseRegOpenKey_Request, BaseRegOpenKey_Response), + 16: DceRpcOp(BaseRegQueryInfoKey_Request, BaseRegQueryInfoKey_Response), + 17: DceRpcOp(BaseRegQueryValue_Request, BaseRegQueryValue_Response), + 18: DceRpcOp(BaseRegReplaceKey_Request, BaseRegReplaceKey_Response), + 19: DceRpcOp(BaseRegRestoreKey_Request, BaseRegRestoreKey_Response), + 20: DceRpcOp(BaseRegSaveKey_Request, BaseRegSaveKey_Response), + 21: DceRpcOp(BaseRegSetKeySecurity_Request, BaseRegSetKeySecurity_Response), + 22: DceRpcOp(BaseRegSetValue_Request, BaseRegSetValue_Response), + 23: DceRpcOp(BaseRegUnLoadKey_Request, BaseRegUnLoadKey_Response), + # 24: Opnum24NotImplemented, + # 25: Opnum25NotImplemented, + 26: DceRpcOp(BaseRegGetVersion_Request, BaseRegGetVersion_Response), + 27: DceRpcOp(OpenCurrentConfig_Request, OpenCurrentConfig_Response), + # 28: Opnum28NotImplemented, + 29: DceRpcOp( + BaseRegQueryMultipleValues_Request, BaseRegQueryMultipleValues_Response + ), + # 30: Opnum30NotImplemented, + 31: DceRpcOp(BaseRegSaveKeyEx_Request, BaseRegSaveKeyEx_Response), + 32: DceRpcOp(OpenPerformanceText_Request, OpenPerformanceText_Response), + 33: DceRpcOp(OpenPerformanceNlsText_Request, OpenPerformanceNlsText_Response), + 34: DceRpcOp( + BaseRegQueryMultipleValues2_Request, BaseRegQueryMultipleValues2_Response + ), + 35: DceRpcOp(BaseRegDeleteKeyEx_Request, BaseRegDeleteKeyEx_Response), +} +register_dcerpc_interface( + name="winreg", + uuid=uuid.UUID("338CD001-2244-31F1-AAAA-900038001003"), + version="1.0", + opnums=WINREG_OPNUMS, +) diff --git a/scapy/layers/msrpce/rpcclient.py b/scapy/layers/msrpce/rpcclient.py index 17fc07ca006..2e0454340a5 100644 --- a/scapy/layers/msrpce/rpcclient.py +++ b/scapy/layers/msrpce/rpcclient.py @@ -50,10 +50,10 @@ GSS_S_CONTINUE_NEEDED, GSS_C_FLAGS, ) -from scapy.layers.smb2 import STATUS_ERREF from scapy.layers.smbclient import ( SMB_RPC_SOCKET, ) +from scapy.layers.windows.erref import STATUS_ERREF # RPC from scapy.layers.msrpce.ept import ( @@ -331,6 +331,7 @@ def sr1_req(self, pkt, **kwargs): print( conf.color_theme.opening(">> REQUEST: %s" % pkt.__class__.__name__) ) + # Add sectrailer if first time talking on this interface vt_trailer = b"" if ( @@ -400,6 +401,7 @@ def sr1_req(self, pkt, **kwargs): ): resp[DceRpc5Fault].payload.show() result = resp + if self.verb and getattr(resp, "status", 0) != 0: if resp.status in _DCE_RPC_ERROR_CODES: print(conf.color_theme.fail(f"! {_DCE_RPC_ERROR_CODES[resp.status]}")) diff --git a/scapy/layers/smb.py b/scapy/layers/smb.py index ded79f15a4d..cf2ee2e868a 100644 --- a/scapy/layers/smb.py +++ b/scapy/layers/smb.py @@ -66,11 +66,11 @@ GSSAPI_BLOB, ) from scapy.layers.smb2 import ( - STATUS_ERREF, SMB2_Compression_Transform_Header, SMB2_Header, SMB2_Transform_Header, ) +from scapy.layers.windows.erref import STATUS_ERREF SMB_COM = { diff --git a/scapy/layers/smb2.py b/scapy/layers/smb2.py index fcfb3702b26..ba6a9292e19 100644 --- a/scapy/layers/smb2.py +++ b/scapy/layers/smb2.py @@ -15,7 +15,6 @@ import functools import hashlib import os -import re import struct from scapy.automaton import select_objects @@ -28,7 +27,6 @@ ConditionalField, FieldLenField, FieldListField, - FlagValue, FlagsField, IP6Field, IPField, @@ -77,6 +75,7 @@ _NTLM_ENUM, _NTLM_post_build, ) +from scapy.layers.windows.erref import STATUS_ERREF # EnumField @@ -89,62 +88,6 @@ 0x0311: "SMB 3.1.1", } -# SMB2 sect 3.3.5.15 + [MS-ERREF] -STATUS_ERREF = { - 0x00000000: "STATUS_SUCCESS", - 0x00000002: "ERROR_FILE_NOT_FOUND", - 0x00000005: "ERROR_ACCESS_DENIED", - 0x00000103: "STATUS_PENDING", - 0x0000010B: "STATUS_NOTIFY_CLEANUP", - 0x0000010C: "STATUS_NOTIFY_ENUM_DIR", - 0x00000532: "ERROR_PASSWORD_EXPIRED", - 0x00000533: "ERROR_ACCOUNT_DISABLED", - 0x000006FE: "ERROR_TRUST_FAILURE", - 0x80000005: "STATUS_BUFFER_OVERFLOW", - 0x80000006: "STATUS_NO_MORE_FILES", - 0x8000002D: "STATUS_STOPPED_ON_SYMLINK", - 0x80070005: "E_ACCESSDENIED", - 0x8007000E: "E_OUTOFMEMORY", - 0x80090308: "SEC_E_INVALID_TOKEN", - 0x8009030C: "SEC_E_LOGON_DENIED", - 0x8009030F: "SEC_E_MESSAGE_ALTERED", - 0x80090310: "SEC_E_OUT_OF_SEQUENCE", - 0x80090346: "SEC_E_BAD_BINDINGS", - 0x80090351: "SEC_E_SMARTCARD_CERT_REVOKED", - 0xC0000003: "STATUS_INVALID_INFO_CLASS", - 0xC0000004: "STATUS_INFO_LENGTH_MISMATCH", - 0xC000000D: "STATUS_INVALID_PARAMETER", - 0xC000000F: "STATUS_NO_SUCH_FILE", - 0xC0000016: "STATUS_MORE_PROCESSING_REQUIRED", - 0xC0000022: "STATUS_ACCESS_DENIED", - 0xC0000033: "STATUS_OBJECT_NAME_INVALID", - 0xC0000034: "STATUS_OBJECT_NAME_NOT_FOUND", - 0xC0000043: "STATUS_SHARING_VIOLATION", - 0xC0000061: "STATUS_PRIVILEGE_NOT_HELD", - 0xC0000064: "STATUS_NO_SUCH_USER", - 0xC000006D: "STATUS_LOGON_FAILURE", - 0xC000006E: "STATUS_ACCOUNT_RESTRICTION", - 0xC0000070: "STATUS_INVALID_WORKSTATION", - 0xC0000071: "STATUS_PASSWORD_EXPIRED", - 0xC0000072: "STATUS_ACCOUNT_DISABLED", - 0xC000009A: "STATUS_INSUFFICIENT_RESOURCES", - 0xC00000BA: "STATUS_FILE_IS_A_DIRECTORY", - 0xC00000BB: "STATUS_NOT_SUPPORTED", - 0xC00000C9: "STATUS_NETWORK_NAME_DELETED", - 0xC00000CC: "STATUS_BAD_NETWORK_NAME", - 0xC0000120: "STATUS_CANCELLED", - 0xC0000122: "STATUS_INVALID_COMPUTER_NAME", - 0xC0000128: "STATUS_FILE_CLOSED", # backup error for older Win versions - 0xC000015B: "STATUS_LOGON_TYPE_NOT_GRANTED", - 0xC000018B: "STATUS_NO_TRUST_SAM_ACCOUNT", - 0xC000019C: "STATUS_FS_DRIVER_REQUIRED", - 0xC0000203: "STATUS_USER_SESSION_DELETED", - 0xC000020C: "STATUS_CONNECTION_DISCONNECTED", - 0xC0000225: "STATUS_NOT_FOUND", - 0xC0000257: "STATUS_PATH_NOT_COVERED", - 0xC000035C: "STATUS_NETWORK_SESSION_EXPIRED", -} - # SMB2 sect 2.1.2.1 REPARSE_TAGS = { 0x00000000: "IO_REPARSE_TAG_RESERVED_ZERO", @@ -767,849 +710,6 @@ class FileStreamInformation(Packet): ] -# [MS-DTYP] sect 2.4.1 - - -class WINNT_SID_IDENTIFIER_AUTHORITY(Packet): - fields_desc = [ - StrFixedLenField("Value", b"\x00\x00\x00\x00\x00\x01", length=6), - ] - - def default_payload_class(self, payload): - return conf.padding_layer - - -# [MS-DTYP] sect 2.4.2 - - -class WINNT_SID(Packet): - fields_desc = [ - ByteField("Revision", 1), - FieldLenField("SubAuthorityCount", None, count_of="SubAuthority", fmt="B"), - PacketField( - "IdentifierAuthority", - WINNT_SID_IDENTIFIER_AUTHORITY(), - WINNT_SID_IDENTIFIER_AUTHORITY, - ), - FieldListField( - "SubAuthority", - [0], - LEIntField("", 0), - count_from=lambda pkt: pkt.SubAuthorityCount, - ), - ] - - def default_payload_class(self, payload): - return conf.padding_layer - - _SID_REG = re.compile(r"^S-(\d)-(\d+)((?:-\d+)*)$") - - @staticmethod - def fromstr(x): - m = WINNT_SID._SID_REG.match(x) - if not m: - raise ValueError("Invalid SID format !") - rev, authority, subauthority = m.groups() - return WINNT_SID( - Revision=int(rev), - IdentifierAuthority=WINNT_SID_IDENTIFIER_AUTHORITY( - Value=struct.pack(">Q", int(authority))[2:] - ), - SubAuthority=[int(x) for x in subauthority[1:].split("-")], - ) - - def summary(self): - return "S-%s-%s%s" % ( - self.Revision, - struct.unpack(">Q", b"\x00\x00" + self.IdentifierAuthority.Value)[0], - ( - ("-%s" % "-".join(str(x) for x in self.SubAuthority)) - if self.SubAuthority - else "" - ), - ) - - -# https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers - -WELL_KNOWN_SIDS = { - # Universal well-known SID - "S-1-0-0": "Null SID", - "S-1-1-0": "Everyone", - "S-1-2-0": "Local", - "S-1-2-1": "Console Logon", - "S-1-3-0": "Creator Owner ID", - "S-1-3-1": "Creator Group ID", - "S-1-3-2": "Owner Server", - "S-1-3-3": "Group Server", - "S-1-3-4": "Owner Rights", - "S-1-4": "Non-unique Authority", - "S-1-5": "NT Authority", - "S-1-5-80-0": "All Services", - # NT well-known SIDs - "S-1-5-1": "Dialup", - "S-1-5-113": "Local account", - "S-1-5-114": "Local account and member of Administrators group", - "S-1-5-2": "Network", - "S-1-5-3": "Batch", - "S-1-5-4": "Interactive", - "S-1-5-6": "Service", - "S-1-5-7": "Anonymous Logon", - "S-1-5-8": "Proxy", - "S-1-5-9": "Enterprise Domain Controllers", - "S-1-5-10": "Self", - "S-1-5-11": "Authenticated Users", - "S-1-5-12": "Restricted Code", - "S-1-5-13": "Terminal Server User", - "S-1-5-14": "Remote Interactive Logon", - "S-1-5-15": "This Organization", - "S-1-5-17": "IUSR", - "S-1-5-18": "System (or LocalSystem)", - "S-1-5-19": "NT Authority (LocalService)", - "S-1-5-20": "Network Service", - "S-1-5-32-544": "Administrators", - "S-1-5-32-545": "Users", - "S-1-5-32-546": "Guests", - "S-1-5-32-547": "Power Users", - "S-1-5-32-548": "Account Operators", - "S-1-5-32-549": "Server Operators", - "S-1-5-32-550": "Print Operators", - "S-1-5-32-551": "Backup Operators", - "S-1-5-32-552": "Replicators", - "S-1-5-32-554": r"Builtin\Pre-Windows 2000 Compatible Access", - "S-1-5-32-555": r"Builtin\Remote Desktop Users", - "S-1-5-32-556": r"Builtin\Network Configuration Operators", - "S-1-5-32-557": r"Builtin\Incoming Forest Trust Builders", - "S-1-5-32-558": r"Builtin\Performance Monitor Users", - "S-1-5-32-559": r"Builtin\Performance Log Users", - "S-1-5-32-560": r"Builtin\Windows Authorization Access Group", - "S-1-5-32-561": r"Builtin\Terminal Server License Servers", - "S-1-5-32-562": r"Builtin\Distributed COM Users", - "S-1-5-32-568": r"Builtin\IIS_IUSRS", - "S-1-5-32-569": r"Builtin\Cryptographic Operators", - "S-1-5-32-573": r"Builtin\Event Log Readers", - "S-1-5-32-574": r"Builtin\Certificate Service DCOM Access", - "S-1-5-32-575": r"Builtin\RDS Remote Access Servers", - "S-1-5-32-576": r"Builtin\RDS Endpoint Servers", - "S-1-5-32-577": r"Builtin\RDS Management Servers", - "S-1-5-32-578": r"Builtin\Hyper-V Administrators", - "S-1-5-32-579": r"Builtin\Access Control Assistance Operators", - "S-1-5-32-580": r"Builtin\Remote Management Users", - "S-1-5-32-581": r"Builtin\Default Account", - "S-1-5-32-582": r"Builtin\Storage Replica Admins", - "S-1-5-32-583": r"Builtin\Device Owners", - "S-1-5-64-10": "NTLM Authentication", - "S-1-5-64-14": "SChannel Authentication", - "S-1-5-64-21": "Digest Authentication", - "S-1-5-80": "NT Service", - "S-1-5-80-0": "All Services", - "S-1-5-83-0": r"NT VIRTUAL MACHINE\Virtual Machines", -} - - -# [MS-DTYP] sect 2.4.3 - -_WINNT_ACCESS_MASK = { - 0x80000000: "GENERIC_READ", - 0x40000000: "GENERIC_WRITE", - 0x20000000: "GENERIC_EXECUTE", - 0x10000000: "GENERIC_ALL", - 0x02000000: "MAXIMUM_ALLOWED", - 0x01000000: "ACCESS_SYSTEM_SECURITY", - 0x00100000: "SYNCHRONIZE", - 0x00080000: "WRITE_OWNER", - 0x00040000: "WRITE_DACL", - 0x00020000: "READ_CONTROL", - 0x00010000: "DELETE", -} - - -# [MS-DTYP] sect 2.4.4.1 - - -WINNT_ACE_FLAGS = { - 0x01: "OBJECT_INHERIT", - 0x02: "CONTAINER_INHERIT", - 0x04: "NO_PROPAGATE_INHERIT", - 0x08: "INHERIT_ONLY", - 0x10: "INHERITED_ACE", - 0x40: "SUCCESSFUL_ACCESS", - 0x80: "FAILED_ACCESS", -} - - -class WINNT_ACE_HEADER(Packet): - fields_desc = [ - ByteEnumField( - "AceType", - 0, - { - 0x00: "ACCESS_ALLOWED", - 0x01: "ACCESS_DENIED", - 0x02: "SYSTEM_AUDIT", - 0x03: "SYSTEM_ALARM", - 0x04: "ACCESS_ALLOWED_COMPOUND", - 0x05: "ACCESS_ALLOWED_OBJECT", - 0x06: "ACCESS_DENIED_OBJECT", - 0x07: "SYSTEM_AUDIT_OBJECT", - 0x08: "SYSTEM_ALARM_OBJECT", - 0x09: "ACCESS_ALLOWED_CALLBACK", - 0x0A: "ACCESS_DENIED_CALLBACK", - 0x0B: "ACCESS_ALLOWED_CALLBACK_OBJECT", - 0x0C: "ACCESS_DENIED_CALLBACK_OBJECT", - 0x0D: "SYSTEM_AUDIT_CALLBACK", - 0x0E: "SYSTEM_ALARM_CALLBACK", - 0x0F: "SYSTEM_AUDIT_CALLBACK_OBJECT", - 0x10: "SYSTEM_ALARM_CALLBACK_OBJECT", - 0x11: "SYSTEM_MANDATORY_LABEL", - 0x12: "SYSTEM_RESOURCE_ATTRIBUTE", - 0x13: "SYSTEM_SCOPED_POLICY_ID", - }, - ), - FlagsField( - "AceFlags", - 0, - 8, - WINNT_ACE_FLAGS, - ), - LenField("AceSize", None, fmt=" conditional expression - cond_expr = None - if hasattr(self.payload, "ApplicationData"): - # Parse tokens - res = [] - for ct in self.payload.ApplicationData.Tokens: - if ct.TokenType in [ - # binary operators - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x88, 0x8e, 0x8f, - 0xa0, 0xa1 - ]: - t1 = res.pop(-1) - t0 = res.pop(-1) - tt = ct.sprintf("%TokenType%") - if ct.TokenType in [0xa0, 0xa1]: # && and || - res.append(f"({t0}) {tt} ({t1})") - else: - res.append(f"{t0} {tt} {t1}") - elif ct.TokenType in [ - # unary operators - 0x87, 0x8d, 0xa2, 0x89, 0x8a, 0x8b, 0x8c, 0x91, 0x92, 0x93 - ]: - t0 = res.pop(-1) - tt = ct.sprintf("%TokenType%") - res.append(f"{tt}{t0}") - elif ct.TokenType in [ - # values - 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0x50, 0x51, 0xf8, 0xf9, - 0xfa, 0xfb - ]: - def lit(ct): - if ct.TokenType in [0x10, 0x18]: # literal strings - return '"%s"' % ct.value - elif ct.TokenType == 0x50: # composite - return "({%s})" % ",".join(lit(x) for x in ct.value) - else: - return str(ct.value) - res.append(lit(ct)) - elif ct.TokenType == 0x00: # padding - pass - else: - raise ValueError("Unhandled token type %s" % ct.TokenType) - if len(res) != 1: - raise ValueError("Incomplete SDDL !") - cond_expr = "(%s)" % res[0] - return { - "ace-flags-string": ace_flag_string, - "sid-string": sid_string, - "mask": mask, - "object-guid": object_guid, - "inherited-object-guid": inherit_object_guid, - "cond-expr": cond_expr, - } - # fmt: on - - def toSDDL(self, accessMask=None): - """ - Return SDDL - """ - data = self.extractData(accessMask=accessMask) - ace_rights = "" # TODO - if self.AceType in [0x9, 0xA, 0xB, 0xD]: # Conditional ACE - conditional_ace_type = { - 0x09: "XA", - 0x0A: "XD", - 0x0B: "XU", - 0x0D: "ZA", - }[self.AceType] - return "D:(%s)" % ( - ";".join( - x - for x in [ - conditional_ace_type, - data["ace-flags-string"], - ace_rights, - str(data["object-guid"]), - str(data["inherited-object-guid"]), - data["sid-string"], - data["cond-expr"], - ] - if x is not None - ) - ) - else: - ace_type = { - 0x00: "A", - 0x01: "D", - 0x02: "AU", - 0x05: "OA", - 0x06: "OD", - 0x07: "OU", - 0x11: "ML", - 0x13: "SP", - }[self.AceType] - return "(%s)" % ( - ";".join( - x - for x in [ - ace_type, - data["ace-flags-string"], - ace_rights, - str(data["object-guid"]), - str(data["inherited-object-guid"]), - data["sid-string"], - data["cond-expr"], - ] - if x is not None - ) - ) - - -# [MS-DTYP] sect 2.4.4.2 - - -class WINNT_ACCESS_ALLOWED_ACE(Packet): - fields_desc = [ - FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK), - PacketField("Sid", WINNT_SID(), WINNT_SID), - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_ACE, AceType=0x00) - - -# [MS-DTYP] sect 2.4.4.3 - - -class WINNT_ACCESS_ALLOWED_OBJECT_ACE(Packet): - fields_desc = [ - FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK), - FlagsField( - "Flags", - 0, - -32, - { - 0x00000001: "OBJECT_TYPE_PRESENT", - 0x00000002: "INHERITED_OBJECT_TYPE_PRESENT", - }, - ), - ConditionalField( - UUIDField("ObjectType", None, uuid_fmt=UUIDField.FORMAT_LE), - lambda pkt: pkt.Flags.OBJECT_TYPE_PRESENT, - ), - ConditionalField( - UUIDField("InheritedObjectType", None, uuid_fmt=UUIDField.FORMAT_LE), - lambda pkt: pkt.Flags.INHERITED_OBJECT_TYPE_PRESENT, - ), - PacketField("Sid", WINNT_SID(), WINNT_SID), - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_OBJECT_ACE, AceType=0x05) - - -# [MS-DTYP] sect 2.4.4.4 - - -class WINNT_ACCESS_DENIED_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_ACE, AceType=0x01) - - -# [MS-DTYP] sect 2.4.4.5 - - -class WINNT_ACCESS_DENIED_OBJECT_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_OBJECT_ACE, AceType=0x06) - - -# [MS-DTYP] sect 2.4.4.17.4+ - - -class WINNT_APPLICATION_DATA_LITERAL_TOKEN(Packet): - def default_payload_class(self, payload): - return conf.padding_layer - - -# fmt: off -WINNT_APPLICATION_DATA_LITERAL_TOKEN.fields_desc = [ - ByteEnumField( - "TokenType", - 0, - { - # [MS-DTYP] sect 2.4.4.17.5 - 0x00: "Padding token", - 0x01: "Signed int8", - 0x02: "Signed int16", - 0x03: "Signed int32", - 0x04: "Signed int64", - 0x10: "Unicode", - 0x18: "Octet String", - 0x50: "Composite", - 0x51: "SID", - # [MS-DTYP] sect 2.4.4.17.6 - 0x80: "==", - 0x81: "!=", - 0x82: "<", - 0x83: "<=", - 0x84: ">", - 0x85: ">=", - 0x86: "Contains", - 0x88: "Any_of", - 0x8e: "Not_Contains", - 0x8f: "Not_Any_of", - 0x89: "Member_of", - 0x8a: "Device_Member_of", - 0x8b: "Member_of_Any", - 0x8c: "Device_Member_of_Any", - 0x90: "Not_Member_of", - 0x91: "Not_Device_Member_of", - 0x92: "Not_Member_of_Any", - 0x93: "Not_Device_Member_of_Any", - # [MS-DTYP] sect 2.4.4.17.7 - 0x87: "Exists", - 0x8d: "Not_Exists", - 0xa0: "&&", - 0xa1: "||", - 0xa2: "!", - # [MS-DTYP] sect 2.4.4.17.8 - 0xf8: "Local attribute", - 0xf9: "User Attribute", - 0xfa: "Resource Attribute", - 0xfb: "Device Attribute", - } - ), - ConditionalField( - # Strings - LEIntField("length", 0), - lambda pkt: pkt.TokenType in [ - 0x10, # Unicode string - 0x18, # Octet string - 0xf8, 0xf9, 0xfa, 0xfb, # Attribute tokens - 0x50, # Composite - ] - ), - ConditionalField( - MultipleTypeField( - [ - ( - LELongField("value", 0), - lambda pkt: pkt.TokenType in [ - 0x01, # signed int8 - 0x02, # signed int16 - 0x03, # signed int32 - 0x04, # signed int64 - ] - ), - ( - StrLenFieldUtf16("value", b"", length_from=lambda pkt: pkt.length), - lambda pkt: pkt.TokenType in [ - 0x10, # Unicode string - 0xf8, 0xf9, 0xfa, 0xfb, # Attribute tokens - ] - ), - ( - StrLenField("value", b"", length_from=lambda pkt: pkt.length), - lambda pkt: pkt.TokenType == 0x18, # Octet string - ), - ( - PacketListField("value", [], WINNT_APPLICATION_DATA_LITERAL_TOKEN, - length_from=lambda pkt: pkt.length), - lambda pkt: pkt.TokenType == 0x50, # Composite - ), - - ], - StrFixedLenField("value", b"", length=0), - ), - lambda pkt: pkt.TokenType in [ - 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0xf8, 0xf9, 0xfa, 0xfb, 0x50 - ] - ), - ConditionalField( - # Literal - ByteEnumField("sign", 0, { - 0x01: "+", - 0x02: "-", - 0x03: "None", - }), - lambda pkt: pkt.TokenType in [ - 0x01, # signed int8 - 0x02, # signed int16 - 0x03, # signed int32 - 0x04, # signed int64 - ] - ), - ConditionalField( - # Literal - ByteEnumField("base", 0, { - 0x01: "Octal", - 0x02: "Decimal", - 0x03: "Hexadecimal", - }), - lambda pkt: pkt.TokenType in [ - 0x01, # signed int8 - 0x02, # signed int16 - 0x03, # signed int32 - 0x04, # signed int64 - ] - ), -] -# fmt: on - - -class WINNT_APPLICATION_DATA(Packet): - fields_desc = [ - StrFixedLenField("Magic", b"\x61\x72\x74\x78", length=4), - PacketListField( - "Tokens", - [], - WINNT_APPLICATION_DATA_LITERAL_TOKEN, - ), - ] - - def default_payload_class(self, payload): - return conf.padding_layer - - -# [MS-DTYP] sect 2.4.4.6 - - -class WINNT_ACCESS_ALLOWED_CALLBACK_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [ - PacketField( - "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA - ), - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_ACE, AceType=0x09) - - -# [MS-DTYP] sect 2.4.4.7 - - -class WINNT_ACCESS_DENIED_CALLBACK_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_CALLBACK_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_ACE, AceType=0x0A) - - -# [MS-DTYP] sect 2.4.4.8 - - -class WINNT_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc + [ - PacketField( - "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA - ), - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE, AceType=0x0B) - - -# [MS-DTYP] sect 2.4.4.9 - - -class WINNT_ACCESS_DENIED_CALLBACK_OBJECT_ACE(Packet): - fields_desc = WINNT_ACCESS_DENIED_OBJECT_ACE.fields_desc + [ - PacketField( - "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA - ), - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_OBJECT_ACE, AceType=0x0C) - - -# [MS-DTYP] sect 2.4.4.10 - - -class WINNT_SYSTEM_AUDIT_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_ACE, AceType=0x02) - - -# [MS-DTYP] sect 2.4.4.11 - - -class WINNT_SYSTEM_AUDIT_OBJECT_ACE(Packet): - # doc is wrong. - fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_OBJECT_ACE, AceType=0x07) - - -# [MS-DTYP] sect 2.4.4.12 - - -class WINNT_SYSTEM_AUDIT_CALLBACK_ACE(Packet): - fields_desc = WINNT_SYSTEM_AUDIT_ACE.fields_desc + [ - PacketField( - "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA - ), - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_CALLBACK_ACE, AceType=0x0D) - - -# [MS-DTYP] sect 2.4.4.13 - - -class WINNT_SYSTEM_MANDATORY_LABEL_ACE(Packet): - fields_desc = WINNT_SYSTEM_AUDIT_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_MANDATORY_LABEL_ACE, AceType=0x11) - - -# [MS-DTYP] sect 2.4.4.14 - - -class WINNT_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE(Packet): - fields_desc = WINNT_SYSTEM_AUDIT_OBJECT_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE, AceType=0x0F) - -# [MS-DTYP] sect 2.4.10.1 - - -class CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1(_NTLMPayloadPacket): - _NTLM_PAYLOAD_FIELD_NAME = "Data" - fields_desc = [ - LEIntField("NameOffset", 0), - LEShortEnumField( - "ValueType", - 0, - { - 0x0001: "CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64", - 0x0002: "CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64", - 0x0003: "CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING", - 0x0005: "CLAIM_SECURITY_ATTRIBUTE_TYPE_SID", - 0x0006: "CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN", - 0x0010: "CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING", - }, - ), - LEShortField("Reserved", 0), - FlagsField( - "Flags", - 0, - -32, - { - 0x0001: "CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE", - 0x0002: "CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE", - 0x0004: "CLAIM_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY", - 0x0008: "CLAIM_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT", - 0x0010: "CLAIM_SECURITY_ATTRIBUTE_DISABLED", - 0x0020: "CLAIM_SECURITY_ATTRIBUTE_MANDATORY", - }, - ), - LEIntField("ValueCount", 0), - FieldListField( - "ValueOffsets", [], LEIntField("", 0), count_from=lambda pkt: pkt.ValueCount - ), - _NTLMPayloadField( - "Data", - lambda pkt: 16 + pkt.ValueCount * 4, - [ - ConditionalField( - StrFieldUtf16("Name", b""), - lambda pkt: pkt.NameOffset, - ), - # TODO: Values - ], - offset_name="Offset", - ), - ] - - -# [MS-DTYP] sect 2.4.4.15 - - -class WINNT_SYSTEM_RESOURCE_ATTRIBUTE_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [ - PacketField( - "AttributeData", - CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1(), - CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1, - ) - ] - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_RESOURCE_ATTRIBUTE_ACE, AceType=0x12) - -# [MS-DTYP] sect 2.4.4.16 - - -class WINNT_SYSTEM_SCOPED_POLICY_ID_ACE(Packet): - fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc - - -bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_SCOPED_POLICY_ID_ACE, AceType=0x13) - -# [MS-DTYP] sect 2.4.5 - - -class WINNT_ACL(Packet): - fields_desc = [ - ByteField("AclRevision", 2), - ByteField("Sbz1", 0x00), - # Total size including header: - # AclRevision(1) + Sbz1(1) + AclSize(2) + AceCount(2) + Sbz2(2) - FieldLenField( - "AclSize", - None, - length_of="Aces", - adjust=lambda _, x: x + 8, - fmt=" bytes - return ( - _NTLM_post_build( - self, - pkt, - self.OFFSET, - { - "OwnerSid": 4, - "GroupSid": 8, - "SACL": 12, - "DACL": 16, - }, - config=[ - ("Offset", _NTLM_ENUM.OFFSET), - ], - ) - + pay - ) - - # [MS-FSCC] 2.4.2 FileAllInformation diff --git a/scapy/layers/smbclient.py b/scapy/layers/smbclient.py index cef9f6e6195..3b806d6fcdd 100644 --- a/scapy/layers/smbclient.py +++ b/scapy/layers/smbclient.py @@ -57,11 +57,11 @@ SMB_Dialect, SMB_Header, ) +from scapy.layers.windows.security import SECURITY_DESCRIPTOR from scapy.layers.smb2 import ( DirectTCP, FileAllInformation, FileIdBothDirectoryInformation, - SECURITY_DESCRIPTOR, SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2, SMB2_CREATE_REQUEST_LEASE, SMB2_CREATE_REQUEST_LEASE_V2, @@ -1876,16 +1876,7 @@ def getsd_output(self, results): Print the output of 'getsd' """ sd = SECURITY_DESCRIPTOR(results) - print("Owner:", sd.OwnerSid.summary()) - print("Group:", sd.GroupSid.summary()) - if getattr(sd, "DACL", None): - print("DACL:") - for ace in sd.DACL.Aces: - print(" - ", ace.toSDDL()) - if getattr(sd, "SACL", None): - print("SACL:") - for ace in sd.SACL.Aces: - print(" - ", ace.toSDDL()) + sd.show_print() if __name__ == "__main__": diff --git a/scapy/layers/smbserver.py b/scapy/layers/smbserver.py index be1c68ee247..99c6ba7d89f 100644 --- a/scapy/layers/smbserver.py +++ b/scapy/layers/smbserver.py @@ -55,6 +55,7 @@ SMBTree_Connect_AndX, SMB_Header, ) +from scapy.layers.windows.security import SECURITY_DESCRIPTOR from scapy.layers.smb2 import ( DFS_REFERRAL_ENTRY1, DFS_REFERRAL_V3, @@ -76,7 +77,6 @@ FileStandardInformation, FileStreamInformation, NETWORK_INTERFACE_INFO, - SECURITY_DESCRIPTOR, SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2, SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE, SMB2_CREATE_QUERY_ON_DISK_ID, diff --git a/scapy/layers/windows/__init__.py b/scapy/layers/windows/__init__.py new file mode 100644 index 00000000000..95ea60fbbe5 --- /dev/null +++ b/scapy/layers/windows/__init__.py @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# This file is part of Scapy +# See https://scapy.net/ for more information + + +""" +This package implements Windows-specific high level helpers. +It makes it easier to use Scapy Windows related objects. + +It currently contains helpers for the Windows Registry. + +Note that if you want to tweak specific fields of the underlying +protocols, you will have to use the lower level objects directly. +""" + +# Make sure config is loaded +from scapy.config import conf # noqa: F401 diff --git a/scapy/layers/windows/erref.py b/scapy/layers/windows/erref.py new file mode 100644 index 00000000000..ba17053ce12 --- /dev/null +++ b/scapy/layers/windows/erref.py @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0-only +# This file is part of Scapy +# See https://scapy.net/ for more information +# Copyright (C) Gabriel Potter + +""" +[MS-ERREF] error codes +""" + +# SMB2 sect 3.3.5.15 + [MS-ERREF] +STATUS_ERREF = { + 0x00000000: "STATUS_SUCCESS", + 0x00000002: "ERROR_FILE_NOT_FOUND", + 0x00000003: "ERROR_PATH_NOT_FOUND", + 0x00000005: "ERROR_ACCESS_DENIED", + 0x00000006: "ERROR_INVALID_HANDLE", + 0x00000011: "ERROR_NOT_SAME_DEVICE", + 0x00000013: "ERROR_WRITE_PROTECT", + 0x00000057: "ERROR_INVALID_PARAMETER", + 0x0000007A: "ERROR_INSUFFICIENT_BUFFER", + 0x0000007B: "ERROR_INVALID_NAME", + 0x000000A1: "ERROR_BAD_PATHNAME", + 0x000000B7: "ERROR_ALREADY_EXISTS", + 0x000000EA: "ERROR_MORE_DATA", + 0x00000103: "STATUS_PENDING", + 0x0000010B: "STATUS_NOTIFY_CLEANUP", + 0x0000010C: "STATUS_NOTIFY_ENUM_DIR", + 0x000003E6: "ERROR_NOACCESS", + 0x00000532: "ERROR_PASSWORD_EXPIRED", + 0x00000533: "ERROR_ACCOUNT_DISABLED", + 0x000006F7: "ERROR_SUBKEY_NOT_FOUND", + 0x000006FE: "ERROR_TRUST_FAILURE", + 0x80000005: "STATUS_BUFFER_OVERFLOW", + 0x80000006: "STATUS_NO_MORE_FILES", + 0x8000002D: "STATUS_STOPPED_ON_SYMLINK", + 0x80070005: "E_ACCESSDENIED", + 0x8007000E: "E_OUTOFMEMORY", + 0x80090308: "SEC_E_INVALID_TOKEN", + 0x8009030C: "SEC_E_LOGON_DENIED", + 0x8009030F: "SEC_E_MESSAGE_ALTERED", + 0x80090310: "SEC_E_OUT_OF_SEQUENCE", + 0x80090346: "SEC_E_BAD_BINDINGS", + 0x80090351: "SEC_E_SMARTCARD_CERT_REVOKED", + 0xC0000003: "STATUS_INVALID_INFO_CLASS", + 0xC0000004: "STATUS_INFO_LENGTH_MISMATCH", + 0xC000000D: "STATUS_INVALID_PARAMETER", + 0xC000000F: "STATUS_NO_SUCH_FILE", + 0xC0000016: "STATUS_MORE_PROCESSING_REQUIRED", + 0xC0000022: "STATUS_ACCESS_DENIED", + 0xC0000033: "STATUS_OBJECT_NAME_INVALID", + 0xC0000034: "STATUS_OBJECT_NAME_NOT_FOUND", + 0xC0000043: "STATUS_SHARING_VIOLATION", + 0xC0000061: "STATUS_PRIVILEGE_NOT_HELD", + 0xC0000064: "STATUS_NO_SUCH_USER", + 0xC000006D: "STATUS_LOGON_FAILURE", + 0xC000006E: "STATUS_ACCOUNT_RESTRICTION", + 0xC0000070: "STATUS_INVALID_WORKSTATION", + 0xC0000071: "STATUS_PASSWORD_EXPIRED", + 0xC0000072: "STATUS_ACCOUNT_DISABLED", + 0xC000009A: "STATUS_INSUFFICIENT_RESOURCES", + 0xC00000BA: "STATUS_FILE_IS_A_DIRECTORY", + 0xC00000BB: "STATUS_NOT_SUPPORTED", + 0xC00000C9: "STATUS_NETWORK_NAME_DELETED", + 0xC00000CC: "STATUS_BAD_NETWORK_NAME", + 0xC0000120: "STATUS_CANCELLED", + 0xC0000122: "STATUS_INVALID_COMPUTER_NAME", + 0xC0000128: "STATUS_FILE_CLOSED", # backup error for older Win versions + 0xC000015B: "STATUS_LOGON_TYPE_NOT_GRANTED", + 0xC000018B: "STATUS_NO_TRUST_SAM_ACCOUNT", + 0xC000019C: "STATUS_FS_DRIVER_REQUIRED", + 0xC0000203: "STATUS_USER_SESSION_DELETED", + 0xC000020C: "STATUS_CONNECTION_DISCONNECTED", + 0xC0000225: "STATUS_NOT_FOUND", + 0xC0000257: "STATUS_PATH_NOT_COVERED", + 0xC000035C: "STATUS_NETWORK_SESSION_EXPIRED", +} diff --git a/scapy/layers/windows/registry.py b/scapy/layers/windows/registry.py new file mode 100644 index 00000000000..edf26b11ec0 --- /dev/null +++ b/scapy/layers/windows/registry.py @@ -0,0 +1,903 @@ +# SPDX-License-Identifier: GPL-2.0-only +# This file is part of Scapy +# See https://scapy.net/ for more information +# Copyright (C) github.com/Ebrix + +""" +Windows Registry RPCs + +This file provides high-level wrapping over Windows Registry related RPCs. +(scapy.layers.msrpce.raw.ms_rrp) +""" + +import struct + +from enum import IntEnum, IntFlag +from typing import Optional, Union, List + +from scapy.compat import StrEnum +from scapy.packet import Packet +from scapy.error import log_runtime + +from scapy.layers.windows.security import ( + SECURITY_DESCRIPTOR, +) +from scapy.layers.msrpce.rpcclient import DCERPC_Client +from scapy.layers.dcerpc import ( + NDRConformantArray, + NDRPointer, + NDRVaryingArray, + DCERPC_Transport, + DCE_C_AUTHN_LEVEL, + find_dcerpc_interface, +) + +from scapy.layers.msrpce.raw.ms_rrp import ( + BaseRegCloseKey_Request, + BaseRegCreateKey_Request, + BaseRegDeleteKey_Request, + BaseRegDeleteValue_Request, + BaseRegEnumKey_Request, + BaseRegEnumValue_Request, + BaseRegGetKeySecurity_Request, + BaseRegGetVersion_Request, + BaseRegOpenKey_Request, + BaseRegQueryInfoKey_Request, + BaseRegQueryInfoKey_Response, + BaseRegQueryValue_Request, + BaseRegSaveKey_Request, + BaseRegSetValue_Request, + NDRContextHandle, + OpenClassesRoot_Request, + OpenCurrentConfig_Request, + OpenCurrentUser_Request, + OpenLocalMachine_Request, + OpenPerformanceData_Request, + OpenPerformanceNlsText_Request, + OpenPerformanceText_Request, + OpenUsers_Request, + PRPC_SECURITY_ATTRIBUTES, + PRPC_SECURITY_DESCRIPTOR, + RPC_UNICODE_STRING, +) + + +class RootKeys(StrEnum): + """ + Standard root keys for the Windows registry + """ + + HKEY_CLASSES_ROOT = "HKCR" + HKEY_CURRENT_USER = "HKCU" + HKEY_LOCAL_MACHINE = "HKLM" + HKEY_CURRENT_CONFIG = "HKCC" + HKEY_USERS = "HKU" + HKEY_PERFORMANCE_DATA = "HKPD" + HKEY_PERFORMANCE_TEXT = "HKPT" + HKEY_PERFORMANCE_NLSTEXT = "HKPN" + + def __new__(cls, value): + # 1. Strip and uppercase the raw input + normalized = value.strip().upper() + # 2. Create the enum member with the normalized value + obj = str.__new__(cls, normalized) + obj._value_ = normalized + return obj + + +class RegOptions(IntFlag): + """ + Registry options for registry keys + """ + + REG_OPTION_NON_VOLATILE = 0x00000000 + REG_OPTION_VOLATILE = 0x00000001 + REG_OPTION_CREATE_LINK = 0x00000002 + REG_OPTION_BACKUP_RESTORE = 0x00000004 + REG_OPTION_OPEN_LINK = 0x00000008 + REG_OPTION_DONT_VIRTUALIZE = 0x00000010 + + +class RegType(IntEnum): + """ + Registry value types + """ + + # These constants are used to specify the type of a registry value. + + REG_SZ = 1 # Unicode string + REG_EXPAND_SZ = 2 # Unicode string with environment variable expansion + REG_BINARY = 3 # Binary data + REG_DWORD = 4 # 32-bit unsigned integer + REG_DWORD_BIG_ENDIAN = 5 # 32-bit unsigned integer in big-endian format + REG_LINK = 6 # Symbolic link + REG_MULTI_SZ = 7 # Multiple Unicode strings + REG_QWORD = 11 # 64-bit unsigned integer + UNK = 99999 # fallback default + + @classmethod + def _missing_(cls, value): + log_runtime.info(f"Unknown registry type: {value}, using UNK") + unk = cls.UNK + unk.real_value = value + return unk + + def __new__(cls, value, real_value=None): + obj = int.__new__(cls, value) + obj._value_ = value + if real_value is None: + real_value = value + obj.real_value = real_value + return obj + + @classmethod + def fromstr(cls, value: Union[str, int]) -> "RegType": + """ + Convert a string to a RegType enum member. + + :param value: The string representation of the registry type. + :return: The corresponding RegType enum member. + """ + if isinstance(value, int): + try: + return cls(value) + except ValueError: + log_runtime.info(f"Unknown registry type: {value}, using UNK") + return cls.UNK + else: + # we want to make sure that regdword, reg_dword, dword and upper + # case equivalents are all properly parsed + value = value.strip().upper() + if "_" not in value: + if value[:3] == "REG": + value = value[3:] + value = "REG_" + value.replace("REG", "", 1) + try: + return cls[value] + except (ValueError, KeyError): + log_runtime.info(f"Unknown registry type: {value}, using UNK") + return cls.UNK + + +class RegEntry: + """ + RegEntry represents a Registry Value, inside a Registry Key. + + :param reg_name: the name of the registry value + :param reg_type: the type of the registry value + :param reg_data: the data of the registry value + """ + + def __init__( + self, + reg_name: str, + reg_type: int, + reg_data: Union[list, str, bytes, int], + ): + # Name + self.reg_name = reg_name + + # Type + try: + self.reg_type = RegType(reg_type) + except ValueError: + self.reg_type = RegType.UNK + + # Check data type + if reg_type == RegType.REG_MULTI_SZ: + if not isinstance(reg_data, list): + raise ValueError("Data must be a 'list' of 'str' for this type.") + elif reg_type in [ + RegType.REG_SZ, + RegType.REG_EXPAND_SZ, + RegType.REG_LINK, + ]: + if not isinstance(reg_data, str): + raise ValueError("Data must be a 'str' for this type.") + elif reg_type == RegType.REG_BINARY: + if not isinstance(reg_data, bytes): + raise ValueError("Data must be a 'bytes' for this type.") + elif reg_type in [ + RegType.REG_DWORD, + RegType.REG_QWORD, + RegType.REG_DWORD_BIG_ENDIAN, + ]: + if not isinstance(reg_data, int): + raise ValueError("Data must be a 'int' for this type.") + else: + if not isinstance(reg_data, bytes): + raise ValueError("Data of this unknown type must be a 'bytes'.") + + self.reg_data = reg_data + + def encode(self) -> bytes: + """ + Encode data based on the type. + """ + if self.reg_type == RegType.REG_MULTI_SZ: + # encode to multiple null terminated strings + return ( + b"\x00\x00".join(x.strip().encode("utf-16le") for x in self.reg_data) + + b"\x00\x00" # final \x00 + + b"\x00\x00" # final empty string + ) + elif self.reg_type in [ + RegType.REG_SZ, + RegType.REG_EXPAND_SZ, + RegType.REG_LINK, + ]: + return self.reg_data.encode("utf-16le") + elif self.reg_type == RegType.REG_BINARY: + return self.reg_data + elif self.reg_type in [ + RegType.REG_DWORD, + RegType.REG_QWORD, + RegType.REG_DWORD_BIG_ENDIAN, + ]: + fmt = { + RegType.REG_DWORD: "I", + }[self.reg_type] + return struct.pack(fmt, self.reg_data) + else: + return self.reg_data + + @staticmethod + def frombytes(reg_name: str, reg_type: RegType, data: bytes): + """ + Create a RegEntry from bytes read on the network. + """ + if reg_type == RegType.REG_MULTI_SZ: + # encode to multiple null terminated strings + reg_data = [x.decode("utf-16le") for x in data.split(b"\x00\x00")[:-1]] + elif reg_type in [ + RegType.REG_SZ, + RegType.REG_EXPAND_SZ, + RegType.REG_LINK, + ]: + reg_data = data.decode("utf-16le") + elif reg_type == RegType.REG_BINARY: + reg_data = data + elif reg_type in [ + RegType.REG_DWORD, + RegType.REG_QWORD, + RegType.REG_DWORD_BIG_ENDIAN, + ]: + fmt = { + RegType.REG_DWORD: "I", + }[reg_type] + reg_data = struct.unpack(fmt, data)[0] + else: + reg_data = data + + return RegEntry( + reg_name=reg_name, + reg_type=reg_type, + reg_data=reg_data, + ) + + @staticmethod + def fromstr(reg_name: str, reg_type: RegType, data: str): + """ + Create a RegEntry from user input. + """ + if reg_type == RegType.REG_MULTI_SZ: + reg_data = data.split(";") + elif reg_type in [ + RegType.REG_SZ, + RegType.REG_EXPAND_SZ, + RegType.REG_LINK, + ]: + reg_data = data + elif reg_type == RegType.REG_BINARY: + reg_data = bytes.fromhex(data) + elif reg_type in [ + RegType.REG_DWORD, + RegType.REG_QWORD, + RegType.REG_DWORD_BIG_ENDIAN, + ]: + reg_data = int(data) + else: + reg_data = data + + return RegEntry( + reg_name=reg_name, + reg_type=reg_type, + reg_data=reg_data, + ) + + def __str__(self) -> str: + return ( + f"{self.reg_value} ({self.reg_type.name}: " + + f"{self.reg_type.real_value if self.reg_type == RegType.UNK else self.reg_type.value}" # noqa E501 + + f") {self.reg_data}" + ) + + def __repr__(self) -> str: + return f"RegEntry({self.reg_value}, {self.reg_type}, {self.reg_data})" + + def __eq__(self, value): + return isinstance(value, RegEntry) and all( + [ + self.reg_data == value.reg_data, + self.reg_type == value.reg_type, + self.reg_data == value.reg_data, + ] + ) + + +class RRP_Client(DCERPC_Client): + """ + High level [MS-RRP] (Windows Registry) Client + """ + + def __init__( + self, + auth_level=DCE_C_AUTHN_LEVEL.PKT_INTEGRITY, + verb=True, + **kwargs, + ): + self.interface = find_dcerpc_interface("winreg") + super(RRP_Client, self).__init__( + DCERPC_Transport.NCACN_NP, + auth_level=auth_level, + verb=verb, + **kwargs, + ) + + def connect(self, host, **kwargs): + """ + This calls DCERPC_Client's connect + """ + super(RRP_Client, self).connect( + host=host, + interface=self.interface, + endpoint="winreg", + **kwargs, + ) + + def bind(self): + """ + This calls DCERPC_Client's bind + """ + super(RRP_Client, self).bind(self.interface) + + def get_root_key_handle( + self, + root_key_name: RootKeys, + sam_desired: int = 0x2000000, # Maximum Allowed + timeout: int = 5, + ) -> Optional[NDRContextHandle]: + """ + Get a handle to a root key. + + :param root_key_name: The name of the root key to open. + Must be one of the RootKeys enum values. + :param sam_desired: The desired access rights for the key. + :param ServerName: The server name. The ServerName SHOULD be + sent as NULL, and MUST be ignored + when it is received because binding to the server + is already complete at this stage + :return: The handle to the opened root key. + """ + + cls_req = { + RootKeys.HKEY_CLASSES_ROOT: OpenClassesRoot_Request, + RootKeys.HKEY_CURRENT_USER: OpenCurrentUser_Request, + RootKeys.HKEY_LOCAL_MACHINE: OpenLocalMachine_Request, + RootKeys.HKEY_USERS: OpenUsers_Request, + RootKeys.HKEY_CURRENT_CONFIG: OpenCurrentConfig_Request, + RootKeys.HKEY_PERFORMANCE_DATA: OpenPerformanceData_Request, + RootKeys.HKEY_PERFORMANCE_TEXT: OpenPerformanceText_Request, + RootKeys.HKEY_PERFORMANCE_NLSTEXT: OpenPerformanceNlsText_Request, + } + + if root_key_name not in cls_req: + raise ValueError(f"Unknown root key: {root_key_name}") + + return self.sr1_req( + cls_req[root_key_name]( + ServerName=None, + samDesired=sam_desired, + ), + timeout=timeout, + ).phKey + + def get_subkey_handle( + self, + root_key_handle: NDRContextHandle, + subkey_path: str, + desired_access_rights: int = 0x2000000, # Maximum Allowed + options: RegOptions = RegOptions.REG_OPTION_NON_VOLATILE, + timeout: int = 5, + ) -> NDRContextHandle: + """ + Get a handle to a subkey. + + :param root_key_handle: The handle to the root key. + :param subkey_path: The name of the subkey to open. + :param desired_access_rights: The desired access rights for the subkey. + :param timeout: The timeout for the request. + :return: The handle to the opened subkey. + """ + + # Ensure it is null-terminated and handle the special case of "." + if str(subkey_path) == ".": + subkey_path = "\x00" + elif not str(subkey_path).endswith("\x00"): + subkey_path = str(subkey_path) + "\x00" + + response = self.sr1_req( + BaseRegOpenKey_Request( + hKey=root_key_handle, + lpSubKey=RPC_UNICODE_STRING(Buffer=subkey_path), + samDesired=desired_access_rights, + dwOptions=options, + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) + + return response.phkResult + + def get_version( + self, + key_handle: NDRContextHandle, + timeout: int = 5, + ) -> Packet: + """ + Get the version of the registry server. + + :param client: The DCERPC client. + :param timeout: The timeout for the request. + :return: The response packet containing the version information. + """ + + response = self.sr1_req( + BaseRegGetVersion_Request( + hKey=key_handle, + ), + timeout=timeout, + ) + + if response.status != 0: + log_runtime.error( + "Got status %s while getting version", hex(response.status) + ) + + return response + + def get_key_info( + self, + key_handle: NDRContextHandle, + timeout: int = 5, + ) -> BaseRegQueryInfoKey_Response: + """ + Get information about a given registry key. + + :param hKey: The handle to the registry key (root key or subkey). + :param timeout: The timeout for the request. + :return: The response packet containing the key information. + """ + + response = self.sr1_req( + BaseRegQueryInfoKey_Request( + hKey=key_handle, + lpClassIn=RPC_UNICODE_STRING(), + ), + timeout=timeout, + ) + + if response.status != 0: + log_runtime.error( + "Got status %s while querying key info", hex(response.status) + ) + raise ValueError(response.status) + + return response + + def get_key_security( + self, + key_handle: NDRContextHandle, + security_information: int = None, + timeout: int = 5, + ) -> SECURITY_DESCRIPTOR: + """ + Get the security descriptor of a given registry key. + + :param hKey: The handle to the registry key (root key or subkey). + :param security_information: The security information to retrieve. + :param timeout: The timeout for the request. + :return: The response packet containing the security descriptor. + """ + + if security_information is None: + security_information = ( + 0x00000001 # OWNER_SECURITY_INFORMATION + | 0x00000002 # GROUP_SECURITY_INFORMATION + | 0x00000004 # DACL_SECURITY_INFORMATION + ) + + # Build initial request + req = BaseRegGetKeySecurity_Request( + hKey=key_handle, + SecurityInformation=security_information, + pRpcSecurityDescriptorIn=PRPC_SECURITY_DESCRIPTOR( + cbInSecurityDescriptor=512, # Initial size of the buffer + ), + ) + + # Send request + response = self.sr1_req(req, timeout=timeout) + if response.status == 0x0000007A: # ERROR_INSUFFICIENT_BUFFER + # The buffer was too small, we need to retry with a larger one + req.pRpcSecurityDescriptorIn.cbInSecurityDescriptor = ( + response.pRpcSecurityDescriptorOut.cbInSecurityDescriptor + ) + response = self.sr1_req(req, timeout=timeout) + + # Check the response status + if response.status != 0: + log_runtime.error( + "Got status %s while getting security", hex(response.status) + ) + return None + + return SECURITY_DESCRIPTOR( + response.pRpcSecurityDescriptorOut.valueof("lpSecurityDescriptor") + ) + + def enum_subkeys( + self, + key_handle: NDRContextHandle, + timeout: int = 5, + ) -> List[str]: + """ + Enumerate subkeys of a given registry key. + + :param hKey: The handle to the registry key (root key or subkey). + :param timeout: The timeout for the request. + :return: A generator yielding the responses for each enumerated subkey. + """ + index = 0 + results = [] + + while True: + response = self.sr1_req( + BaseRegEnumKey_Request( + hKey=key_handle, + dwIndex=index, + lpNameIn=RPC_UNICODE_STRING(MaximumLength=1024), + lpClassIn=RPC_UNICODE_STRING(), + lpftLastWriteTime=None, + ), + timeout=timeout, + ) + + # Send request + if response.status == 0x00000103: # ERROR_NO_MORE_ITEMS + break + # Check the response status + elif response.status != 0: + raise ValueError(response.status) + + index += 1 + results.append(response.lpNameOut.valueof("Buffer")[:-1].decode()) + + return results + + def enum_values( + self, + key_handle: NDRContextHandle, + timeout: int = 5, + ) -> List[RegEntry]: + """ + Enumerate values of a given registry key. + + :param hKey: The handle to the registry key (root key or subkey). + :param timeout: The timeout for the request. + :return: A generator yielding the responses for each enumerated value. + """ + index = 0 + results = [] + + while True: + # Get the name and value at index `index` + response = self.sr1_req( + BaseRegEnumValue_Request( + hKey=key_handle, + dwIndex=index, + lpValueNameIn=RPC_UNICODE_STRING( + MaximumLength=2048, + Buffer=NDRPointer( + value=NDRConformantArray( + max_count=1024, value=NDRVaryingArray(value=b"") + ) + ), + ), + lpType=0, # pointer to type, set to 0 for query + lpData=None, # pointer to buffer + lpcbData=0, # pointer to buffer size + lpcbLen=0, # pointer to length + ), + timeout=timeout, + ) + + if response.status == 0x00000103: # ERROR_NO_MORE_ITEMS + break + elif response.status != 0: + raise ValueError(response.status) + + # Get the value name + lpValueName = response.valueof("lpValueNameOut") + + # Get value content + req = BaseRegQueryValue_Request( + hKey=key_handle, + lpValueName=lpValueName, + lpType=0, + lpcbData=1024, + lpcbLen=0, + lpData=NDRPointer( + value=NDRConformantArray( + max_count=1024, + value=NDRVaryingArray(actual_count=0, value=b""), + ) + ), + ) + + # Send request + response = self.sr1_req(req, timeout=timeout) + if response.status == 0x000000EA: # ERROR_MORE_DATA + # The buffer was too small, we need to retry with a larger one + req.lpcbData = response.lpcbData + req.lpData.value.max_count = response.lpcbData.value + response = self.sr1_req(req, timeout=timeout) + + # Check the response status + elif response.status != 0: + raise ValueError(response.status) + + index += 1 + results.append( + RegEntry.frombytes( + lpValueName.valueof("Buffer")[:-1].decode(), + response.valueof("lpType"), + response.valueof("lpData"), + ) + ) + + return results + + def get_value( + self, + key_handle: NDRContextHandle, + value_name: str, + timeout: int = 5, + ) -> RegEntry: + """ + Get the value of a given registry key. + + :param hKey: The handle to the registry key (root key or subkey). + :param value_name: The name of the value to retrieve. + :param timeout: The timeout for the request. + :return: The response packet containing the value data. + """ + + pkt = BaseRegQueryValue_Request( + hKey=key_handle, + lpValueName=value_name, + lpType=0, + lpcbData=1024, + lpcbLen=0, + lpData=NDRPointer( + value=NDRConformantArray( + max_count=1024, value=NDRVaryingArray(actual_count=0, value=b"") + ) + ), + ) + + response = self.sr1_req(pkt, timeout=timeout) + + if response.status == 0x000000EA: # ERROR_MORE_DATA + # The buffer was too small, we need to retry with a larger one + pkt.lpcbData = response.lpcbData + pkt.lpData.value.max_count = response.lpcbData.value + response = self.sr1_req(pkt, timeout=timeout) + + if response.status != 0: + raise ValueError(response.status) + + return RegEntry.frombytes( + value_name, + response.valueof("lpType"), + response.valueof("lpData"), + ) + + def save_subkey( + self, + key_handle: NDRContextHandle, + file_path: str, + security_attributes: PRPC_SECURITY_ATTRIBUTES = None, + timeout: int = 5, + ) -> None: + """ + Save a given registry key to a file. + + :param hKey: The handle to the registry key (root key or subkey). + :param file_path: The path to the file where the key will be saved. + Default path is %WINDIR%\\System32, which is readable by all users. + :param security_attributes: Security attributes for the saved key. + :param timeout: The timeout for the request. + """ + + response = self.sr1_req( + BaseRegSaveKey_Request( + hKey=key_handle, + lpFile=RPC_UNICODE_STRING(Buffer=file_path), + pSecurityAttributes=security_attributes, + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) + + def set_value( + self, + key_handle: NDRContextHandle, + entry: RegEntry, + timeout: int = 5, + ) -> None: + """ + Set a given value for a registry key. + + :param hKey: The handle to the registry key (root key or subkey). + :param entry: The 'RegEntry' entry to set, containing the name, type and data + of the value. + :param timeout: The timeout for the request. + """ + data = entry.encode() + + response = self.sr1_req( + BaseRegSetValue_Request( + hKey=key_handle, + lpValueName=RPC_UNICODE_STRING( + Buffer=entry.reg_name.encode("utf-8") + b"\x00" + ), + dwType=entry.reg_type.value, + cbData=len(data), + lpData=data, + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) + + def create_subkey( + self, + root_key_handle: NDRContextHandle, + subkey_path: str, + desired_access_rights: int = 0x2000000, # Maximum allowed + options: RegOptions = RegOptions.REG_OPTION_NON_VOLATILE, + security_attributes: PRPC_SECURITY_ATTRIBUTES = None, + timeout: int = 5, + ) -> NDRContextHandle: + """ + Create a given subkey under a registry key. + + :param client: The DCERPC client. + :param root_key_handle: The handle to the root key. + :param subkey_path: The name of the subkey to create. + :param desired_access_rights: The desired access rights for the subkey. + :param options: The options for the subkey. + :param security_attributes: Security attributes for the created key. + :param timeout: The timeout for the request. + :return: The handle to the created subkey. + """ + + if not str(subkey_path).endswith("\x00"): + subkey_path = str(subkey_path) + "\x00" + + response = self.sr1_req( + BaseRegCreateKey_Request( + hKey=root_key_handle, + lpSubKey=RPC_UNICODE_STRING(Buffer=subkey_path), + samDesired=desired_access_rights, + dwOptions=options, + lpSecurityAttributes=security_attributes, + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) + + return response.phkResult + + def delete_subkey( + self, + root_key_handle: NDRContextHandle, + subkey_path: str, + timeout: int = 5, + ) -> None: + """ + Delete a given subkey from a registry key. + + :param client: The DCERPC client. + :param hKey: The handle to the root key. + :param subkey_path: The name of the subkey to remove. + :param timeout: The timeout for the request. + """ + + if not str(subkey_path).endswith("\x00"): + subkey_path = str(subkey_path) + "\x00" + + response = self.sr1_req( + BaseRegDeleteKey_Request( + hKey=root_key_handle, + lpSubKey=RPC_UNICODE_STRING(Buffer=subkey_path), + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) + + def delete_value( + self, + key_handle: NDRContextHandle, + value_name: str, + timeout: int = 5, + ) -> None: + """ + Delete a given value from a registry key. + + :param client: The DCERPC client. + :param hKey: The handle to the subkey to remove. + :param value_name: The name of the value to delete. + :param timeout: The timeout for the request. + """ + + if not str(value_name).endswith("\x00"): + value_name = str(value_name) + "\x00" + + response = self.sr1_req( + BaseRegDeleteValue_Request( + hKey=key_handle, + lpValueName=RPC_UNICODE_STRING(Buffer=value_name), + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) + + def close_key( + self, + key_handle: NDRContextHandle, + timeout: int = 5, + ) -> None: + """ + Close a given registry key handle. + + :param client: The DCERPC client. + :param hKey: The handle to the registry key (root key or subkey). + :param timeout: The timeout for the request. + """ + + response = self.sr1_req( + BaseRegCloseKey_Request( + hKey=key_handle, + ), + timeout=timeout, + ) + + if response.status != 0: + raise ValueError(response.status) diff --git a/scapy/layers/windows/security.py b/scapy/layers/windows/security.py new file mode 100644 index 00000000000..8606f893c89 --- /dev/null +++ b/scapy/layers/windows/security.py @@ -0,0 +1,931 @@ +# SPDX-License-Identifier: GPL-2.0-only +# This file is part of Scapy +# See https://scapy.net/ for more information +# Copyright (C) Gabriel Potter + +""" +Python objects for Microsoft Windows security structures. +""" + +import re +import struct + +from scapy.config import conf +from scapy.packet import Packet, bind_layers +from scapy.fields import ( + ByteEnumField, + ByteField, + ConditionalField, + FieldLenField, + FieldListField, + FlagsField, + FlagValue, + LEIntField, + LELongField, + LenField, + LEShortEnumField, + LEShortField, + MultipleTypeField, + PacketField, + PacketListField, + ShortField, + StrFieldUtf16, + StrFixedLenField, + StrLenField, + StrLenFieldUtf16, + UUIDField, +) + +from scapy.layers.ntlm import ( + _NTLM_ENUM, + _NTLM_post_build, + _NTLMPayloadField, + _NTLMPayloadPacket, +) + +# [MS-DTYP] sect 2.4.1 + + +class WINNT_SID_IDENTIFIER_AUTHORITY(Packet): + + fields_desc = [ + StrFixedLenField("Value", b"\x00\x00\x00\x00\x00\x01", length=6), + ] + + def default_payload_class(self, payload: bytes) -> Packet: + return conf.padding_layer + + +# [MS-DTYP] sect 2.4.2 + + +class WINNT_SID(Packet): + fields_desc = [ + ByteField("Revision", 1), + FieldLenField("SubAuthorityCount", None, count_of="SubAuthority", fmt="B"), + PacketField( + "IdentifierAuthority", + WINNT_SID_IDENTIFIER_AUTHORITY(), + WINNT_SID_IDENTIFIER_AUTHORITY, + ), + FieldListField( + "SubAuthority", + [0], + LEIntField("", 0), + count_from=lambda pkt: pkt.SubAuthorityCount, + ), + ] + + def default_payload_class(self, payload: bytes) -> Packet: + return conf.padding_layer + + _SID_REG = re.compile(r"^S-(\d)-(\d+)((?:-\d+)*)$") + + @staticmethod + def fromstr(x: str): + """ + Helper to create a SID from its string representation. + + :param x: string representation of the SID like "S-1-5-18" + :type x: str + + Example: + + >>> from scapy.layers.windows.security import WINNT_SID + >>> WINNT_SID.fromstr("S-1-5-18") + SubAuthority=[18] |> + >>> _.summary() + >>> 'S-1-5-18' + """ + + m = WINNT_SID._SID_REG.match(x) + if not m: + raise ValueError("Invalid SID format !") + rev, authority, subauthority = m.groups() + return WINNT_SID( + Revision=int(rev), + IdentifierAuthority=WINNT_SID_IDENTIFIER_AUTHORITY( + Value=struct.pack(">Q", int(authority))[2:] + ), + SubAuthority=[int(x) for x in subauthority[1:].split("-")], + ) + + def summary(self) -> str: + """ + Return the string representation of the SID. + """ + return "S-%s-%s%s" % ( + self.Revision, + struct.unpack(">Q", b"\x00\x00" + self.IdentifierAuthority.Value)[0], + ( + ("-%s" % "-".join(str(x) for x in self.SubAuthority)) + if self.SubAuthority + else "" + ), + ) + + +# https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers + +WELL_KNOWN_SIDS = { + # Universal well-known SID + "S-1-0-0": "Null SID", + "S-1-1-0": "Everyone", + "S-1-2-0": "Local", + "S-1-2-1": "Console Logon", + "S-1-3-0": "Creator Owner ID", + "S-1-3-1": "Creator Group ID", + "S-1-3-2": "Owner Server", + "S-1-3-3": "Group Server", + "S-1-3-4": "Owner Rights", + "S-1-4": "Non-unique Authority", + "S-1-5": "NT Authority", + "S-1-5-80-0": "All Services", + # NT well-known SIDs + "S-1-5-1": "Dialup", + "S-1-5-113": "Local account", + "S-1-5-114": "Local account and member of Administrators group", + "S-1-5-2": "Network", + "S-1-5-3": "Batch", + "S-1-5-4": "Interactive", + "S-1-5-6": "Service", + "S-1-5-7": "Anonymous Logon", + "S-1-5-8": "Proxy", + "S-1-5-9": "Enterprise Domain Controllers", + "S-1-5-10": "Self", + "S-1-5-11": "Authenticated Users", + "S-1-5-12": "Restricted Code", + "S-1-5-13": "Terminal Server User", + "S-1-5-14": "Remote Interactive Logon", + "S-1-5-15": "This Organization", + "S-1-5-17": "IUSR", + "S-1-5-18": "System (or LocalSystem)", + "S-1-5-19": "NT Authority (LocalService)", + "S-1-5-20": "Network Service", + "S-1-5-32-544": "Administrators", + "S-1-5-32-545": "Users", + "S-1-5-32-546": "Guests", + "S-1-5-32-547": "Power Users", + "S-1-5-32-548": "Account Operators", + "S-1-5-32-549": "Server Operators", + "S-1-5-32-550": "Print Operators", + "S-1-5-32-551": "Backup Operators", + "S-1-5-32-552": "Replicators", + "S-1-5-32-554": r"Builtin\Pre-Windows 2000 Compatible Access", + "S-1-5-32-555": r"Builtin\Remote Desktop Users", + "S-1-5-32-556": r"Builtin\Network Configuration Operators", + "S-1-5-32-557": r"Builtin\Incoming Forest Trust Builders", + "S-1-5-32-558": r"Builtin\Performance Monitor Users", + "S-1-5-32-559": r"Builtin\Performance Log Users", + "S-1-5-32-560": r"Builtin\Windows Authorization Access Group", + "S-1-5-32-561": r"Builtin\Terminal Server License Servers", + "S-1-5-32-562": r"Builtin\Distributed COM Users", + "S-1-5-32-568": r"Builtin\IIS_IUSRS", + "S-1-5-32-569": r"Builtin\Cryptographic Operators", + "S-1-5-32-573": r"Builtin\Event Log Readers", + "S-1-5-32-574": r"Builtin\Certificate Service DCOM Access", + "S-1-5-32-575": r"Builtin\RDS Remote Access Servers", + "S-1-5-32-576": r"Builtin\RDS Endpoint Servers", + "S-1-5-32-577": r"Builtin\RDS Management Servers", + "S-1-5-32-578": r"Builtin\Hyper-V Administrators", + "S-1-5-32-579": r"Builtin\Access Control Assistance Operators", + "S-1-5-32-580": r"Builtin\Remote Management Users", + "S-1-5-32-581": r"Builtin\Default Account", + "S-1-5-32-582": r"Builtin\Storage Replica Admins", + "S-1-5-32-583": r"Builtin\Device Owners", + "S-1-5-64-10": "NTLM Authentication", + "S-1-5-64-14": "SChannel Authentication", + "S-1-5-64-21": "Digest Authentication", + "S-1-5-80": "NT Service", + "S-1-5-80-0": "All Services", + "S-1-5-83-0": r"NT VIRTUAL MACHINE\Virtual Machines", +} + + +# [MS-DTYP] sect 2.4.3 + +_WINNT_ACCESS_MASK = { + 0x80000000: "GENERIC_READ", + 0x40000000: "GENERIC_WRITE", + 0x20000000: "GENERIC_EXECUTE", + 0x10000000: "GENERIC_ALL", + 0x02000000: "MAXIMUM_ALLOWED", + 0x01000000: "ACCESS_SYSTEM_SECURITY", + 0x00100000: "SYNCHRONIZE", + 0x00080000: "WRITE_OWNER", + 0x00040000: "WRITE_DACL", + 0x00020000: "READ_CONTROL", + 0x00010000: "DELETE", +} + + +# [MS-DTYP] sect 2.4.4.1 + + +WINNT_ACE_FLAGS = { + 0x01: "OBJECT_INHERIT", + 0x02: "CONTAINER_INHERIT", + 0x04: "NO_PROPAGATE_INHERIT", + 0x08: "INHERIT_ONLY", + 0x10: "INHERITED_ACE", + 0x40: "SUCCESSFUL_ACCESS", + 0x80: "FAILED_ACCESS", +} + + +class WINNT_ACE_HEADER(Packet): + """ + Access Control Entry (ACE) Header + It is composed of 3 fields, followed by ACE-specific data: + + - AceType (1 byte): see below for standard values + - AceFlags (1 byte): see WINNT_ACE_FLAGS + - AceSize (2 bytes): total size of the ACE, including the header + and the ACE-specific data. + """ + + fields_desc = [ + ByteEnumField( + "AceType", + 0, + { + 0x00: "ACCESS_ALLOWED", + 0x01: "ACCESS_DENIED", + 0x02: "SYSTEM_AUDIT", + 0x03: "SYSTEM_ALARM", + 0x04: "ACCESS_ALLOWED_COMPOUND", + 0x05: "ACCESS_ALLOWED_OBJECT", + 0x06: "ACCESS_DENIED_OBJECT", + 0x07: "SYSTEM_AUDIT_OBJECT", + 0x08: "SYSTEM_ALARM_OBJECT", + 0x09: "ACCESS_ALLOWED_CALLBACK", + 0x0A: "ACCESS_DENIED_CALLBACK", + 0x0B: "ACCESS_ALLOWED_CALLBACK_OBJECT", + 0x0C: "ACCESS_DENIED_CALLBACK_OBJECT", + 0x0D: "SYSTEM_AUDIT_CALLBACK", + 0x0E: "SYSTEM_ALARM_CALLBACK", + 0x0F: "SYSTEM_AUDIT_CALLBACK_OBJECT", + 0x10: "SYSTEM_ALARM_CALLBACK_OBJECT", + 0x11: "SYSTEM_MANDATORY_LABEL", + 0x12: "SYSTEM_RESOURCE_ATTRIBUTE", + 0x13: "SYSTEM_SCOPED_POLICY_ID", + }, + ), + FlagsField( + "AceFlags", + 0, + 8, + WINNT_ACE_FLAGS, + ), + LenField("AceSize", None, fmt=" conditional expression + cond_expr = None + if hasattr(self.payload, "ApplicationData"): + # Parse tokens + res = [] + for ct in self.payload.ApplicationData.Tokens: + if ct.TokenType in [ + # binary operators + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x88, 0x8e, 0x8f, + 0xa0, 0xa1 + ]: + t1 = res.pop(-1) + t0 = res.pop(-1) + tt = ct.sprintf("%TokenType%") + if ct.TokenType in [0xa0, 0xa1]: # && and || + res.append(f"({t0}) {tt} ({t1})") + else: + res.append(f"{t0} {tt} {t1}") + elif ct.TokenType in [ + # unary operators + 0x87, 0x8d, 0xa2, 0x89, 0x8a, 0x8b, 0x8c, 0x91, 0x92, 0x93 + ]: + t0 = res.pop(-1) + tt = ct.sprintf("%TokenType%") + res.append(f"{tt}{t0}") + elif ct.TokenType in [ + # values + 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0x50, 0x51, 0xf8, 0xf9, + 0xfa, 0xfb + ]: + def lit(ct): + if ct.TokenType in [0x10, 0x18]: # literal strings + return '"%s"' % ct.value + elif ct.TokenType == 0x50: # composite + return "({%s})" % ",".join(lit(x) for x in ct.value) + else: + return str(ct.value) + res.append(lit(ct)) + elif ct.TokenType == 0x00: # padding + pass + else: + raise ValueError("Unhandled token type %s" % ct.TokenType) + if len(res) != 1: + raise ValueError("Incomplete SDDL !") + cond_expr = "(%s)" % res[0] + return { + "ace-flags-string": ace_flag_string, + "sid-string": sid_string, + "mask": mask, + "object-guid": object_guid, + "inherited-object-guid": inherit_object_guid, + "cond-expr": cond_expr, + } + # fmt: on + + def toSDDL(self, accessMask=None): + """ + Return SDDL + """ + data = self.extractData(accessMask=accessMask) + ace_rights = "" # TODO + if self.AceType in [0x9, 0xA, 0xB, 0xD]: # Conditional ACE + conditional_ace_type = { + 0x09: "XA", + 0x0A: "XD", + 0x0B: "XU", + 0x0D: "ZA", + }[self.AceType] + return "D:(%s)" % ( + ";".join( + x + for x in [ + conditional_ace_type, + data["ace-flags-string"], + ace_rights, + str(data["object-guid"]), + str(data["inherited-object-guid"]), + data["sid-string"], + data["cond-expr"], + ] + if x is not None + ) + ) + else: + ace_type = { + 0x00: "A", + 0x01: "D", + 0x02: "AU", + 0x05: "OA", + 0x06: "OD", + 0x07: "OU", + 0x11: "ML", + 0x13: "SP", + }[self.AceType] + return "(%s)" % ( + ";".join( + x + for x in [ + ace_type, + data["ace-flags-string"], + ace_rights, + str(data["object-guid"]), + str(data["inherited-object-guid"]), + data["sid-string"], + data["cond-expr"], + ] + if x is not None + ) + ) + + +# [MS-DTYP] sect 2.4.4.2 + + +class WINNT_ACCESS_ALLOWED_ACE(Packet): + fields_desc = [ + FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK), + PacketField("Sid", WINNT_SID(), WINNT_SID), + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_ACE, AceType=0x00) + + +# [MS-DTYP] sect 2.4.4.3 + + +class WINNT_ACCESS_ALLOWED_OBJECT_ACE(Packet): + fields_desc = [ + FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK), + FlagsField( + "Flags", + 0, + -32, + { + 0x00000001: "OBJECT_TYPE_PRESENT", + 0x00000002: "INHERITED_OBJECT_TYPE_PRESENT", + }, + ), + ConditionalField( + UUIDField("ObjectType", None, uuid_fmt=UUIDField.FORMAT_LE), + lambda pkt: pkt.Flags.OBJECT_TYPE_PRESENT, + ), + ConditionalField( + UUIDField("InheritedObjectType", None, uuid_fmt=UUIDField.FORMAT_LE), + lambda pkt: pkt.Flags.INHERITED_OBJECT_TYPE_PRESENT, + ), + PacketField("Sid", WINNT_SID(), WINNT_SID), + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_OBJECT_ACE, AceType=0x05) + + +# [MS-DTYP] sect 2.4.4.4 + + +class WINNT_ACCESS_DENIED_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_ACE, AceType=0x01) + + +# [MS-DTYP] sect 2.4.4.5 + + +class WINNT_ACCESS_DENIED_OBJECT_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_OBJECT_ACE, AceType=0x06) + + +# [MS-DTYP] sect 2.4.4.17.4+ + + +class WINNT_APPLICATION_DATA_LITERAL_TOKEN(Packet): + def default_payload_class(self, payload): + return conf.padding_layer + + +# fmt: off +WINNT_APPLICATION_DATA_LITERAL_TOKEN.fields_desc = [ + ByteEnumField( + "TokenType", + 0, + { + # [MS-DTYP] sect 2.4.4.17.5 + 0x00: "Padding token", + 0x01: "Signed int8", + 0x02: "Signed int16", + 0x03: "Signed int32", + 0x04: "Signed int64", + 0x10: "Unicode", + 0x18: "Octet String", + 0x50: "Composite", + 0x51: "SID", + # [MS-DTYP] sect 2.4.4.17.6 + 0x80: "==", + 0x81: "!=", + 0x82: "<", + 0x83: "<=", + 0x84: ">", + 0x85: ">=", + 0x86: "Contains", + 0x88: "Any_of", + 0x8e: "Not_Contains", + 0x8f: "Not_Any_of", + 0x89: "Member_of", + 0x8a: "Device_Member_of", + 0x8b: "Member_of_Any", + 0x8c: "Device_Member_of_Any", + 0x90: "Not_Member_of", + 0x91: "Not_Device_Member_of", + 0x92: "Not_Member_of_Any", + 0x93: "Not_Device_Member_of_Any", + # [MS-DTYP] sect 2.4.4.17.7 + 0x87: "Exists", + 0x8d: "Not_Exists", + 0xa0: "&&", + 0xa1: "||", + 0xa2: "!", + # [MS-DTYP] sect 2.4.4.17.8 + 0xf8: "Local attribute", + 0xf9: "User Attribute", + 0xfa: "Resource Attribute", + 0xfb: "Device Attribute", + } + ), + ConditionalField( + # Strings + LEIntField("length", 0), + lambda pkt: pkt.TokenType in [ + 0x10, # Unicode string + 0x18, # Octet string + 0xf8, 0xf9, 0xfa, 0xfb, # Attribute tokens + 0x50, # Composite + ] + ), + ConditionalField( + MultipleTypeField( + [ + ( + LELongField("value", 0), + lambda pkt: pkt.TokenType in [ + 0x01, # signed int8 + 0x02, # signed int16 + 0x03, # signed int32 + 0x04, # signed int64 + ] + ), + ( + StrLenFieldUtf16("value", b"", length_from=lambda pkt: pkt.length), + lambda pkt: pkt.TokenType in [ + 0x10, # Unicode string + 0xf8, 0xf9, 0xfa, 0xfb, # Attribute tokens + ] + ), + ( + StrLenField("value", b"", length_from=lambda pkt: pkt.length), + lambda pkt: pkt.TokenType == 0x18, # Octet string + ), + ( + PacketListField("value", [], WINNT_APPLICATION_DATA_LITERAL_TOKEN, + length_from=lambda pkt: pkt.length), + lambda pkt: pkt.TokenType == 0x50, # Composite + ), + + ], + StrFixedLenField("value", b"", length=0), + ), + lambda pkt: pkt.TokenType in [ + 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0xf8, 0xf9, 0xfa, 0xfb, 0x50 + ] + ), + ConditionalField( + # Literal + ByteEnumField("sign", 0, { + 0x01: "+", + 0x02: "-", + 0x03: "None", + }), + lambda pkt: pkt.TokenType in [ + 0x01, # signed int8 + 0x02, # signed int16 + 0x03, # signed int32 + 0x04, # signed int64 + ] + ), + ConditionalField( + # Literal + ByteEnumField("base", 0, { + 0x01: "Octal", + 0x02: "Decimal", + 0x03: "Hexadecimal", + }), + lambda pkt: pkt.TokenType in [ + 0x01, # signed int8 + 0x02, # signed int16 + 0x03, # signed int32 + 0x04, # signed int64 + ] + ), +] +# fmt: on + + +class WINNT_APPLICATION_DATA(Packet): + fields_desc = [ + StrFixedLenField("Magic", b"\x61\x72\x74\x78", length=4), + PacketListField( + "Tokens", + [], + WINNT_APPLICATION_DATA_LITERAL_TOKEN, + ), + ] + + def default_payload_class(self, payload): + return conf.padding_layer + + +# [MS-DTYP] sect 2.4.4.6 + + +class WINNT_ACCESS_ALLOWED_CALLBACK_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [ + PacketField( + "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA + ), + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_ACE, AceType=0x09) + + +# [MS-DTYP] sect 2.4.4.7 + + +class WINNT_ACCESS_DENIED_CALLBACK_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_CALLBACK_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_ACE, AceType=0x0A) + + +# [MS-DTYP] sect 2.4.4.8 + + +class WINNT_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc + [ + PacketField( + "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA + ), + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE, AceType=0x0B) + + +# [MS-DTYP] sect 2.4.4.9 + + +class WINNT_ACCESS_DENIED_CALLBACK_OBJECT_ACE(Packet): + fields_desc = WINNT_ACCESS_DENIED_OBJECT_ACE.fields_desc + [ + PacketField( + "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA + ), + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_OBJECT_ACE, AceType=0x0C) + + +# [MS-DTYP] sect 2.4.4.10 + + +class WINNT_SYSTEM_AUDIT_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_ACE, AceType=0x02) + + +# [MS-DTYP] sect 2.4.4.11 + + +class WINNT_SYSTEM_AUDIT_OBJECT_ACE(Packet): + # doc is wrong. + fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_OBJECT_ACE, AceType=0x07) + + +# [MS-DTYP] sect 2.4.4.12 + + +class WINNT_SYSTEM_AUDIT_CALLBACK_ACE(Packet): + fields_desc = WINNT_SYSTEM_AUDIT_ACE.fields_desc + [ + PacketField( + "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA + ), + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_CALLBACK_ACE, AceType=0x0D) + + +# [MS-DTYP] sect 2.4.4.13 + + +class WINNT_SYSTEM_MANDATORY_LABEL_ACE(Packet): + fields_desc = WINNT_SYSTEM_AUDIT_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_MANDATORY_LABEL_ACE, AceType=0x11) + + +# [MS-DTYP] sect 2.4.4.14 + + +class WINNT_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE(Packet): + fields_desc = WINNT_SYSTEM_AUDIT_OBJECT_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE, AceType=0x0F) + +# [MS-DTYP] sect 2.4.10.1 + + +class CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1(_NTLMPayloadPacket): + _NTLM_PAYLOAD_FIELD_NAME = "Data" + fields_desc = [ + LEIntField("NameOffset", 0), + LEShortEnumField( + "ValueType", + 0, + { + 0x0001: "CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64", + 0x0002: "CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64", + 0x0003: "CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING", + 0x0005: "CLAIM_SECURITY_ATTRIBUTE_TYPE_SID", + 0x0006: "CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN", + 0x0010: "CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING", + }, + ), + LEShortField("Reserved", 0), + FlagsField( + "Flags", + 0, + -32, + { + 0x0001: "CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE", + 0x0002: "CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE", + 0x0004: "CLAIM_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY", + 0x0008: "CLAIM_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT", + 0x0010: "CLAIM_SECURITY_ATTRIBUTE_DISABLED", + 0x0020: "CLAIM_SECURITY_ATTRIBUTE_MANDATORY", + }, + ), + LEIntField("ValueCount", 0), + FieldListField( + "ValueOffsets", [], LEIntField("", 0), count_from=lambda pkt: pkt.ValueCount + ), + _NTLMPayloadField( + "Data", + lambda pkt: 16 + pkt.ValueCount * 4, + [ + ConditionalField( + StrFieldUtf16("Name", b""), + lambda pkt: pkt.NameOffset, + ), + # TODO: Values + ], + offset_name="Offset", + ), + ] + + +# [MS-DTYP] sect 2.4.4.15 + + +class WINNT_SYSTEM_RESOURCE_ATTRIBUTE_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [ + PacketField( + "AttributeData", + CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1(), + CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1, + ) + ] + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_RESOURCE_ATTRIBUTE_ACE, AceType=0x12) + +# [MS-DTYP] sect 2.4.4.16 + + +class WINNT_SYSTEM_SCOPED_POLICY_ID_ACE(Packet): + fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + + +bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_SCOPED_POLICY_ID_ACE, AceType=0x13) + +# [MS-DTYP] sect 2.4.5 + + +class WINNT_ACL(Packet): + fields_desc = [ + ByteField("AclRevision", 2), + ByteField("Sbz1", 0x00), + # Total size including header: + # AclRevision(1) + Sbz1(1) + AclSize(2) + AceCount(2) + Sbz2(2) + FieldLenField( + "AclSize", + None, + length_of="Aces", + adjust=lambda _, x: x + 8, + fmt=" bytes + return ( + _NTLM_post_build( + self, + pkt, + self.OFFSET, + { + "OwnerSid": 4, + "GroupSid": 8, + "SACL": 12, + "DACL": 16, + }, + config=[ + ("Offset", _NTLM_ENUM.OFFSET), + ], + ) + + pay + ) + + def show_print(self): + """ + Print the SECURITY_DESCRIPTOR in a human format + """ + print("Owner:", self.OwnerSid.summary()) + print("Group:", self.GroupSid.summary()) + if getattr(self, "DACL", None): + print("DACL:") + for ace in self.DACL.Aces: + print(" - ", ace.toSDDL()) + if getattr(self, "SACL", None): + print("SACL:") + for ace in self.SACL.Aces: + print(" - ", ace.toSDDL()) diff --git a/scapy/modules/ldaphero.py b/scapy/modules/ldaphero.py index 8e70095922d..8842cf3b593 100644 --- a/scapy/modules/ldaphero.py +++ b/scapy/modules/ldaphero.py @@ -43,7 +43,7 @@ from scapy.layers.ntlm import NTLMSSP from scapy.layers.kerberos import KerberosSSP from scapy.layers.spnego import SPNEGOSSP -from scapy.layers.smb2 import ( +from scapy.layers.windows.security import ( SECURITY_DESCRIPTOR, WELL_KNOWN_SIDS, WINNT_ACE_FLAGS, diff --git a/scapy/modules/ticketer.py b/scapy/modules/ticketer.py index 93755d9198b..16716ae0637 100644 --- a/scapy/modules/ticketer.py +++ b/scapy/modules/ticketer.py @@ -98,7 +98,7 @@ USER_SESSION_KEY, CLAIM_ENTRY_sub2, ) -from scapy.layers.smb2 import ( +from scapy.layers.windows.security import ( WINNT_SID, WINNT_SID_IDENTIFIER_AUTHORITY, ) diff --git a/test/scapy/layers/msrpce/mslsad.uts b/test/scapy/layers/msrpce/mslsad.uts index 219907ceaca..e997381ca75 100644 --- a/test/scapy/layers/msrpce/mslsad.uts +++ b/test/scapy/layers/msrpce/mslsad.uts @@ -27,7 +27,7 @@ assert bytes(pkt) == b'\x00\x00\x00\x00\x92\xa1*"\xc2\xc2\nJ\xaf\x0bL\xdd]C\x8c\ = [MS-LSAD] - Dissect LsarEnumerateAccountsWithUserRight_Response -from scapy.layers.smb2 import WINNT_SID +from scapy.layers.windows.security import WINNT_SID pkt = LsarEnumerateAccountsWithUserRight_Response(b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\t\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x05 \x00\x00\x00*\x02\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x05 \x00\x00\x00 \x02\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\x0b\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00') information = pkt.valueof("EnumerationBuffer.Information") diff --git a/test/scapy/layers/smb2.uts b/test/scapy/layers/smb2.uts index 2e05b8357d2..c882a2e27b5 100644 --- a/test/scapy/layers/smb2.uts +++ b/test/scapy/layers/smb2.uts @@ -551,6 +551,8 @@ assert not set_info.Data.ReplaceIfExists = SMB2 - Build and dissect SECURITY_DESCRIPTOR +from scapy.layers.windows.security import * + sd = SECURITY_DESCRIPTOR( Control="DACL_PRESENT+DACL_PROTECTED+SELF_RELATIVE", OwnerSid=WINNT_SID.fromstr("S-1-1-0"), diff --git a/test/scapy/layers/tls/tlsclientserver.uts b/test/scapy/layers/tls/tlsclientserver.uts index 5f1885e9d06..7a552e3c779 100644 --- a/test/scapy/layers/tls/tlsclientserver.uts +++ b/test/scapy/layers/tls/tlsclientserver.uts @@ -102,7 +102,7 @@ def run_tls_test_server(expected_data, q, curve=None, cookie=False, client_auth= def wait_tls_test_server_online(): t = time.time() while True: - if time.time() - t > 1: + if time.time() - t > 3: raise RuntimeError("Server socket failed to start in time") try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -116,6 +116,7 @@ def wait_tls_test_server_online(): s.close() except: pass + time.sleep(0.1) continue @@ -176,7 +177,11 @@ def test_tls_server(suite="", version="", tls13=False, client_auth=False, psk=No atmtsrv = q_.get(timeout=5) if not atmtsrv: raise RuntimeError("Server hanged on startup") - wait_tls_test_server_online() + try: + wait_tls_test_server_online() + except Exception as ex: + atmtsrv.stop() + raise ex print("Thread synchronised") # Run openssl client run_openssl_client(msg, suite=suite, version=version, tls13=tls13, client_auth=client_auth, psk=psk) @@ -297,7 +302,11 @@ def test_tls_client(suite, version, curve=None, cookie=False, client_auth=False, atmtsrv = q_.get(timeout=5) if not atmtsrv: raise RuntimeError("Server hanged on startup") - wait_tls_test_server_online() + try: + wait_tls_test_server_online() + except Exception as ex: + atmtsrv.stop() + raise ex print("Thread synchronised") # Run client if sess_in_out: