mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/awelzel/spicy-format-for-8.0'
* origin/topic/awelzel/spicy-format-for-8.0: Update .git-blame-ignore-revs analyzer/protocol: Reformat with spicy-format pre-commit-config: Bump spicy-format to 0.26.0
This commit is contained in:
commit
96f9cc73c3
9 changed files with 1446 additions and 1521 deletions
|
@ -33,3 +33,6 @@ f5a76c1aedc7f8886bc6abef0dfaa8065684b1f6
|
||||||
|
|
||||||
# clang-format: Format JSON with clang-format
|
# clang-format: Format JSON with clang-format
|
||||||
e6256446ddef5c5d5240eefff974556f2e12ac46
|
e6256446ddef5c5d5240eefff974556f2e12ac46
|
||||||
|
|
||||||
|
# analyzer/protocol: Reformat with spicy-format
|
||||||
|
d70bcd07b9b26036b16092fe950eca40e2f5a032
|
||||||
|
|
|
@ -52,8 +52,7 @@ repos:
|
||||||
exclude: '^(.typos.toml|src/SmithWaterman.cc|testing/.*|auxil/.*|scripts/base/frameworks/files/magic/.*|CHANGES|scripts/base/protocols/ssl/mozilla-ca-list.zeek)$'
|
exclude: '^(.typos.toml|src/SmithWaterman.cc|testing/.*|auxil/.*|scripts/base/frameworks/files/magic/.*|CHANGES|scripts/base/protocols/ssl/mozilla-ca-list.zeek)$'
|
||||||
|
|
||||||
- repo: https://github.com/bbannier/spicy-format
|
- repo: https://github.com/bbannier/spicy-format
|
||||||
rev: v0.25.0
|
rev: v0.26.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: spicy-format
|
- id: spicy-format
|
||||||
# TODO: Reformat existing large analyzers just before 8.0.
|
exclude: '^testing/.*'
|
||||||
exclude: '(^testing/.*)|(protocol/ldap/.*)|(protocol/quic/.*)|(protocol/websocket/.*)'
|
|
||||||
|
|
8
CHANGES
8
CHANGES
|
@ -1,3 +1,11 @@
|
||||||
|
8.0.0-dev.775 | 2025-07-29 10:05:20 +0200
|
||||||
|
|
||||||
|
* Update .git-blame-ignore-revs (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* analyzer/protocol: Reformat with spicy-format (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* pre-commit-config: Bump spicy-format to 0.26.0 (Arne Welzel, Corelight)
|
||||||
|
|
||||||
8.0.0-dev.770 | 2025-07-28 14:18:15 -0700
|
8.0.0-dev.770 | 2025-07-28 14:18:15 -0700
|
||||||
|
|
||||||
* dce-rpc: Make named_pipe filed docs extensive (Arne Welzel, Corelight)
|
* dce-rpc: Make named_pipe filed docs extensive (Arne Welzel, Corelight)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
8.0.0-dev.770
|
8.0.0-dev.775
|
||||||
|
|
|
@ -50,7 +50,7 @@ public type ASN1Type = enum {
|
||||||
GeneralString = 27,
|
GeneralString = 27,
|
||||||
UniversalString = 28,
|
UniversalString = 28,
|
||||||
CharacterString = 29,
|
CharacterString = 29,
|
||||||
BMPString = 30
|
BMPString = 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
#- ASN.1 data classes --------------------------------------------------------
|
#- ASN.1 data classes --------------------------------------------------------
|
||||||
|
@ -59,7 +59,7 @@ public type ASN1Class = enum {
|
||||||
Universal = 0,
|
Universal = 0,
|
||||||
Application = 1,
|
Application = 1,
|
||||||
ContextSpecific = 2,
|
ContextSpecific = 2,
|
||||||
Private = 3
|
Private = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
#- ASN.1 tag definition (including length) ------------------------------------
|
#- ASN.1 tag definition (including length) ------------------------------------
|
||||||
|
@ -73,14 +73,12 @@ type LengthType = unit {
|
||||||
islong: 7;
|
islong: 7;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
switch (self.data.islong) {
|
switch (self.data.islong) {
|
||||||
0 -> : void {
|
0 -> : void {
|
||||||
self.len = self.data.num;
|
self.len = self.data.num;
|
||||||
self.tag_len = 1;
|
self.tag_len = 1;
|
||||||
}
|
}
|
||||||
1 -> : bytes &size=self.data.num
|
1 -> : bytes &size=self.data.num &convert=$$.to_uint(spicy::ByteOrder::Network) {
|
||||||
&convert=$$.to_uint(spicy::ByteOrder::Network) {
|
|
||||||
self.len = $$;
|
self.len = $$;
|
||||||
self.tag_len = self.data.num + 1;
|
self.tag_len = self.data.num + 1;
|
||||||
}
|
}
|
||||||
|
@ -128,13 +126,11 @@ type ASN1String = unit(tag: ASN1Tag, len: uint64) {
|
||||||
# see "Restricted Character String Types" in
|
# see "Restricted Character String Types" in
|
||||||
# "Generic String Encoding Rules (GSER) for ASN.1 Types"
|
# "Generic String Encoding Rules (GSER) for ASN.1 Types"
|
||||||
# (https://datatracker.ietf.org/doc/html/rfc3641#section-3.2)
|
# (https://datatracker.ietf.org/doc/html/rfc3641#section-3.2)
|
||||||
|
|
||||||
case ASN1Type::PrintableString,
|
case ASN1Type::PrintableString,
|
||||||
ASN1Type::GeneralizedTime,
|
ASN1Type::GeneralizedTime,
|
||||||
ASN1Type::UTCTime: {
|
ASN1Type::UTCTime: {
|
||||||
self.encoding = spicy::Charset::ASCII;
|
self.encoding = spicy::Charset::ASCII;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ASN1Type::UTF8String,
|
case ASN1Type::UTF8String,
|
||||||
ASN1Type::GeneralString,
|
ASN1Type::GeneralString,
|
||||||
ASN1Type::CharacterString,
|
ASN1Type::CharacterString,
|
||||||
|
@ -192,7 +188,6 @@ type ASN1ObjectIdentifier = unit(len: uint64) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#- ASN.1 message header (tag + length information) ----------------------------
|
#- ASN.1 message header (tag + length information) ----------------------------
|
||||||
|
|
||||||
public type ASN1Header = unit {
|
public type ASN1Header = unit {
|
||||||
|
@ -204,23 +199,13 @@ public type ASN1Header = unit {
|
||||||
|
|
||||||
public type ASN1Body = unit(head: ASN1Header, recursive: bool) {
|
public type ASN1Body = unit(head: ASN1Header, recursive: bool) {
|
||||||
switch (head.tag.type_) {
|
switch (head.tag.type_) {
|
||||||
|
|
||||||
ASN1Type::Boolean -> bool_value: uint8 &convert=cast<bool>($$) &requires=head.len.len == 1;
|
ASN1Type::Boolean -> bool_value: uint8 &convert=cast<bool>($$) &requires=head.len.len == 1;
|
||||||
|
|
||||||
ASN1Type::Integer,
|
ASN1Type::Integer,
|
||||||
ASN1Type::Enumerated -> num_value: bytes &size=head.len.len
|
ASN1Type::Enumerated -> num_value: bytes &size=head.len.len &convert=$$.to_int(spicy::ByteOrder::Big);
|
||||||
&convert=$$.to_int(spicy::ByteOrder::Big);
|
|
||||||
|
|
||||||
ASN1Type::NullVal -> null_value: bytes &size=0 &requires=head.len.len == 0;
|
ASN1Type::NullVal -> null_value: bytes &size=0 &requires=head.len.len == 0;
|
||||||
|
|
||||||
ASN1Type::BitString -> bitstr_value: ASN1BitString(head.len.len, head.tag.constructed);
|
ASN1Type::BitString -> bitstr_value: ASN1BitString(head.len.len, head.tag.constructed);
|
||||||
|
ASN1Type::OctetString -> str_value: ASN1OctetString(head.len.len, head.tag.constructed) &convert=$$.value.decode(spicy::Charset::ASCII);
|
||||||
ASN1Type::OctetString -> str_value: ASN1OctetString(head.len.len, head.tag.constructed)
|
ASN1Type::ObjectIdentifier -> str_value: ASN1ObjectIdentifier(head.len.len) &convert=$$.oidstring;
|
||||||
&convert=$$.value.decode(spicy::Charset::ASCII);
|
|
||||||
|
|
||||||
ASN1Type::ObjectIdentifier -> str_value: ASN1ObjectIdentifier(head.len.len)
|
|
||||||
&convert=$$.oidstring;
|
|
||||||
|
|
||||||
ASN1Type::BMPString,
|
ASN1Type::BMPString,
|
||||||
ASN1Type::CharacterString,
|
ASN1Type::CharacterString,
|
||||||
ASN1Type::GeneralizedTime,
|
ASN1Type::GeneralizedTime,
|
||||||
|
@ -235,8 +220,8 @@ public type ASN1Body = unit(head: ASN1Header, recursive: bool) {
|
||||||
ASN1Type::VideotextString,
|
ASN1Type::VideotextString,
|
||||||
ASN1Type::VisibleString,
|
ASN1Type::VisibleString,
|
||||||
ASN1Type::UniversalString -> str_value: ASN1String(head.tag, head.len.len);
|
ASN1Type::UniversalString -> str_value: ASN1String(head.tag, head.len.len);
|
||||||
|
ASN1Type::Sequence,
|
||||||
ASN1Type::Sequence, ASN1Type::Set -> seq: ASN1SubMessages(head.len.len) if (recursive);
|
ASN1Type::Set -> seq: ASN1SubMessages(head.len.len) if(recursive);
|
||||||
|
|
||||||
# TODO: ASN1Type values not handled yet
|
# TODO: ASN1Type values not handled yet
|
||||||
ASN1Type::ObjectDescriptor,
|
ASN1Type::ObjectDescriptor,
|
||||||
|
@ -266,14 +251,11 @@ public type ASN1Message = unit(recursive: bool) {
|
||||||
|
|
||||||
head: ASN1Header;
|
head: ASN1Header;
|
||||||
switch (self.head.tag.class) {
|
switch (self.head.tag.class) {
|
||||||
|
|
||||||
ASN1Class::Universal -> body: ASN1Body(self.head, recursive);
|
ASN1Class::Universal -> body: ASN1Body(self.head, recursive);
|
||||||
|
|
||||||
ASN1Class::Application,
|
ASN1Class::Application,
|
||||||
ASN1Class::ContextSpecific,
|
ASN1Class::ContextSpecific,
|
||||||
ASN1Class::Private -> application_data: bytes &size=self.head.len.len {
|
ASN1Class::Private -> application_data: bytes &size=self.head.len.len {
|
||||||
self.application_id = cast<int32>(self.head.tag.type_);
|
self.application_id = cast<int32>(self.head.tag.type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,12 +115,9 @@ public type ResultCode = enum {
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
public type Result = unit {
|
public type Result = unit {
|
||||||
code: ASN1::ASN1Message(True) &convert=cast<ResultCode>(cast<uint8>($$.body.num_value))
|
code: ASN1::ASN1Message(True) &convert=cast<ResultCode>(cast<uint8>($$.body.num_value)) &default=ResultCode::Undef;
|
||||||
&default=ResultCode::Undef;
|
matchedDN: ASN1::ASN1Message(True) &convert=$$.body.str_value &default="";
|
||||||
matchedDN: ASN1::ASN1Message(True) &convert=$$.body.str_value
|
diagnosticMessage: ASN1::ASN1Message(True) &convert=$$.body.str_value &default="";
|
||||||
&default="";
|
|
||||||
diagnosticMessage: ASN1::ASN1Message(True) &convert=$$.body.str_value
|
|
||||||
&default="";
|
|
||||||
|
|
||||||
# TODO: if we want to parse referral URIs in result
|
# TODO: if we want to parse referral URIs in result
|
||||||
# https://tools.ietf.org/html/rfc4511#section-4.1.10
|
# https://tools.ietf.org/html/rfc4511#section-4.1.10
|
||||||
|
@ -162,7 +159,6 @@ public type MessageDispatch = unit(ctx: Ctx&) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
type MaybeEncrypted = unit(ctx: Ctx&) {
|
type MaybeEncrypted = unit(ctx: Ctx&) {
|
||||||
# A plaintext LDAP message always starts with at least 3 bytes and the first
|
# A plaintext LDAP message always starts with at least 3 bytes and the first
|
||||||
|
@ -242,7 +238,8 @@ type KrbWrapToken = unit {
|
||||||
};
|
};
|
||||||
filler: skip b"\xff";
|
filler: skip b"\xff";
|
||||||
ec: uint16; # extra count
|
ec: uint16; # extra count
|
||||||
rrc: uint16 { # right rotation count
|
rrc: uint16 {
|
||||||
|
# right rotation count
|
||||||
# Handle rrc == ec or rrc == 0.
|
# Handle rrc == ec or rrc == 0.
|
||||||
if (self.rrc == self.ec) {
|
if (self.rrc == self.ec) {
|
||||||
self.header_ec = self.ec;
|
self.header_ec = self.ec;
|
||||||
|
@ -406,7 +403,7 @@ type GSS_SPNEGO_Init = unit {
|
||||||
spnegoInitial: skip GSS_SPNEGO_negTokenInit if(self?.spnegoInitByte);
|
spnegoInitial: skip GSS_SPNEGO_negTokenInit if(self?.spnegoInitByte);
|
||||||
};
|
};
|
||||||
|
|
||||||
type SaslCredentials = unit() {
|
type SaslCredentials = unit {
|
||||||
mechanism: ASN1::ASN1Message(False) &convert=$$.body.str_value;
|
mechanism: ASN1::ASN1Message(False) &convert=$$.body.str_value;
|
||||||
|
|
||||||
# Peak into GSS-SPNEGO payload if we have any.
|
# Peak into GSS-SPNEGO payload if we have any.
|
||||||
|
@ -416,7 +413,7 @@ type SaslCredentials = unit() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type SicilyMessage = unit() {
|
type SicilyMessage = unit {
|
||||||
# Just ensure the signature matches. We could do more,
|
# Just ensure the signature matches. We could do more,
|
||||||
# but it'd be better to forward to an NTLM analyzer.
|
# but it'd be better to forward to an NTLM analyzer.
|
||||||
signature: skip b"NTLMSSP";
|
signature: skip b"NTLMSSP";
|
||||||
|
@ -486,23 +483,18 @@ type BindRequest = unit(inout message: Message, ctx: Ctx&) {
|
||||||
|
|
||||||
if (|self.authData| > 0) {
|
if (|self.authData| > 0) {
|
||||||
switch (self.authType) {
|
switch (self.authType) {
|
||||||
BindAuthType::BIND_AUTH_SIMPLE ->
|
BindAuthType::BIND_AUTH_SIMPLE -> : void {
|
||||||
: void {
|
|
||||||
self.simpleCreds = self.authData.decode();
|
self.simpleCreds = self.authData.decode();
|
||||||
message.arg = self.simpleCreds;
|
message.arg = self.simpleCreds;
|
||||||
}
|
}
|
||||||
|
BindAuthType::BIND_AUTH_SASL -> saslCreds: SaslCredentials {
|
||||||
BindAuthType::BIND_AUTH_SASL ->
|
|
||||||
saslCreds: SaslCredentials {
|
|
||||||
message.arg = self.saslCreds.mechanism;
|
message.arg = self.saslCreds.mechanism;
|
||||||
ctx.saslMechanism = self.saslCreds.mechanism;
|
ctx.saslMechanism = self.saslCreds.mechanism;
|
||||||
}
|
}
|
||||||
|
BindAuthType::SICILY_NEGOTIATE,
|
||||||
BindAuthType::SICILY_NEGOTIATE, BindAuthType::SICILY_RESPONSE ->
|
BindAuthType::SICILY_RESPONSE -> sicilyMessage: SicilyMessage {
|
||||||
sicilyMessage: SicilyMessage {
|
|
||||||
message.arg = self.sicilyMessage.signature_decoded;
|
message.arg = self.sicilyMessage.signature_decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
* -> : void;
|
* -> : void;
|
||||||
} &parse-from=self.authData;
|
} &parse-from=self.authData;
|
||||||
};
|
};
|
||||||
|
@ -543,8 +535,7 @@ type BindResponse = unit(inout message: Message, ctx: Ctx&) {
|
||||||
|
|
||||||
# If the client requested GSS-SPNEGO, try to parse the server's response
|
# If the client requested GSS-SPNEGO, try to parse the server's response
|
||||||
# to switch message mode.
|
# to switch message mode.
|
||||||
gss_spnego: GSS_SPNEGO_Subsequent &parse-from=self.serverSaslCreds[0].payload
|
gss_spnego: GSS_SPNEGO_Subsequent &parse-from=self.serverSaslCreds[0].payload if(ctx.saslMechanism == "GSS-SPNEGO" && |self.serverSaslCreds| > 0) {
|
||||||
if (ctx.saslMechanism == "GSS-SPNEGO" && |self.serverSaslCreds| > 0) {
|
|
||||||
|
|
||||||
if ($$?.negTokenResp) {
|
if ($$?.negTokenResp) {
|
||||||
local token = $$.negTokenResp;
|
local token = $$.negTokenResp;
|
||||||
|
@ -603,8 +594,7 @@ public type AttributeSelection = unit {
|
||||||
# https://tools.ietf.org/html/rfc4511#section-4.5.1
|
# https://tools.ietf.org/html/rfc4511#section-4.5.1
|
||||||
# and decide how deep that should be fleshed out.
|
# and decide how deep that should be fleshed out.
|
||||||
: ASN1::ASN1Message(True) {
|
: ASN1::ASN1Message(True) {
|
||||||
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) &&
|
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && ($$.body?.seq)) {
|
||||||
($$.body?.seq)) {
|
|
||||||
for (i in $$.body.seq.submessages) {
|
for (i in $$.body.seq.submessages) {
|
||||||
if (i.body?.str_value) {
|
if (i.body?.str_value) {
|
||||||
self.attributes.push_back(i.body.str_value);
|
self.attributes.push_back(i.body.str_value);
|
||||||
|
@ -619,9 +609,7 @@ type AttributeValueAssertion = unit {
|
||||||
var val: string = "";
|
var val: string = "";
|
||||||
|
|
||||||
: ASN1::ASN1Message(True) {
|
: ASN1::ASN1Message(True) {
|
||||||
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) &&
|
if (($$.head.tag.type_ == ASN1::ASN1Type::Sequence) && ($$.body?.seq) && (|$$.body.seq.submessages| >= 2)) {
|
||||||
($$.body?.seq) &&
|
|
||||||
(|$$.body.seq.submessages| >= 2)) {
|
|
||||||
if ($$.body.seq.submessages[0].body?.str_value) {
|
if ($$.body.seq.submessages[0].body?.str_value) {
|
||||||
self.desc = $$.body.seq.submessages[0].body.str_value;
|
self.desc = $$.body.seq.submessages[0].body.str_value;
|
||||||
}
|
}
|
||||||
|
@ -715,7 +703,6 @@ public function bytes_sid_to_SID_repr(bts: bytes) : string {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function uint32_to_hex_repr(bts: bytes): string {
|
public function uint32_to_hex_repr(bts: bytes): string {
|
||||||
# Needs to be exactly 4 bytes
|
# Needs to be exactly 4 bytes
|
||||||
if (|bts| != 4) {
|
if (|bts| != 4) {
|
||||||
|
@ -739,12 +726,11 @@ public function string_representation(search_filter: SearchFilter): string {
|
||||||
switch (local fType = search_filter.filterType) {
|
switch (local fType = search_filter.filterType) {
|
||||||
# The NOT, AND and OR filter types are trees and may hold many leaf nodes. So recursively get
|
# The NOT, AND and OR filter types are trees and may hold many leaf nodes. So recursively get
|
||||||
# the stringPresentations for the leaf nodes and add them all in one final statement.
|
# the stringPresentations for the leaf nodes and add them all in one final statement.
|
||||||
|
|
||||||
case FilterType::FILTER_NOT: {
|
case FilterType::FILTER_NOT: {
|
||||||
repr = "(!%s)" % search_filter.FILTER_NOT.searchfilter.stringRepresentation;
|
repr = "(!%s)" % search_filter.FILTER_NOT.searchfilter.stringRepresentation;
|
||||||
}
|
}
|
||||||
|
case FilterType::FILTER_AND,
|
||||||
case FilterType::FILTER_AND, FilterType::FILTER_OR: {
|
FilterType::FILTER_OR: {
|
||||||
local nestedObj: ParseNestedAndOr;
|
local nestedObj: ParseNestedAndOr;
|
||||||
local printChar = "";
|
local printChar = "";
|
||||||
|
|
||||||
|
@ -780,12 +766,9 @@ public function string_representation(search_filter: SearchFilter): string {
|
||||||
for (searchFilter in nestedObj.searchfilters) {
|
for (searchFilter in nestedObj.searchfilters) {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: {
|
case 0: {
|
||||||
repr = "(%s%s%s" % (
|
repr = "(%s%s%s" % (printChar, searchFilter.stringRepresentation,
|
||||||
printChar,
|
|
||||||
searchFilter.stringRepresentation,
|
|
||||||
# If we have exactly one element immediately close the statement since we are done.
|
# If we have exactly one element immediately close the statement since we are done.
|
||||||
|nestedObj.searchfilters| == 1 ? ")" : ""
|
|nestedObj.searchfilters| == 1 ? ")" : "");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
repr = repr + searchFilter.stringRepresentation + ")";
|
repr = repr + searchFilter.stringRepresentation + ")";
|
||||||
|
@ -799,39 +782,29 @@ public function string_representation(search_filter: SearchFilter): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
# The following FilterTypes are leaf nodes and can thus be represented in a statement
|
# The following FilterTypes are leaf nodes and can thus be represented in a statement
|
||||||
|
|
||||||
case FilterType::FILTER_EXT: {
|
case FilterType::FILTER_EXT: {
|
||||||
# For extended search filters the meaning of the individual fields in
|
# For extended search filters the meaning of the individual fields in
|
||||||
# `DecodedAttributeValue` is slightly different.
|
# `DecodedAttributeValue` is slightly different.
|
||||||
repr = "(%s:%s:=%s)" % (search_filter.FILTER_EXT.assertionValueDecoded,
|
repr = "(%s:%s:=%s)" % (search_filter.FILTER_EXT.assertionValueDecoded, search_filter.FILTER_EXT.attributeDesc.decode(), search_filter.FILTER_EXT.matchValue);
|
||||||
search_filter.FILTER_EXT.attributeDesc.decode(),
|
|
||||||
search_filter.FILTER_EXT.matchValue);
|
|
||||||
}
|
}
|
||||||
case FilterType::FILTER_APPROX: {
|
case FilterType::FILTER_APPROX: {
|
||||||
repr = "(%s~=%s)" % (search_filter.FILTER_APPROX.attributeDesc.decode(),
|
repr = "(%s~=%s)" % (search_filter.FILTER_APPROX.attributeDesc.decode(), search_filter.FILTER_APPROX.assertionValueDecoded);
|
||||||
search_filter.FILTER_APPROX.assertionValueDecoded);
|
|
||||||
}
|
}
|
||||||
case FilterType::FILTER_EQ: {
|
case FilterType::FILTER_EQ: {
|
||||||
repr = "(%s=%s)" % (search_filter.FILTER_EQ.attributeDesc.decode(),
|
repr = "(%s=%s)" % (search_filter.FILTER_EQ.attributeDesc.decode(), search_filter.FILTER_EQ.assertionValueDecoded);
|
||||||
search_filter.FILTER_EQ.assertionValueDecoded);
|
|
||||||
}
|
}
|
||||||
case FilterType::FILTER_GE: {
|
case FilterType::FILTER_GE: {
|
||||||
repr = "(%s>=%s)" % (search_filter.FILTER_GE.attributeDesc.decode(),
|
repr = "(%s>=%s)" % (search_filter.FILTER_GE.attributeDesc.decode(), search_filter.FILTER_GE.assertionValueDecoded);
|
||||||
search_filter.FILTER_GE.assertionValueDecoded);
|
|
||||||
}
|
}
|
||||||
case FilterType::FILTER_LE: {
|
case FilterType::FILTER_LE: {
|
||||||
repr = "(%s<=%s)" % (search_filter.FILTER_LE.attributeDesc.decode(),
|
repr = "(%s<=%s)" % (search_filter.FILTER_LE.attributeDesc.decode(), search_filter.FILTER_LE.assertionValueDecoded);
|
||||||
search_filter.FILTER_LE.assertionValueDecoded);
|
|
||||||
}
|
}
|
||||||
case FilterType::FILTER_SUBSTR: {
|
case FilterType::FILTER_SUBSTR: {
|
||||||
local anys: string = "";
|
local anys: string = "";
|
||||||
if (|search_filter.FILTER_SUBSTR.anys| > 0)
|
if (|search_filter.FILTER_SUBSTR.anys| > 0)
|
||||||
anys = b"*".join(search_filter.FILTER_SUBSTR.anys).decode() + "*";
|
anys = b"*".join(search_filter.FILTER_SUBSTR.anys).decode() + "*";
|
||||||
|
|
||||||
repr = "(%s=%s*%s%s)" % (search_filter.FILTER_SUBSTR.attributeDesc.decode(),
|
repr = "(%s=%s*%s%s)" % (search_filter.FILTER_SUBSTR.attributeDesc.decode(), search_filter.FILTER_SUBSTR.initial, anys, search_filter.FILTER_SUBSTR.final);
|
||||||
search_filter.FILTER_SUBSTR.initial,
|
|
||||||
anys,
|
|
||||||
search_filter.FILTER_SUBSTR.final);
|
|
||||||
}
|
}
|
||||||
case FilterType::FILTER_PRESENT: {
|
case FilterType::FILTER_PRESENT: {
|
||||||
repr = "(%s=*)" % search_filter.FILTER_PRESENT;
|
repr = "(%s=*)" % search_filter.FILTER_PRESENT;
|
||||||
|
@ -862,19 +835,16 @@ type DecodedAttributeValue = unit(fType: FilterType) {
|
||||||
switch (self.attributeDesc) {
|
switch (self.attributeDesc) {
|
||||||
# Special parsing required for some CLDAP attributes,
|
# Special parsing required for some CLDAP attributes,
|
||||||
# see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/895a7744-aff3-4f64-bcfa-f8c05915d2e9
|
# see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/895a7744-aff3-4f64-bcfa-f8c05915d2e9
|
||||||
|
|
||||||
case b"DomainGuid": {
|
case b"DomainGuid": {
|
||||||
self.assertionValueDecoded = utf16_guid_to_hex_repr(self.assertionValue);
|
self.assertionValueDecoded = utf16_guid_to_hex_repr(self.assertionValue);
|
||||||
}
|
}
|
||||||
|
case b"objectSid",
|
||||||
case b"objectSid", b"AAC": {
|
b"AAC": {
|
||||||
self.assertionValueDecoded = bytes_sid_to_hex_repr(self.assertionValue);
|
self.assertionValueDecoded = bytes_sid_to_hex_repr(self.assertionValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
case b"DomainSid": {
|
case b"DomainSid": {
|
||||||
self.assertionValueDecoded = bytes_sid_to_SID_repr(self.assertionValue);
|
self.assertionValueDecoded = bytes_sid_to_SID_repr(self.assertionValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
case b"NtVer": {
|
case b"NtVer": {
|
||||||
self.assertionValueDecoded = uint32_to_hex_repr(self.assertionValue);
|
self.assertionValueDecoded = uint32_to_hex_repr(self.assertionValue);
|
||||||
}
|
}
|
||||||
|
@ -933,31 +903,18 @@ type SearchFilter = unit {
|
||||||
switch (self.filterType) {
|
switch (self.filterType) {
|
||||||
|
|
||||||
# FilterTypes that hold one or more SearchFilters inside them
|
# FilterTypes that hold one or more SearchFilters inside them
|
||||||
|
FilterType::FILTER_AND -> FILTER_AND: ParseNestedAndOr() &parse-from=self.filterBytes;
|
||||||
FilterType::FILTER_AND -> FILTER_AND: ParseNestedAndOr()
|
FilterType::FILTER_OR -> FILTER_OR: ParseNestedAndOr() &parse-from=self.filterBytes;
|
||||||
&parse-from=self.filterBytes;
|
FilterType::FILTER_NOT -> FILTER_NOT: ParseNestedNot() &parse-from=self.filterBytes;
|
||||||
FilterType::FILTER_OR -> FILTER_OR: ParseNestedAndOr()
|
|
||||||
&parse-from=self.filterBytes;
|
|
||||||
FilterType::FILTER_NOT -> FILTER_NOT: ParseNestedNot()
|
|
||||||
&parse-from=self.filterBytes;
|
|
||||||
|
|
||||||
# FilterTypes that we can actually convert to a string
|
# FilterTypes that we can actually convert to a string
|
||||||
|
FilterType::FILTER_EQ -> FILTER_EQ: DecodedAttributeValue(FilterType::FILTER_EQ) &parse-from=self.filterBytes;
|
||||||
FilterType::FILTER_EQ -> FILTER_EQ: DecodedAttributeValue(FilterType::FILTER_EQ)
|
FilterType::FILTER_SUBSTR -> FILTER_SUBSTR: SubstringFilter &parse-from=self.filterBytes;
|
||||||
&parse-from=self.filterBytes;
|
FilterType::FILTER_GE -> FILTER_GE: DecodedAttributeValue(FilterType::FILTER_GE) &parse-from=self.filterBytes;
|
||||||
FilterType::FILTER_SUBSTR -> FILTER_SUBSTR: SubstringFilter
|
FilterType::FILTER_LE -> FILTER_LE: DecodedAttributeValue(FilterType::FILTER_LE) &parse-from=self.filterBytes;
|
||||||
&parse-from=self.filterBytes;
|
FilterType::FILTER_APPROX -> FILTER_APPROX: DecodedAttributeValue(FilterType::FILTER_APPROX) &parse-from=self.filterBytes;
|
||||||
FilterType::FILTER_GE -> FILTER_GE: DecodedAttributeValue(FilterType::FILTER_GE)
|
FilterType::FILTER_EXT -> FILTER_EXT: DecodedAttributeValue(FilterType::FILTER_EXT) &parse-from=self.filterBytes;
|
||||||
&parse-from=self.filterBytes;
|
FilterType::FILTER_PRESENT -> FILTER_PRESENT: ASN1::ASN1OctetString(self.filterLen, False) &convert=$$.value.decode(spicy::Charset::ASCII) &parse-from=self.filterBytes;
|
||||||
FilterType::FILTER_LE -> FILTER_LE: DecodedAttributeValue(FilterType::FILTER_LE)
|
|
||||||
&parse-from=self.filterBytes;
|
|
||||||
FilterType::FILTER_APPROX -> FILTER_APPROX: DecodedAttributeValue(FilterType::FILTER_APPROX)
|
|
||||||
&parse-from=self.filterBytes;
|
|
||||||
FilterType::FILTER_EXT -> FILTER_EXT: DecodedAttributeValue(FilterType::FILTER_EXT)
|
|
||||||
&parse-from=self.filterBytes;
|
|
||||||
FilterType::FILTER_PRESENT -> FILTER_PRESENT: ASN1::ASN1OctetString(self.filterLen, False)
|
|
||||||
&convert=$$.value.decode(spicy::Charset::ASCII)
|
|
||||||
&parse-from=self.filterBytes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# So when you're done with recursively parsing the filters, we can now leverage the tree structure to
|
# So when you're done with recursively parsing the filters, we can now leverage the tree structure to
|
||||||
|
@ -970,19 +927,16 @@ type SearchFilter = unit {
|
||||||
on %error {
|
on %error {
|
||||||
self.stringRepresentation = "FILTER_PARSING_ERROR";
|
self.stringRepresentation = "FILTER_PARSING_ERROR";
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public type SearchRequest = unit(inout message: Message) {
|
public type SearchRequest = unit(inout message: Message) {
|
||||||
baseObject: ASN1::ASN1Message(True) &convert=$$.body.str_value {
|
baseObject: ASN1::ASN1Message(True) &convert=$$.body.str_value {
|
||||||
message.obj = self.baseObject;
|
message.obj = self.baseObject;
|
||||||
}
|
}
|
||||||
scope: ASN1::ASN1Message(True) &convert=cast<SearchScope>(cast<uint8>($$.body.num_value))
|
scope: ASN1::ASN1Message(True) &convert=cast<SearchScope>(cast<uint8>($$.body.num_value)) &default=SearchScope::Undef {
|
||||||
&default=SearchScope::Undef {
|
|
||||||
message.arg = "%s" % self.scope;
|
message.arg = "%s" % self.scope;
|
||||||
}
|
}
|
||||||
deref: ASN1::ASN1Message(True) &convert=cast<SearchDerefAlias>(cast<uint8>($$.body.num_value))
|
deref: ASN1::ASN1Message(True) &convert=cast<SearchDerefAlias>(cast<uint8>($$.body.num_value)) &default=SearchDerefAlias::Undef;
|
||||||
&default=SearchDerefAlias::Undef;
|
|
||||||
sizeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0;
|
sizeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0;
|
||||||
timeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0;
|
timeLimit: ASN1::ASN1Message(True) &convert=$$.body.num_value &default=0;
|
||||||
typesOnly: ASN1::ASN1Message(True) &convert=$$.body.bool_value &default=False;
|
typesOnly: ASN1::ASN1Message(True) &convert=$$.body.bool_value &default=False;
|
||||||
|
@ -1110,9 +1064,7 @@ type ExtendedRequest = unit(inout message: Message, ctx: Ctx&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# If there's more byte to parse, it's the requestValue.
|
# If there's more byte to parse, it's the requestValue.
|
||||||
: ASN1::ASN1Message(False)
|
: ASN1::ASN1Message(False) &requires=($$.head.tag.class == ASN1::ASN1Class::ContextSpecific) if(message.opLen > self.offset()) {
|
||||||
&requires=($$.head.tag.class == ASN1::ASN1Class::ContextSpecific)
|
|
||||||
if ( message.opLen > self.offset() ) {
|
|
||||||
|
|
||||||
self.requestValue = $$.application_data;
|
self.requestValue = $$.application_data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,7 @@ import spicy;
|
||||||
import zeek;
|
import zeek;
|
||||||
|
|
||||||
# The interface to the C++ code that handles the decryption of the INITIAL packet payload using well-known keys
|
# The interface to the C++ code that handles the decryption of the INITIAL packet payload using well-known keys
|
||||||
public function decrypt_crypto_payload(
|
public function decrypt_crypto_payload(version: uint32, data: bytes, connection_id: bytes, encrypted_offset: uint64, payload_offset: uint64, from_client: bool): bytes &cxxname="QUIC_decrypt_crypto_payload";
|
||||||
version: uint32,
|
|
||||||
data: bytes,
|
|
||||||
connection_id: bytes,
|
|
||||||
encrypted_offset: uint64,
|
|
||||||
payload_offset: uint64,
|
|
||||||
from_client: bool
|
|
||||||
): bytes &cxxname="QUIC_decrypt_crypto_payload";
|
|
||||||
|
|
||||||
|
|
||||||
# Can we decrypt?
|
# Can we decrypt?
|
||||||
function can_decrypt(long_header: LongHeaderPacket, context: Context, crypto: CryptoSinkUnit&): bool {
|
function can_decrypt(long_header: LongHeaderPacket, context: Context, crypto: CryptoSinkUnit&): bool {
|
||||||
|
@ -76,7 +68,8 @@ type CryptoSinkUnit = unit(is_orig: bool, context: Context&) {
|
||||||
self.buffered += $$[2];
|
self.buffered += $$[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
: void &requires=(self.length <= 2**14 + 256) { # The length MUST NOT exceed 2^14 + 256 bytes (RFC 8446)
|
: void &requires=(self.length <= 2**14 + 256) {
|
||||||
|
# The length MUST NOT exceed 2^14 + 256 bytes (RFC 8446)
|
||||||
|
|
||||||
# The client or server hello data is forwarded to the SSL analyzer as a
|
# The client or server hello data is forwarded to the SSL analyzer as a
|
||||||
# TLSPlaintext record with legacy_record_version set to \x03\x03 (1.3).
|
# TLSPlaintext record with legacy_record_version set to \x03\x03 (1.3).
|
||||||
|
@ -246,13 +239,9 @@ public type LongHeaderPacketV1 = unit(inout outer: LongHeaderPacket) {
|
||||||
switch (LongPacketTypeV1(outer.first_byte.packet_type)) {
|
switch (LongPacketTypeV1(outer.first_byte.packet_type)) {
|
||||||
LongPacketTypeV1::INITIAL -> initial_hdr: InitialPacket(outer) {
|
LongPacketTypeV1::INITIAL -> initial_hdr: InitialPacket(outer) {
|
||||||
outer.is_initial = True;
|
outer.is_initial = True;
|
||||||
outer.encrypted_offset = outer.offset() +
|
outer.encrypted_offset = outer.offset() + self.initial_hdr.length.bytes_to_parse + self.initial_hdr.token_length.bytes_to_parse + self.initial_hdr.token_length.result_;
|
||||||
self.initial_hdr.length.bytes_to_parse +
|
|
||||||
self.initial_hdr.token_length.bytes_to_parse +
|
|
||||||
self.initial_hdr.token_length.result_;
|
|
||||||
outer.payload_length = self.initial_hdr.length.result_;
|
outer.payload_length = self.initial_hdr.length.result_;
|
||||||
}
|
}
|
||||||
|
|
||||||
LongPacketTypeV1::ZERO_RTT -> zerortt_hdr: ZeroRTTPacket(outer);
|
LongPacketTypeV1::ZERO_RTT -> zerortt_hdr: ZeroRTTPacket(outer);
|
||||||
LongPacketTypeV1::HANDSHAKE -> handshake_hdr: HandshakePacket(outer);
|
LongPacketTypeV1::HANDSHAKE -> handshake_hdr: HandshakePacket(outer);
|
||||||
LongPacketTypeV1::RETRY -> retry_hdr: RetryPacket(outer) {
|
LongPacketTypeV1::RETRY -> retry_hdr: RetryPacket(outer) {
|
||||||
|
@ -265,13 +254,9 @@ public type LongHeaderPacketV2 = unit(inout outer: LongHeaderPacket) {
|
||||||
switch (LongPacketTypeV2(outer.first_byte.packet_type)) {
|
switch (LongPacketTypeV2(outer.first_byte.packet_type)) {
|
||||||
LongPacketTypeV2::INITIAL -> initial_hdr: InitialPacket(outer) {
|
LongPacketTypeV2::INITIAL -> initial_hdr: InitialPacket(outer) {
|
||||||
outer.is_initial = True;
|
outer.is_initial = True;
|
||||||
outer.encrypted_offset = outer.offset() +
|
outer.encrypted_offset = outer.offset() + self.initial_hdr.length.bytes_to_parse + self.initial_hdr.token_length.bytes_to_parse + self.initial_hdr.token_length.result_;
|
||||||
self.initial_hdr.length.bytes_to_parse +
|
|
||||||
self.initial_hdr.token_length.bytes_to_parse +
|
|
||||||
self.initial_hdr.token_length.result_;
|
|
||||||
outer.payload_length = self.initial_hdr.length.result_;
|
outer.payload_length = self.initial_hdr.length.result_;
|
||||||
}
|
}
|
||||||
|
|
||||||
LongPacketTypeV2::ZERO_RTT -> zerortt_hdr: ZeroRTTPacket(outer);
|
LongPacketTypeV2::ZERO_RTT -> zerortt_hdr: ZeroRTTPacket(outer);
|
||||||
LongPacketTypeV2::HANDSHAKE -> handshake_hdr: HandshakePacket(outer);
|
LongPacketTypeV2::HANDSHAKE -> handshake_hdr: HandshakePacket(outer);
|
||||||
LongPacketTypeV2::RETRY -> retry_hdr: RetryPacket(outer) {
|
LongPacketTypeV2::RETRY -> retry_hdr: RetryPacket(outer) {
|
||||||
|
@ -302,9 +287,13 @@ public type LongHeaderPacket = unit {
|
||||||
};
|
};
|
||||||
|
|
||||||
version: uint32;
|
version: uint32;
|
||||||
dest_conn_id_len: uint8 { self.server_conn_id_length = $$; }
|
dest_conn_id_len: uint8 {
|
||||||
|
self.server_conn_id_length = $$;
|
||||||
|
}
|
||||||
dest_conn_id: bytes &size=self.server_conn_id_length;
|
dest_conn_id: bytes &size=self.server_conn_id_length;
|
||||||
src_conn_id_len: uint8 { self.client_conn_id_length = $$; }
|
src_conn_id_len: uint8 {
|
||||||
|
self.client_conn_id_length = $$;
|
||||||
|
}
|
||||||
src_conn_id: bytes &size=self.client_conn_id_length;
|
src_conn_id: bytes &size=self.client_conn_id_length;
|
||||||
|
|
||||||
switch (self.version) {
|
switch (self.version) {
|
||||||
|
@ -407,7 +396,6 @@ type ConnectionClosePayload = unit(header: LongHeaderPacket) {
|
||||||
reason_phrase: bytes &size=self.reason_phrase_length.result_;
|
reason_phrase: bytes &size=self.reason_phrase_length.result_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# Long packets
|
# Long packets
|
||||||
# Specific long packet type units
|
# Specific long packet type units
|
||||||
|
@ -448,7 +436,6 @@ type HandshakePacket = unit(header: LongHeaderPacket) {
|
||||||
payload: skip bytes &size=self.length.result_;
|
payload: skip bytes &size=self.length.result_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
type RetryPacket = unit(header: LongHeaderPacket) {
|
type RetryPacket = unit(header: LongHeaderPacket) {
|
||||||
var header: LongHeaderPacket = header;
|
var header: LongHeaderPacket = header;
|
||||||
var retry_token: bytes;
|
var retry_token: bytes;
|
||||||
|
@ -585,7 +572,6 @@ type Packet = unit(from_client: bool, context: Context&) {
|
||||||
self.long_header.payload_length,
|
self.long_header.payload_length,
|
||||||
from_client
|
from_client
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
context.server_cid_len = self.long_header.src_conn_id_len;
|
context.server_cid_len = self.long_header.src_conn_id_len;
|
||||||
context.client_cid_len = self.long_header.dest_conn_id_len;
|
context.client_cid_len = self.long_header.dest_conn_id_len;
|
||||||
|
|
|
@ -12,11 +12,7 @@ const OPCODE_CLOSE = 0x08;
|
||||||
const OPCODE_PING = 0x09;
|
const OPCODE_PING = 0x09;
|
||||||
const OPCODE_PONG = 0x0a;
|
const OPCODE_PONG = 0x0a;
|
||||||
|
|
||||||
public function fast_unmask(
|
public function fast_unmask(masking_key_idx: uint64, masking_key: vector<uint8>, chunk: bytes): bytes &cxxname="hlt_websocket::WebSocket::fast_unmask";
|
||||||
masking_key_idx: uint64,
|
|
||||||
masking_key: vector<uint8>,
|
|
||||||
chunk: bytes
|
|
||||||
): bytes &cxxname="hlt_websocket::WebSocket::fast_unmask";
|
|
||||||
|
|
||||||
type Frame = unit(m: Message) {
|
type Frame = unit(m: Message) {
|
||||||
var payload_len: uint64;
|
var payload_len: uint64;
|
||||||
|
@ -89,7 +85,6 @@ type CloseFrame = unit {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public type Message = unit {
|
public type Message = unit {
|
||||||
# transient trickery
|
# transient trickery
|
||||||
var done: bool = False;
|
var done: bool = False;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue