Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMB: Implement encryption, cleanup RequireSignature #4643

Merged
merged 1 commit into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .config/codespell_ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ browseable
byteorder
cace
cas
ciph
componet
comversion
cros
Expand Down
17 changes: 15 additions & 2 deletions doc/scapy/layers/smb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ Scapy provides pretty good support for SMB 2/3 and very partial support of SMB1.

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.

.. warning:: Encryption is currently not supported in neither the client nor server.

.. _client:

SMB 2/3 client
Expand Down Expand Up @@ -94,6 +92,12 @@ You might be wondering if you can pass the ``HashNT`` of the password of the use

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)])``.

**smbclient forcing encryption**:

.. code:: python

>>> smbclient("server1.domain.local", "admin", REQUIRE_ENCRYPTION=True)

.. note::

It is also possible to start the :class:`~scapy.layers.smbclient.smbclient` directly from the OS, using the following::
Expand Down Expand Up @@ -306,6 +310,15 @@ A share is identified by a ``name`` and a ``path`` (+ an optional description ca
readonly=False,
)

**Start a SMB server requiring encryption (two methods)**:

.. code:: python

# Method 1: require encryption globally (available in SMB 3.0.0+)
>>> smbserver(..., REQUIRE_ENCRYPTION=True)
# Method 2: for a specific share (only available in SMB 3.1.1+)
>>> smbserver(..., shares=[SMBShare(name="Scapy", path="/tmp", encryptdata=True)])

.. note::

It is possible to start the :class:`~scapy.layers.smbserver.smbserver` (albeit only in unauthenticated mode) directly from the OS, using the following::
Expand Down
5 changes: 5 additions & 0 deletions doc/scapy/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,12 @@ Available by default:
- HTTP 1.0
- TLS
- Kerberos
- LDAP
- SMB
- DCE/RPC
- Postgres
- DOIP
- and maybe other protocols if this page isn't up to date.
- :py:class:`~scapy.sessions.TLSSession` -> *matches TLS sessions* on the flow.
- :py:class:`~scapy.sessions.NetflowSession` -> *resolve Netflow V9 packets* from their NetflowFlowset information objects

Expand Down
5 changes: 2 additions & 3 deletions scapy/layers/ntlm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1680,9 +1680,7 @@ def GSS_Accept_sec_context(self, Context: CONTEXT, val=None):
EncryptedRandomSessionKey = b"\x00" * 16
else:
EncryptedRandomSessionKey = auth_tok.EncryptedRandomSessionKey
ExportedSessionKey = RC4K(
KeyExchangeKey, EncryptedRandomSessionKey
)
ExportedSessionKey = RC4K(KeyExchangeKey, EncryptedRandomSessionKey)
else:
ExportedSessionKey = KeyExchangeKey
Context.ExportedSessionKey = ExportedSessionKey
Expand Down Expand Up @@ -1800,6 +1798,7 @@ def _getSessionBaseKey(self, Context, auth_tok):
return NTLMv2_ComputeSessionBaseKey(
ResponseKeyNT, auth_tok.NtChallengeResponse.NTProofStr
)
log_runtime.debug("NTLMSSP: Bad credentials for %s" % username)
return None

def _checkLogin(self, Context, auth_tok):
Expand Down
50 changes: 31 additions & 19 deletions scapy/layers/smb.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
)
from scapy.layers.smb2 import (
STATUS_ERREF,
SMB2_Compression_Transform_Header,
SMB2_Header,
SMB2_Transform_Header,
)


Expand Down Expand Up @@ -919,11 +921,9 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
elif _pkt[0] == 0x13: # LOGON_SAM_USER_RESPONSE
try:
i = _pkt.index(b"\xff\xff\xff\xff")
NtVersion = (
NETLOGON_SAM_LOGON_RESPONSE_NT40.fields_desc[-3].getfield(
None, _pkt[i - 4:i]
)[1]
)
NtVersion = NETLOGON_SAM_LOGON_RESPONSE_NT40.fields_desc[
-3
].getfield(None, _pkt[i - 4 : i])[1]
if NtVersion.V1 and not NtVersion.V5:
return NETLOGON_SAM_LOGON_RESPONSE_NT40
except Exception:
Expand Down Expand Up @@ -1013,6 +1013,7 @@ class NETLOGON_SAM_LOGON_RESPONSE_NT40(NETLOGON):

# [MS-ADTS] sect 6.3.1.8


class NETLOGON_SAM_LOGON_RESPONSE(NETLOGON, DNSCompressedPacket):
fields_desc = [
LEShortEnumField("OpCode", 0x17, _NETLOGON_opcodes),
Expand Down Expand Up @@ -1085,8 +1086,7 @@ def pre_dissect(self, s):
try:
i = s.index(b"\xff\xff\xff\xff")
self.fields["NtVersion"] = self.fields_desc[-3].getfield(
self,
s[i - 4:i]
self, s[i - 4 : i]
)[1]
except Exception:
self.NtVersion = 0xB
Expand All @@ -1098,20 +1098,25 @@ def get_full(self):

# [MS-BRWS] sect 2.2


class BRWS(Packet):
fields_desc = [
ByteEnumField("OpCode", 0x00, {
0x01: "HostAnnouncement",
0x02: "AnnouncementRequest",
0x08: "RequestElection",
0x09: "GetBackupListRequest",
0x0A: "GetBackupListResponse",
0x0B: "BecomeBackup",
0x0C: "DomainAnnouncement",
0x0D: "MasterAnnouncement",
0x0E: "ResetStateRequest",
0x0F: "LocalMasterAnnouncement",
}),
ByteEnumField(
"OpCode",
0x00,
{
0x01: "HostAnnouncement",
0x02: "AnnouncementRequest",
0x08: "RequestElection",
0x09: "GetBackupListRequest",
0x0A: "GetBackupListResponse",
0x0B: "BecomeBackup",
0x0C: "DomainAnnouncement",
0x0D: "MasterAnnouncement",
0x0E: "ResetStateRequest",
0x0F: "LocalMasterAnnouncement",
},
),
]

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

# [MS-BRWS] sect 2.2.1


class BRWS_HostAnnouncement(BRWS):
OpCode = 0x01
fields_desc = [
Expand All @@ -1157,6 +1163,7 @@ def mysummary(self):

# [MS-BRWS] sect 2.2.6


class BRWS_BecomeBackup(BRWS):
OpCode = 0x0B
fields_desc = [
Expand All @@ -1170,6 +1177,7 @@ def mysummary(self):

# [MS-BRWS] sect 2.2.10


class BRWS_LocalMasterAnnouncement(BRWS_HostAnnouncement):
OpCode = 0x0F

Expand All @@ -1193,6 +1201,10 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
return SMB_Header
if _pkt[:4] == b"\xfeSMB":
return SMB2_Header
if _pkt[:4] == b"\xfdSMB":
return SMB2_Transform_Header
if _pkt[:4] == b"\xfcSMB":
return SMB2_Compression_Transform_Header
return cls


Expand Down
Loading
Loading