Skip to content

Commit

Permalink
Basic [MS-BRWS] support (#4300)
Browse files Browse the repository at this point in the history
  • Loading branch information
gpotter2 authored Feb 26, 2024
1 parent 4a86d93 commit d8d24da
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 3 deletions.
2 changes: 1 addition & 1 deletion scapy/layers/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ def is_request(self, req):
req = req.protocolOp
return (
req.attributes
and req.attributes[0].type.val == b"Netlogon"
and req.attributes[0].type.val.lower() == b"netlogon"
and req.filter
and isinstance(req.filter.filter, LDAP_FilterAnd)
and any(
Expand Down
13 changes: 12 additions & 1 deletion scapy/layers/netbios.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,11 @@ class NBNSRegistrationRequest(Packet):
IPField("NB_ADDRESS", "127.0.0.1")
]

def mysummary(self):
return self.sprintf("Register %G% %QUESTION_NAME% at %NB_ADDRESS%")


bind_bottom_up(NBNSHeader, NBNSRegistrationRequest, OPCODE=0x5)
bind_layers(NBNSHeader, NBNSRegistrationRequest,
OPCODE=0x5, NM_FLAGS=0x11, QDCOUNT=1, ARCOUNT=1)

Expand Down Expand Up @@ -312,7 +316,7 @@ class NBTDatagram(Packet):
ShortField("ID", 0),
IPField("SourceIP", "127.0.0.1"),
ShortField("SourcePort", 138),
ShortField("Length", 272),
ShortField("Length", None),
ShortField("Offset", 0),
NetBIOSNameField("SourceName", "windows"),
ShortEnumField("SUFFIX1", 0x4141, _NETBIOS_SUFFIXES),
Expand All @@ -321,6 +325,13 @@ class NBTDatagram(Packet):
ShortEnumField("SUFFIX2", 0x4141, _NETBIOS_SUFFIXES),
ByteField("NULL2", 0)]

def post_build(self, pkt, pay):
if self.Length is None:
length = len(pay) + 68
pkt = pkt[:10] + struct.pack("!H", length) + pkt[12:]
return pkt + pay


# SESSION SERVICE PACKETS


Expand Down
87 changes: 86 additions & 1 deletion scapy/layers/smb.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,10 @@ class SMBSession_Null(Packet):

class _SMB_TransactionRequest_Data(PacketLenField):
def m2i(self, pkt, m):
if pkt.WordCount == 0x11:
if pkt.Name == b"\\MAILSLOT\\NET\\NETLOGON":
return NETLOGON(m)
elif pkt.Name == b"\\MAILSLOT\\BROWSE" or pkt.name == b"\\MAILSLOT\\LANMAN":
return BRWS(m)
return conf.raw_layer(m)


Expand Down Expand Up @@ -780,6 +782,11 @@ def post_build(self, pkt, pay):
+ pay
)

def mysummary(self):
if self.DataLen:
return self.sprintf("Tran %Name% ") + self.Data.mysummary()
return self.sprintf("Tran %Name%")


bind_top_down(SMB_Header, SMBTransaction_Request, Command=0x25)

Expand Down Expand Up @@ -1084,6 +1091,84 @@ def get_full(self):
return self.original


# [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",
}),
]

def mysummary(self):
return self.sprintf("%OpCode%")

registered_opcodes = {}

@classmethod
def register_variant(cls):
cls.registered_opcodes[cls.OpCode.default] = cls

@classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt:
return cls.registered_opcodes.get(_pkt[0], cls)
return cls

def default_payload_class(self, payload):
return conf.padding_layer


# [MS-BRWS] sect 2.2.1

class BRWS_HostAnnouncement(BRWS):
OpCode = 0x01
fields_desc = [
BRWS,
ByteField("UpdateCount", 0),
LEIntField("Periodicity", 128000),
StrFixedLenField("ServerName", b"", length=16),
ByteField("OSVersionMajor", 6),
ByteField("OSVersionMinor", 1),
LEIntField("ServerType", 4611),
ByteField("BrowserConfigVersionMajor", 21),
ByteField("BrowserConfigVersionMinor", 1),
XLEShortField("Signature", 0xAA55),
StrNullField("Comment", ""),
]

def mysummary(self):
return self.sprintf("%OpCode% for %ServerName%")


# [MS-BRWS] sect 2.2.6

class BRWS_BecomeBackup(BRWS):
OpCode = 0x0B
fields_desc = [
BRWS,
StrNullField("BrowserToPromote", b""),
]

def mysummary(self):
return self.sprintf("%OpCode% from %BrowserToPromote%")


# [MS-BRWS] sect 2.2.10

class BRWS_LocalMasterAnnouncement(BRWS_HostAnnouncement):
OpCode = 0x0F


# SMB dispatcher


Expand Down
55 changes: 55 additions & 0 deletions test/scapy/layers/smb.uts
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,58 @@ assert smb_sax_resp_2.SecurityBlob.token.negResult == 0
assert smb_sax_resp_2.SecurityBlob.token.mechListMIC.value.val == b'\x01\x00\x00\x00\xee\t\x91S\xab\x7f]\xe6\x00\x00\x00\x00'
assert smb_sax_resp_2.NativeOS == 'Windows 8.1 9600'
assert smb_sax_resp_2.NativeLanMan == 'Windows 8.1 6.3'


+ Test BRWS

= BRWS BecomeBackup - build

pkt = \
IP(id=3109, ttl=128, src='192.168.1.2', dst='192.168.1.255') / \
UDP(sport=138, dport=138) / \
NBTDatagram(Type=17, Flags=2, ID=37087, SourceIP='192.168.1.2',
SourcePort=138, SourceName=b'VIKRANT-LAPTOP ',
SUFFIX1=16705, DestinationName=b'WORKGROUP',
SUFFIX2=16975) / \
SMB_Header(Flags=0) / \
SMBMailslot_Write(Data=BRWS_BecomeBackup(OpCode=11, BrowserToPromote='LENOVO-NETBOOK'),
Timeout=1000, Name='\\MAILSLOT\\BROWSE')


assert bytes(pkt) == b'E\x00\x00\xd4\x0c%\x00\x00\x80\x11\xa9\xa2\xc0\xa8\x01\x02\xc0\xa8\x01\xff\x00\x8a\x00\x8a\x00\xc0\xca)\x11\x02\x90\xdf\xc0\xa8\x01\x02\x00\x8a\x00\xaa\x00\x00 FGEJELFCEBEOFECNEMEBFAFEEPFACAAA\x00 FHEPFCELEHFCEPFFFACACACACACACABO\x00\xffSMB%\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x03\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00V\x00\x03\x00\x01\x00\x01\x00\x02\x00!\x00\\MAILSLOT\\BROWSE\x00\x0bLENOVO-NETBOOK\x00'

= BRWS BecomeBackup - dissection

pkt = IP(b'E\x00\x00\xd4\x0c%\x00\x00\x80\x11\xa9\xa2\xc0\xa8\x01\x02\xc0\xa8\x01\xff\x00\x8a\x00\x8a\x00\xc0\xca)\x11\x02\x90\xdf\xc0\xa8\x01\x02\x00\x8a\x00\xaa\x00\x00 FGEJELFCEBEOFECNEMEBFAFEEPFACAAA\x00 FHEPFCELEHFCEPFFFACACACACACACABO\x00\xffSMB%\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x03\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00V\x00\x03\x00\x01\x00\x01\x00\x02\x00!\x00\\MAILSLOT\\BROWSE\x00\x0bLENOVO-NETBOOK\x00')

assert SMBMailslot_Write in pkt
assert pkt[SMBMailslot_Write].Timeout == 1000
assert pkt[SMBMailslot_Write].Name == b"\\MAILSLOT\\BROWSE"
assert pkt[SMBMailslot_Write].Data.BrowserToPromote == b'LENOVO-NETBOOK'

= BRWS HostAnnouncement - build

pkt = \
IP(id=51657, tos=0x20, src='192.168.1.8', dst='192.168.1.255') / \
UDP(sport=138, dport=138) / \
NBTDatagram(Type=17, Flags=2, ID=18755, SourceIP='192.168.1.8',
SourcePort=0, SourceName='MACBOOKPRO-199C',
SUFFIX1=16705, DestinationName='WORKGROUP',
SUFFIX2=16974) / \
SMB_Header(Flags=0, PIDLow=176, MID=18754) / \
SMBMailslot_Write(Data=BRWS_HostAnnouncement(ServerName="MACBOOKPRO-122A", Comment="Super's MacBook Pro"),
Timeout=0, Flags=2, Name='\\MAILSLOT\\BROWSE')


assert bytes(pkt) == b"E \x00\xf8\xc9\xc9\x00\x00@\x11+\xb4\xc0\xa8\x01\x08\xc0\xa8\x01\xff\x00\x8a\x00\x8a\x00\xe4\xb3\xb0\x11\x02IC\xc0\xa8\x01\x08\x00\x00\x00\xce\x00\x00 ENEBEDECEPEPELFAFCEPCNDBDJDJEDAA\x00 FHEPFCELEHFCEPFFFACACACACACACABN\x00\xffSMB%\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00BI\x11\x00\x004\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00V\x00\x03\x00\x01\x00\x01\x00\x02\x00E\x00\\MAILSLOT\\BROWSE\x00\x01\x00\x00\xf4\x01\x00MACBOOKPRO-122A\x00\x06\x01\x03\x12\x00\x00\x15\x01U\xaaSuper's MacBook Pro\x00"

= BRWS HostAnnouncement - dissection

pkt = IP(b"E \x00\xf8\xc9\xc9\x00\x00@\x11+\xb4\xc0\xa8\x01\x08\xc0\xa8\x01\xff\x00\x8a\x00\x8a\x00\xe4\xb3\xb0\x11\x02IC\xc0\xa8\x01\x08\x00\x00\x00\xce\x00\x00 ENEBEDECEPEPELFAFCEPCNDBDJDJEDAA\x00 FHEPFCELEHFCEPFFFACACACACACACABN\x00\xffSMB%\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00BI\x11\x00\x004\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00V\x00\x03\x00\x01\x00\x01\x00\x02\x00E\x00\\MAILSLOT\\BROWSE\x00\x01\x00\x00\xf4\x01\x00MACBOOKPRO-122A\x00\x06\x01\x03\x12\x00\x00\x15\x01U\xaaSuper's MacBook Pro\x00")

assert SMBMailslot_Write in pkt
assert pkt[SMBMailslot_Write].Name == b"\\MAILSLOT\\BROWSE"
assert pkt[SMBMailslot_Write].Data.OpCode == 1
assert pkt[SMBMailslot_Write].Data.ServerName == b"MACBOOKPRO-122A\x00"
assert pkt[SMBMailslot_Write].Data.Comment == b"Super's MacBook Pro"
assert pkt[SMBMailslot_Write].Data.Signature == 0xAA55

0 comments on commit d8d24da

Please sign in to comment.