Skip to content

Commit f6ba322

Browse files
authored
SMB: Implement encryption, cleanup RequireSignature (#4643)
Signed-By: gpotter2 <[email protected]>
1 parent b4dbb19 commit f6ba322

File tree

10 files changed

+622
-143
lines changed

10 files changed

+622
-143
lines changed

.config/codespell_ignore.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ browseable
88
byteorder
99
cace
1010
cas
11+
ciph
1112
componet
1213
comversion
1314
cros

doc/scapy/layers/smb.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ Scapy provides pretty good support for SMB 2/3 and very partial support of SMB1.
55

66
You can use the :class:`~scapy.layers.smb2.SMB2_Header` to dissect or build SMB2/3, or :class:`~scapy.layers.smb.SMB_Header` for SMB1.
77

8-
.. warning:: Encryption is currently not supported in neither the client nor server.
9-
108
.. _client:
119

1210
SMB 2/3 client
@@ -94,6 +92,12 @@ You might be wondering if you can pass the ``HashNT`` of the password of the use
9492
9593
If you pay very close attention, you'll notice that in this case we aren't using the :class:`~scapy.layers.spnego.SPNEGOSSP` wrapper. You could have used ``ssp=SPNEGOSSP([t.ssp(1)])``.
9694

95+
**smbclient forcing encryption**:
96+
97+
.. code:: python
98+
99+
>>> smbclient("server1.domain.local", "admin", REQUIRE_ENCRYPTION=True)
100+
97101
.. note::
98102

99103
It is also possible to start the :class:`~scapy.layers.smbclient.smbclient` directly from the OS, using the following::
@@ -306,6 +310,15 @@ A share is identified by a ``name`` and a ``path`` (+ an optional description ca
306310
readonly=False,
307311
)
308312
313+
**Start a SMB server requiring encryption (two methods)**:
314+
315+
.. code:: python
316+
317+
# Method 1: require encryption globally (available in SMB 3.0.0+)
318+
>>> smbserver(..., REQUIRE_ENCRYPTION=True)
319+
# Method 2: for a specific share (only available in SMB 3.1.1+)
320+
>>> smbserver(..., shares=[SMBShare(name="Scapy", path="/tmp", encryptdata=True)])
321+
309322
.. note::
310323

311324
It is possible to start the :class:`~scapy.layers.smbserver.smbserver` (albeit only in unauthenticated mode) directly from the OS, using the following::

doc/scapy/usage.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,12 @@ Available by default:
798798
- HTTP 1.0
799799
- TLS
800800
- Kerberos
801+
- LDAP
802+
- SMB
801803
- DCE/RPC
804+
- Postgres
805+
- DOIP
806+
- and maybe other protocols if this page isn't up to date.
802807
- :py:class:`~scapy.sessions.TLSSession` -> *matches TLS sessions* on the flow.
803808
- :py:class:`~scapy.sessions.NetflowSession` -> *resolve Netflow V9 packets* from their NetflowFlowset information objects
804809

scapy/layers/ntlm.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,9 +1680,7 @@ def GSS_Accept_sec_context(self, Context: CONTEXT, val=None):
16801680
EncryptedRandomSessionKey = b"\x00" * 16
16811681
else:
16821682
EncryptedRandomSessionKey = auth_tok.EncryptedRandomSessionKey
1683-
ExportedSessionKey = RC4K(
1684-
KeyExchangeKey, EncryptedRandomSessionKey
1685-
)
1683+
ExportedSessionKey = RC4K(KeyExchangeKey, EncryptedRandomSessionKey)
16861684
else:
16871685
ExportedSessionKey = KeyExchangeKey
16881686
Context.ExportedSessionKey = ExportedSessionKey
@@ -1800,6 +1798,7 @@ def _getSessionBaseKey(self, Context, auth_tok):
18001798
return NTLMv2_ComputeSessionBaseKey(
18011799
ResponseKeyNT, auth_tok.NtChallengeResponse.NTProofStr
18021800
)
1801+
log_runtime.debug("NTLMSSP: Bad credentials for %s" % username)
18031802
return None
18041803

18051804
def _checkLogin(self, Context, auth_tok):

scapy/layers/smb.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@
6767
)
6868
from scapy.layers.smb2 import (
6969
STATUS_ERREF,
70+
SMB2_Compression_Transform_Header,
7071
SMB2_Header,
72+
SMB2_Transform_Header,
7173
)
7274

7375

@@ -919,11 +921,9 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
919921
elif _pkt[0] == 0x13: # LOGON_SAM_USER_RESPONSE
920922
try:
921923
i = _pkt.index(b"\xff\xff\xff\xff")
922-
NtVersion = (
923-
NETLOGON_SAM_LOGON_RESPONSE_NT40.fields_desc[-3].getfield(
924-
None, _pkt[i - 4:i]
925-
)[1]
926-
)
924+
NtVersion = NETLOGON_SAM_LOGON_RESPONSE_NT40.fields_desc[
925+
-3
926+
].getfield(None, _pkt[i - 4 : i])[1]
927927
if NtVersion.V1 and not NtVersion.V5:
928928
return NETLOGON_SAM_LOGON_RESPONSE_NT40
929929
except Exception:
@@ -1013,6 +1013,7 @@ class NETLOGON_SAM_LOGON_RESPONSE_NT40(NETLOGON):
10131013

10141014
# [MS-ADTS] sect 6.3.1.8
10151015

1016+
10161017
class NETLOGON_SAM_LOGON_RESPONSE(NETLOGON, DNSCompressedPacket):
10171018
fields_desc = [
10181019
LEShortEnumField("OpCode", 0x17, _NETLOGON_opcodes),
@@ -1085,8 +1086,7 @@ def pre_dissect(self, s):
10851086
try:
10861087
i = s.index(b"\xff\xff\xff\xff")
10871088
self.fields["NtVersion"] = self.fields_desc[-3].getfield(
1088-
self,
1089-
s[i - 4:i]
1089+
self, s[i - 4 : i]
10901090
)[1]
10911091
except Exception:
10921092
self.NtVersion = 0xB
@@ -1098,20 +1098,25 @@ def get_full(self):
10981098

10991099
# [MS-BRWS] sect 2.2
11001100

1101+
11011102
class BRWS(Packet):
11021103
fields_desc = [
1103-
ByteEnumField("OpCode", 0x00, {
1104-
0x01: "HostAnnouncement",
1105-
0x02: "AnnouncementRequest",
1106-
0x08: "RequestElection",
1107-
0x09: "GetBackupListRequest",
1108-
0x0A: "GetBackupListResponse",
1109-
0x0B: "BecomeBackup",
1110-
0x0C: "DomainAnnouncement",
1111-
0x0D: "MasterAnnouncement",
1112-
0x0E: "ResetStateRequest",
1113-
0x0F: "LocalMasterAnnouncement",
1114-
}),
1104+
ByteEnumField(
1105+
"OpCode",
1106+
0x00,
1107+
{
1108+
0x01: "HostAnnouncement",
1109+
0x02: "AnnouncementRequest",
1110+
0x08: "RequestElection",
1111+
0x09: "GetBackupListRequest",
1112+
0x0A: "GetBackupListResponse",
1113+
0x0B: "BecomeBackup",
1114+
0x0C: "DomainAnnouncement",
1115+
0x0D: "MasterAnnouncement",
1116+
0x0E: "ResetStateRequest",
1117+
0x0F: "LocalMasterAnnouncement",
1118+
},
1119+
),
11151120
]
11161121

11171122
def mysummary(self):
@@ -1135,6 +1140,7 @@ def default_payload_class(self, payload):
11351140

11361141
# [MS-BRWS] sect 2.2.1
11371142

1143+
11381144
class BRWS_HostAnnouncement(BRWS):
11391145
OpCode = 0x01
11401146
fields_desc = [
@@ -1157,6 +1163,7 @@ def mysummary(self):
11571163

11581164
# [MS-BRWS] sect 2.2.6
11591165

1166+
11601167
class BRWS_BecomeBackup(BRWS):
11611168
OpCode = 0x0B
11621169
fields_desc = [
@@ -1170,6 +1177,7 @@ def mysummary(self):
11701177

11711178
# [MS-BRWS] sect 2.2.10
11721179

1180+
11731181
class BRWS_LocalMasterAnnouncement(BRWS_HostAnnouncement):
11741182
OpCode = 0x0F
11751183

@@ -1193,6 +1201,10 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
11931201
return SMB_Header
11941202
if _pkt[:4] == b"\xfeSMB":
11951203
return SMB2_Header
1204+
if _pkt[:4] == b"\xfdSMB":
1205+
return SMB2_Transform_Header
1206+
if _pkt[:4] == b"\xfcSMB":
1207+
return SMB2_Compression_Transform_Header
11961208
return cls
11971209

11981210

0 commit comments

Comments
 (0)