Skip to content

Commit 7e9e488

Browse files
authored
[DEV] Mailslot-Ping: NETLOGON and Browser poisoner additions
Merge pull request #34 from MatrixEditor/feat/mailslot-ping
2 parents 243e054 + 4d7b94b commit 7e9e488

6 files changed

Lines changed: 1466 additions & 15 deletions

File tree

dementor/assets/Dementor.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,25 @@ Port = 445
363363
# DisableExtendedSessionSecurity = false
364364
# DisableNTLMv2 = false
365365

366+
# =============================================================================
367+
# Browser (NetBIOS Datagram Service)
368+
# =============================================================================
369+
[Browser]
370+
371+
# Specifies the NetBIOS domain name to advertise in NETLOGON responses.
372+
# This value is used when responding to PDC queries (LOGON_PRIMARY_QUERY)
373+
# and DC discovery requests (LOGON_SAM_LOGON_REQUEST).
374+
# The default value is: "CONTOSO"
375+
376+
# DomainName = "WORKGROUP"
377+
378+
# Specifies the hostname to advertise as the domain controller in NETLOGON
379+
# responses. This value is used when responding to PDC queries and DC
380+
# discovery requests.
381+
# The default value is: "DC01"
382+
383+
# Hostname = "FILESERVER"
384+
366385

367386
# =============================================================================
368387
# SMTP (Simple Mail Transfer Protocol)

dementor/config/session.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class SessionConfig(TomlConfig):
128128
ssdp_config: ssdp.SSDPConfig
129129
upnp_config: upnp.UPNPConfig
130130
x11_config: x11.X11Config
131+
browser_config: netbios.BrowserConfig
131132

132133
ntlm_challenge: bytes
133134
ntlm_disable_ess: bool
@@ -164,6 +165,7 @@ class SessionConfig(TomlConfig):
164165
ipp_enabled: bool
165166
ssdp_enabled: bool
166167
upnp_enabled: bool
168+
browser_enabled: bool
167169

168170
def __init__(self) -> None:
169171
super().__init__(config.get_global_config().get("Dementor", {}))

dementor/protocols/mailslot.py

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
# Copyright (c) 2025-Present MatrixEditor
2+
#
3+
# Permission is hereby granted, free of charge, to any person obtaining a copy
4+
# of this software and associated documentation files (the "Software"), to deal
5+
# in the Software without restriction, including without limitation the rights
6+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
# copies of the Software, and to permit persons to whom the Software is
8+
# furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in all
11+
# copies or substantial portions of the Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
# SOFTWARE.
20+
"""Remote Mailslot Protocol implementation per [MS-MAIL].
21+
22+
This module implements the Remote Mailslot Protocol as specified in
23+
[MS-MAIL] (Remote Mailslot Protocol). Mailslots provide a one-way
24+
interprocess communication mechanism for connectionless, unreliable
25+
message delivery over SMB.
26+
27+
The protocol is used extensively in Windows networking for service
28+
discovery, domain controller location, and browser service announcements.
29+
"""
30+
31+
from impacket.smb import SMB
32+
from scapy.layers import netbios, smb
33+
34+
35+
# ===========================================================================
36+
# Constants
37+
# ===========================================================================
38+
# Mailslot operation codes per [MS-MAIL] § 2.2.1
39+
MAILSLOT_WRITE = 0x0001 # Write to mailslot
40+
41+
# Mailslot class values per [MS-MAIL] § 2.2.1
42+
MAILSLOT_CLASS_UNRELIABLE = 0x0002 # Unreliable (connectionless)
43+
44+
# Common mailslot names per [MS-MAIL] § 1.3
45+
MAILSLOT_NETLOGON = "\\MAILSLOT\\NET\\NETLOGON"
46+
MAILSLOT_BROWSE = "\\MAILSLOT\\BROWSE"
47+
MAILSLOT_LANMAN = "\\MAILSLOT\\LANMAN"
48+
49+
# NBT datagram types per [RFC1002] § 4.4.1
50+
NBT_DIRECT_UNIQUE = 0x10 # Direct unique datagram
51+
NBT_DIRECT_GROUP = 0x11 # Direct group datagram
52+
NBT_BROADCAST = 0x12 # Broadcast datagram
53+
54+
# NBT datagram flags per [RFC1002] § 4.4.1
55+
# SNT (Source Node Type) field values:
56+
NBT_SNT_B_NODE = 0x00 # B-node (broadcast)
57+
NBT_SNT_P_NODE = 0x01 # P-node (point-to-point)
58+
NBT_SNT_M_NODE = 0x02 # M-node (mixed)
59+
NBT_SNT_H_NODE = 0x03 # H-node (hybrid)
60+
61+
# Flag bits:
62+
NBT_FLAG_FIRST = 0x02 # First packet
63+
NBT_FLAG_MORE = 0x01 # More fragments follow
64+
65+
66+
# ===========================================================================
67+
# Mailslot Message Construction
68+
# ===========================================================================
69+
def build_mailslot_write(
70+
mailslot_name: str,
71+
data: bytes,
72+
mailslot_class: int = MAILSLOT_CLASS_UNRELIABLE,
73+
priority: int = 0,
74+
) -> smb.SMBMailslot_Write:
75+
r"""
76+
Build an SMB mailslot write transaction per [MS-MAIL] § 2.2.1.
77+
78+
Constructs an SMB_COM_TRANSACTION request with mailslot-specific
79+
setup words and parameters. The transaction writes data to a named
80+
mailslot on the target system.
81+
82+
Per [MS-MAIL] § 2.2.1, the SMB_COM_TRANSACTION request contains:
83+
- Setup words: [MailSlotOpcode, Priority, Class]
84+
- Name: Mailslot name (null-terminated ASCII)
85+
- Data: Message payload
86+
87+
Product Behavior Notes (per [MS-MAIL] § 2.2.1):
88+
- <3> Windows sets SMB_Header.Flags to 0x00
89+
- <4> Windows sets SMB_Header.Flags2 to 0x00
90+
- <5> Windows sets SMB_Header.PIDLow to 0x0000
91+
92+
:param mailslot_name: Name of the mailslot (e.g., "\\\\MAILSLOT\\\\NET\\\\NETLOGON")
93+
:type mailslot_name: str
94+
:param data: Message payload to write to the mailslot
95+
:type data: bytes
96+
:param mailslot_class: Mailslot class (1=reliable, 2=unreliable), defaults to 2
97+
:type mailslot_class: int
98+
:param priority: Message priority (0-9), defaults to 0
99+
:type priority: int
100+
:return: SMB mailslot write transaction
101+
:rtype: smb.SMBMailslot_Write
102+
103+
Example:
104+
>>> from dementor.protocols import mailslot
105+
>>> msg = mailslot.build_mailslot_write(
106+
... mailslot.MAILSLOT_NETLOGON,
107+
... b"\\x07\\x00...", # NETLOGON message
108+
... )
109+
>>> bytes(msg)
110+
b'\\x11\\x00...'
111+
112+
"""
113+
# Setup words per [MS-MAIL] § 2.2.1:
114+
# - Setup[0]: MailSlotOpcode (0x0001 = Write)
115+
# - Setup[1]: Priority (0-9)
116+
# - Setup[2]: Class (1=reliable, 2=unreliable)
117+
setup_words = [MAILSLOT_WRITE, priority, mailslot_class]
118+
119+
# Mailslot name must be null-terminated ASCII per [MS-MAIL] § 2.2.1
120+
mailslot_name_bytes = mailslot_name.encode("ascii") + b"\x00"
121+
122+
# Build the SMB_COM_TRANSACTION mailslot write
123+
# Per [MS-MAIL] § 2.2.1, the Buffer field contains:
124+
# - ("Parameter", b"") - Empty parameter block
125+
# - ("Data", data) - Message payload
126+
return smb.SMBMailslot_Write(
127+
SetupCount=3,
128+
Setup=setup_words,
129+
Name=mailslot_name_bytes,
130+
Buffer=[
131+
("Parameter", b""),
132+
("Data", data),
133+
],
134+
)
135+
136+
137+
def build_smb_header(
138+
command: int = SMB.SMB_COM_TRANSACTION,
139+
flags: int = 0x00,
140+
flags2: int = 0x00,
141+
tid: int = 0x0000,
142+
pid_low: int = 0xFEFF,
143+
uid: int = 0x0000,
144+
mid: int = 0x0000,
145+
) -> smb.SMB_Header:
146+
"""
147+
Build an SMB header for mailslot transactions per [MS-MAIL] § 2.2.1.
148+
149+
Per [MS-MAIL] § 2.2.1 product behavior notes:
150+
- <3> Windows sets Flags to 0x00
151+
- <4> Windows sets Flags2 to 0x00
152+
- <5> Windows sets PIDLow to 0xFEFF
153+
154+
:param command: SMB command code, defaults to 0x25 (SMB_COM_TRANSACTION)
155+
:type command: int
156+
:param flags: SMB flags, defaults to 0x00
157+
:type flags: int
158+
:param flags2: SMB flags2, defaults to 0x00
159+
:type flags2: int
160+
:param tid: Tree ID, defaults to 0x0000
161+
:type tid: int
162+
:param pid_low: Process ID (low word), defaults to 0xFEFF
163+
:type pid_low: int
164+
:param uid: User ID, defaults to 0x0000
165+
:type uid: int
166+
:param mid: Multiplex ID, defaults to 0x0000
167+
:type mid: int
168+
:return: SMB header
169+
:rtype: smb.SMB_Header
170+
"""
171+
return smb.SMB_Header(
172+
Command=command,
173+
Flags=flags,
174+
Flags2=flags2,
175+
TID=tid,
176+
PIDLow=pid_low,
177+
UID=uid,
178+
MID=mid,
179+
)
180+
181+
182+
# ===========================================================================
183+
# NBT Datagram Construction
184+
# ===========================================================================
185+
def build_nbt_datagram(
186+
source_name: str,
187+
destination_name: str,
188+
source_ip: str,
189+
smb_packet: smb.SMB_Header | smb.SMBMailslot_Write,
190+
datagram_type: int = NBT_DIRECT_GROUP,
191+
source_port: int = 138,
192+
node_type: int = NBT_SNT_H_NODE,
193+
first_packet: bool = True,
194+
more_fragments: bool = False,
195+
) -> netbios.NBTDatagram:
196+
"""
197+
Build an NBT datagram for mailslot message delivery per [RFC1002] § 4.4.1.
198+
199+
NetBIOS over TCP/UDP (NBT) datagrams provide the transport layer for
200+
mailslot messages. The datagram encapsulates the SMB mailslot write
201+
transaction and delivers it to the target NetBIOS name.
202+
203+
Per [RFC1002] § 4.4.1, the NBT datagram header contains:
204+
- MSG_TYPE: Datagram type (DIRECT_UNIQUE, DIRECT_GROUP, BROADCAST)
205+
- FLAGS: Source node type and fragmentation flags
206+
- DGM_ID: Datagram identifier
207+
- SOURCE_IP: IP address of sender
208+
- SOURCE_PORT: UDP port of sender (typically 138)
209+
- SOURCE_NAME: NetBIOS name of sender (16 bytes, encoded)
210+
- DESTINATION_NAME: NetBIOS name of recipient (16 bytes, encoded)
211+
212+
Per [MS-MAIL] § 3.1.4.1 product behavior note <13>:
213+
- Windows uses DIRECT_GROUP (0x11) for mailslot broadcasts
214+
- Source node type is typically H-node (0x03)
215+
- First packet flag (F) is set to 1
216+
- More fragments flag (M) is set to 0 for single-packet messages
217+
218+
:param source_name: NetBIOS name of sender (max 15 chars)
219+
:type source_name: str
220+
:param destination_name: NetBIOS name of recipient (max 15 chars)
221+
:type destination_name: str
222+
:param source_ip: IP address of sender
223+
:type source_ip: str
224+
:param smb_packet: SMB packet to encapsulate
225+
:type smb_packet: smb.SMB_Header | smb.SMBMailslot_Write
226+
:param datagram_type: NBT datagram type, defaults to NBT_DIRECT_GROUP (0x11)
227+
:type datagram_type: int
228+
:param source_port: UDP source port, defaults to 138
229+
:type source_port: int
230+
:param node_type: Source node type (B/P/M/H-node), defaults to H-node (0x03)
231+
:type node_type: int
232+
:param first_packet: First packet flag, defaults to True
233+
:type first_packet: bool
234+
:param more_fragments: More fragments flag, defaults to False
235+
:type more_fragments: bool
236+
:return: NBT datagram
237+
:rtype: netbios.NBTDatagram
238+
"""
239+
# Encode NetBIOS names per [RFC1001] § 14.1
240+
# NetBIOS names are 16 bytes: 15 chars + 1 byte suffix
241+
# Pad with spaces to 15 chars, append null byte (0x00) for workstation
242+
source_nb_name = (source_name.upper()[:15].ljust(15) + "\x00").encode("ascii")
243+
dest_nb_name = (destination_name.upper()[:15].ljust(15) + "\x00").encode("ascii")
244+
245+
# Build FLAGS field per [RFC1002] § 4.4.1
246+
# Bits 0-1: SNT (Source Node Type)
247+
# Bit 2: F (First packet)
248+
# Bit 3: M (More fragments)
249+
flags = (node_type & 0x03) << 2
250+
if first_packet:
251+
flags |= NBT_FLAG_FIRST
252+
if more_fragments:
253+
flags |= NBT_FLAG_MORE
254+
255+
# Build NBT datagram per [RFC1002] § 4.4.1
256+
datagram = netbios.NBTDatagram(
257+
Type=datagram_type,
258+
Flags=flags,
259+
SourceIP=source_ip,
260+
SourcePort=source_port,
261+
SourceName=source_nb_name,
262+
DestinationName=dest_nb_name,
263+
)
264+
265+
# Attach SMB packet as payload
266+
return datagram / smb_packet
267+
268+
269+
# ===========================================================================
270+
# High-Level API
271+
# ===========================================================================
272+
def mailslot_write(
273+
mailslot_name: str,
274+
data: bytes,
275+
source_name: str,
276+
destination_name: str,
277+
source_ip: str,
278+
mailslot_class: int = MAILSLOT_CLASS_UNRELIABLE,
279+
priority: int = 0,
280+
) -> bytes:
281+
r"""
282+
Build a complete mailslot message ready for transmission.
283+
284+
This is a high-level convenience function that combines all the steps
285+
required to build a mailslot message:
286+
1. Build SMB mailslot write transaction per [MS-MAIL] § 2.2.1
287+
2. Build SMB header per [MS-MAIL] § 2.2.1
288+
3. Build NBT datagram per [RFC1002] § 4.4.1
289+
290+
The resulting packet can be sent via UDP to port 138 on the target system.
291+
292+
:param mailslot_name: Name of the mailslot (e.g., "\\\\MAILSLOT\\\\NET\\\\NETLOGON")
293+
:type mailslot_name: str
294+
:param data: Message payload
295+
:type data: bytes
296+
:param source_name: NetBIOS name of sender (max 15 chars)
297+
:type source_name: str
298+
:param destination_name: NetBIOS name of recipient (max 15 chars)
299+
:type destination_name: str
300+
:param source_ip: IP address of sender
301+
:type source_ip: str
302+
:param mailslot_class: Mailslot class (1=reliable, 2=unreliable), defaults to 2
303+
:type mailslot_class: int
304+
:param priority: Message priority (0-9), defaults to 0
305+
:type priority: int
306+
:return: Complete mailslot message as bytes
307+
:rtype: bytes
308+
"""
309+
# Build SMB mailslot write transaction
310+
transaction = build_mailslot_write(
311+
mailslot_name=mailslot_name,
312+
data=data,
313+
mailslot_class=mailslot_class,
314+
priority=priority,
315+
)
316+
317+
# Build SMB header
318+
smb_header = build_smb_header()
319+
320+
# Combine SMB header and transaction
321+
smb_packet = smb_header / transaction
322+
323+
# Build NBT datagram
324+
datagram = build_nbt_datagram(
325+
source_name=source_name,
326+
destination_name=destination_name,
327+
source_ip=source_ip,
328+
smb_packet=smb_packet,
329+
)
330+
331+
# Return as bytes
332+
return bytes(datagram)

0 commit comments

Comments
 (0)