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

LDAP analyzer #56

Merged
merged 21 commits into from
May 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
de1c46a
Topic/ldap (#1)
mmguero May 10, 2021
3949c90
Added ldap version
mmguero May 10, 2021
599c7a9
added more ldap codes
mmguero May 10, 2021
b5f36c7
don't save both 'bind' and 'bind simple'/'bind SASL' in the operation…
mmguero May 10, 2021
9594f6d
rename ldap.zeek to main.zeek
mmguero May 10, 2021
cd5c670
added ldap test
mmguero May 11, 2021
78ea982
update changes
mmguero May 11, 2021
a666fb5
fix LDAP test (specify -C to zeek)
mmguero May 11, 2021
7cce9bb
void fields never store a value and cannot be named
mmguero May 11, 2021
40fbc83
void fields never store a value and cannot be named
mmguero May 11, 2021
7737a0c
Moving computation for |self.seq.submessages| to temporary local vari…
mmguero May 12, 2021
d403227
changes made after @bbanier's review of PR zeek/spicy-analyzers#56. S…
mmguero May 12, 2021
6edc9ce
changes made after @bbanier's review of PR zeek/spicy-analyzers#56. S…
mmguero May 12, 2021
9d470d1
Added proto (TCP for now, may include UDP in the future ) to the ldap…
mmguero May 12, 2021
0962e6a
update .log files from baseline test to reflect new logs fields
mmguero May 12, 2021
e5e5ffd
Remove analyzer_id from scripts for ipsec.
keithjjones May 13, 2021
bf8b3d7
update changes
mmguero May 11, 2021
8cedba7
Merge remote-tracking branch 'upstream/main' into main
mmguero May 18, 2021
51ec8fd
try to expose less useless stuff in each unit, for zeek/spicy-analyze…
mmguero May 18, 2021
6696428
something in 51ec8fd broke something, this will (should) fix it
mmguero May 18, 2021
3c5ccb4
something in 51ec8fd broke something, this will (should) fix it
mmguero May 18, 2021
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Currently, the following analyzers are included:
- DNS <sup>[1]</sup>
- HTTP <sup>[1]</sup>
- IPSec
- LDAP
- OpenVPN
- PNG
- Portable Executable (PE) <sup>[2]</sup>
Expand Down
1 change: 1 addition & 0 deletions analyzer/__load__.zeek
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@load ./protocol/dns
@load ./protocol/http
@load ./protocol/ipsec
@load ./protocol/ldap
@load ./protocol/openvpn
@load ./protocol/tftp
@load ./protocol/wireguard
1 change: 1 addition & 0 deletions analyzer/protocol/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_subdirectory(dhcp)
add_subdirectory(dns)
add_subdirectory(http)
add_subdirectory(ipsec)
add_subdirectory(ldap)
add_subdirectory(openvpn)
add_subdirectory(tftp)
add_subdirectory(wireguard)
3 changes: 3 additions & 0 deletions analyzer/protocol/ldap/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright (c) 2021 by the Zeek Project. See LICENSE for details.

spicy_add_analyzer(ldap ldap.spicy ldap_zeek.spicy ldap.evt)
mmguero marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions analyzer/protocol/ldap/__load__.zeek
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright (c) 2021 by the Zeek Project. See LICENSE for details.

@load ./main
mmguero marked this conversation as resolved.
Show resolved Hide resolved
286 changes: 286 additions & 0 deletions analyzer/protocol/ldap/asn1.spicy
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
# Copyright (c) 2021 by the Zeek Project. See LICENSE for details.

module asn1;
mmguero marked this conversation as resolved.
Show resolved Hide resolved

###############################################################################
# ASN.1 structure decoding
#
# A Layman's Guide to a Subset of ASN.1, BER, and DER
# http://luca.ntop.org/Teaching/Appunti/asn1.html
#
# ASN.1 Tutorial from Computer Networks and Open Systems:
# An Application Development Perspective
# https://www.obj-sys.com/asn1tutorial/asn1only.html
#
# The ASN1JS tool (http://lapo.it/asn1js and https://github.com/lapo-luchini/asn1js)
# is invaluable in debugging ASN.1
###############################################################################

import spicy;

#- ASN.1 data types ----------------------------------------------------------
# https://www.obj-sys.com/asn1tutorial/node124.html
# https://www.obj-sys.com/asn1tutorial/node10.html

public type ASN1Type = enum {
Boolean = 1,
Integer = 2,
BitString = 3,
OctetString = 4,
NullVal = 5,
ObjectIdentifier = 6,
ObjectDescriptor = 7,
mmguero marked this conversation as resolved.
Show resolved Hide resolved
InstanceOf = 8,
Real = 9,
Enumerated = 10,
EmbeddedPDV = 11,
UTF8String = 12,
RelativeOID = 13,
Sequence = 16,
Set = 17,
NumericString = 18,
PrintableString = 19,
TeletextString = 20,
VideotextString = 21,
IA5String = 22,
UTCTime = 23,
GeneralizedTime = 24,
GraphicString = 25,
VisibleString = 26,
GeneralString = 27,
UniversalString = 28,
CharacterString = 29,
BMPString = 30
};

#- ASN.1 data classes --------------------------------------------------------

public type ASN1Class = enum {
Universal = 0,
Application = 1,
ContextSpecific = 2,
Private = 3
};

#- ASN.1 tag definition (including length) ------------------------------------

type LengthType = unit {
mmguero marked this conversation as resolved.
Show resolved Hide resolved
var len: uint64;
var tag_len: uint8;

mmguero marked this conversation as resolved.
Show resolved Hide resolved
data : bitfield(8) {
num: 0..6;
islong: 7;
};


switch ( self.data.islong ) {
0 -> : void {
self.len = self.data.num;
self.tag_len = 1;
}
1 -> : bytes &size=self.data.num
&convert=$$.to_uint(spicy::ByteOrder::Network) {
self.len = $$;
self.tag_len = self.data.num + 1;
}
};
};

type ASN1Tag = unit {
var type_: ASN1Type;
var class: ASN1Class;
var constructed: bool;

: bitfield(8) {
num: 0..4;
constructed: 5;
class: 6..7;
} {
self.type_ = ASN1Type($$.num);
self.class = ASN1Class($$.class);
self.constructed = cast<bool>($$.constructed);
}
};

#- ASN.1 bit string -----------------------------------------------------------
# https://www.obj-sys.com/asn1tutorial/node10.html

type ASN1BitString = unit(len: uint64, constructed: bool) {
: uint8; # unused bits
value_bits: bytes &size=(len - 1);

# TODO - constructed form
# https://github.com/zeek/spicy/issues/921
# `bytes` needs << and >> support before we can implement complex bitstrings
mmguero marked this conversation as resolved.
Show resolved Hide resolved
#
};

#- ASN.1 octet string ---------------------------------------------------------
# https://www.obj-sys.com/asn1tutorial/node10.html

type ASN1OctetString = unit(len: uint64, constructed: bool) {
value: bytes &size = len;

# TODO - constructed form
};

#- ASN.1 various string types -------------------------------------------------
# https://www.obj-sys.com/asn1tutorial/node124.html

type ASN1String = unit(tag: ASN1Tag, len: uint64) {
var value: string = "";

: ASN1OctetString(len, tag.constructed) {
switch ( tag.type_ ) {

# see "Restricted Character String Types" in
# "Generic String Encoding Rules (GSER) for ASN.1 Types"
# (https://datatracker.ietf.org/doc/html/rfc3641#section-3.2)

case ASN1Type::PrintableString,
ASN1Type::GeneralizedTime,
ASN1Type::UTCTime: {
self.value = $$.value.decode(hilti::Charset::ASCII);
}

case ASN1Type::UTF8String,
ASN1Type::GeneralString,
ASN1Type::CharacterString,
ASN1Type::GraphicString,
ASN1Type::IA5String,
ASN1Type::NumericString,
ASN1Type::TeletextString,
ASN1Type::VideotextString,
ASN1Type::VisibleString,
# TODO: RFC3641 mentions special UTF-8 mapping rules for
# BMPString and UniversalString. This *may* not be correct.
ASN1Type::BMPString,
ASN1Type::UniversalString: {
self.value = $$.value.decode(hilti::Charset::UTF8);
}
}
}
};

#- ASN.1 OID ------------------------------------------------------------------
# https://www.obj-sys.com/asn1tutorial/node124.html

type ASN1ObjectIdentifierNibble = unit {
data : bitfield(8) {
num: 0..6;
more: 7;
};
} &convert=self.data;

type ASN1ObjectIdentifier = unit(len: uint64) {
var oid: vector<uint64>;
var temp: uint64;
var oidstring: string;

: uint8 if ( len >= 1 ) {
self.temp = $$ / 40;
self.oid.push_back( self.temp );
self.oidstring = "%d" % (self.temp);
self.temp = $$ % 40;
self.oid.push_back( self.temp );
self.oidstring = self.oidstring + ".%d" % (self.temp);
self.temp = 0;
}

sublist: ASN1ObjectIdentifierNibble[len - 1] foreach {
self.temp = ( self.temp<<7 ) | $$.num;
if ( $$.more != 1 ) {
self.oid.push_back(self.temp);
self.oidstring = self.oidstring + ".%d" % (self.temp);
self.temp = 0;
}
}
};


#- ASN.1 message header (tag + length information) ----------------------------

public type ASN1Header = unit {
tag: ASN1Tag;
len: LengthType;
};

#- ASN.1 message body ---------------------------------------------------------

public type ASN1Body = unit(head: ASN1Header, recursive: bool) {
switch ( head.tag.type_ ) {

ASN1Type::Boolean -> bool_value: uint8 &convert=cast<bool>($$) &requires=head.len.len==1;

ASN1Type::Integer,
ASN1Type::Enumerated -> num_value: bytes &size=head.len.len
&convert=$$.to_int(spicy::ByteOrder::Big);

ASN1Type::NullVal -> null_value: bytes &size=0 &requires=head.len.len==0;

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(hilti::Charset::ASCII);

ASN1Type::ObjectIdentifier -> str_value: ASN1ObjectIdentifier(head.len.len)
&convert=$$.oidstring;

ASN1Type::BMPString,
ASN1Type::CharacterString,
ASN1Type::GeneralizedTime,
mmguero marked this conversation as resolved.
Show resolved Hide resolved
ASN1Type::GeneralString,
ASN1Type::GraphicString,
ASN1Type::IA5String,
ASN1Type::NumericString,
ASN1Type::PrintableString,
ASN1Type::TeletextString,
ASN1Type::UTCTime,
ASN1Type::UTF8String,
ASN1Type::VideotextString,
ASN1Type::VisibleString,
ASN1Type::UniversalString -> str_value: ASN1String(head.tag, head.len.len)
&convert=$$.value;

ASN1Type::Sequence, ASN1Type::Set -> seq: ASN1SubMessages(head.len.len) if (recursive);

# TODO: ASN1Type values not handled yet
ASN1Type::ObjectDescriptor,
ASN1Type::InstanceOf,
ASN1Type::Real,
ASN1Type::EmbeddedPDV,
ASN1Type::RelativeOID -> unimplemented_value: bytes &size=head.len.len;

# unknown (to me) ASN.1 enumeration, skip over silently
* -> unimplemented_value: bytes &size=head.len.len;
};
};

#- ASN.1 array of ASN.1 sequence/set sub-messages (up to msgLen bytes) --------

public type ASN1SubMessages = unit(msgLen: uint64) {
submessages: ASN1Message(True)[] &eod;
} &size=msgLen;

#- ASN.1 message with header and body -----------------------------------------
# Universal or Application/ContextSpecific/Private
# - if Universal, body:ASN1Body is parsed
# - else, application_data:bytes stores data array

public type ASN1Message = unit(recursive: bool) {
var application_id: int32;

head: ASN1Header;
switch ( self.head.tag.class ) {

ASN1Class::Universal -> body: ASN1Body(self.head, recursive);

ASN1Class::Application,
ASN1Class::ContextSpecific,
ASN1Class::Private -> application_data: bytes &size=self.head.len.len {
self.application_id = cast<int32>(self.head.tag.type_);
}

};
};
39 changes: 39 additions & 0 deletions analyzer/protocol/ldap/ldap.evt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (c) 2021 by the Zeek Project. See LICENSE for details.

protocol analyzer spicy::ldap_tcp over TCP:
mmguero marked this conversation as resolved.
Show resolved Hide resolved
parse with ldap::Messages,
ports {389/tcp, 3268/tcp};

# TODO: LDAP can also use UDP transport

import ldap;
import ldap_zeek;

on ldap::Message -> event ldap::message($conn,
self.messageID,
self.opcode,
self.result.code,
self.result.matchedDN,
self.result.diagnosticMessage,
self.obj,
self.arg);

on ldap::BindRequest -> event ldap::bindreq($conn,
message.messageID,
self.version,
self.name,
self.authType,
message.arg);

on ldap::SearchRequest -> event ldap::searchreq($conn,
message.messageID,
self.baseObject,
self.scope,
self.deref,
self.sizeLimit,
self.timeLimit,
self.typesOnly);

on ldap::SearchResultEntry -> event ldap::searchres($conn,
message.messageID,
self.objectName);
Loading