mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 16:48:19 +00:00
Pushing out the new NTLM and GSSAPI analyzers.
I accidentally left these out of the previous commit.
This commit is contained in:
parent
5b5589e167
commit
d6e01b7769
18 changed files with 894 additions and 0 deletions
15
src/analyzer/protocol/gssapi/CMakeLists.txt
Normal file
15
src/analyzer/protocol/gssapi/CMakeLists.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
include(BroPlugin)
|
||||||
|
|
||||||
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
bro_plugin_begin(Bro GSSAPI)
|
||||||
|
bro_plugin_cc(GSSAPI.cc Plugin.cc)
|
||||||
|
bro_plugin_bif(types.bif events.bif)
|
||||||
|
bro_plugin_pac(
|
||||||
|
gssapi.pac
|
||||||
|
gssapi-protocol.pac
|
||||||
|
gssapi-analyzer.pac
|
||||||
|
)
|
||||||
|
bro_plugin_end()
|
||||||
|
|
56
src/analyzer/protocol/gssapi/GSSAPI.cc
Normal file
56
src/analyzer/protocol/gssapi/GSSAPI.cc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "GSSAPI.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
|
||||||
|
using namespace analyzer::gssapi;
|
||||||
|
|
||||||
|
GSSAPI_Analyzer::GSSAPI_Analyzer(Connection* c)
|
||||||
|
: tcp::TCP_ApplicationAnalyzer("GSSAPI", c)
|
||||||
|
{
|
||||||
|
interp = new binpac::GSSAPI::GSSAPI_Conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GSSAPI_Analyzer::~GSSAPI_Analyzer()
|
||||||
|
{
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::Done()
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Done();
|
||||||
|
|
||||||
|
interp->FlowEOF(true);
|
||||||
|
interp->FlowEOF(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::EndpointEOF(bool is_orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||||
|
interp->FlowEOF(is_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
|
||||||
|
assert(TCP());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
ProtocolConfirmation();
|
||||||
|
}
|
||||||
|
catch ( const binpac::Exception& e )
|
||||||
|
{
|
||||||
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSSAPI_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||||
|
interp->NewGap(orig, len);
|
||||||
|
}
|
39
src/analyzer/protocol/gssapi/GSSAPI.h
Normal file
39
src/analyzer/protocol/gssapi/GSSAPI.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#ifndef ANALYZER_PROTOCOL_GSSAPI_GSSAPI_H
|
||||||
|
#define ANALYZER_PROTOCOL_GSSAPI_GSSAPI_H
|
||||||
|
|
||||||
|
#include "events.bif.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
|
|
||||||
|
#include "gssapi_pac.h"
|
||||||
|
|
||||||
|
namespace analyzer { namespace gssapi {
|
||||||
|
|
||||||
|
class GSSAPI_Analyzer
|
||||||
|
|
||||||
|
: public tcp::TCP_ApplicationAnalyzer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSSAPI_Analyzer(Connection* conn);
|
||||||
|
virtual ~GSSAPI_Analyzer();
|
||||||
|
|
||||||
|
// Overriden from Analyzer.
|
||||||
|
virtual void Done();
|
||||||
|
|
||||||
|
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||||
|
virtual void Undelivered(uint64 seq, int len, bool orig);
|
||||||
|
|
||||||
|
// Overriden from tcp::TCP_ApplicationAnalyzer.
|
||||||
|
virtual void EndpointEOF(bool is_orig);
|
||||||
|
|
||||||
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
|
{ return new GSSAPI_Analyzer(conn); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binpac::GSSAPI::GSSAPI_Conn* interp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // namespace analyzer::*
|
||||||
|
|
||||||
|
#endif
|
24
src/analyzer/protocol/gssapi/Plugin.cc
Normal file
24
src/analyzer/protocol/gssapi/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// See the file in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "plugin/Plugin.h"
|
||||||
|
|
||||||
|
#include "GSSAPI.h"
|
||||||
|
|
||||||
|
namespace plugin {
|
||||||
|
namespace Bro_GSSAPI {
|
||||||
|
|
||||||
|
class Plugin : public plugin::Plugin {
|
||||||
|
public:
|
||||||
|
plugin::Configuration Configure()
|
||||||
|
{
|
||||||
|
AddComponent(new ::analyzer::Component("GSSAPI", ::analyzer::gssapi::GSSAPI_Analyzer::Instantiate));
|
||||||
|
|
||||||
|
plugin::Configuration config;
|
||||||
|
config.name = "Bro::GSSAPI";
|
||||||
|
config.description = "GSSAPI analyzer";
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
} plugin;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
5
src/analyzer/protocol/gssapi/events.bif
Normal file
5
src/analyzer/protocol/gssapi/events.bif
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
## Generated for GSSAPI messages of type *accept-completed*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
event gssapi_accepted%(c: connection%);
|
49
src/analyzer/protocol/gssapi/gssapi-analyzer.pac
Normal file
49
src/analyzer/protocol/gssapi/gssapi-analyzer.pac
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
refine connection GSSAPI_Conn += {
|
||||||
|
%member{
|
||||||
|
analyzer::Analyzer *ntlm;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
ntlm = analyzer_mgr->InstantiateAnalyzer("NTLM", bro_analyzer->Conn());
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
if ( ntlm )
|
||||||
|
delete ntlm;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function forward_ntlm(data: bytestring, is_orig: bool): bool
|
||||||
|
%{
|
||||||
|
if ( ntlm )
|
||||||
|
ntlm->DeliverStream(${data}.length(), ${data}.begin(), is_orig);
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_gssapi_neg_token(val: GSSAPI_NEG_TOKEN): bool
|
||||||
|
%{
|
||||||
|
if ( ${val.is_init} )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for ( uint i = 0; i < ${val.resp.args}->size(); ++i )
|
||||||
|
{
|
||||||
|
switch ( ${val.resp.args[i].seq_meta.index} )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if ( ${val.resp.args[i].args.neg_state} == 0 )
|
||||||
|
{
|
||||||
|
BifEvent::generate_gssapi_accepted(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
}
|
||||||
|
|
||||||
|
refine typeattr GSSAPI_NEG_TOKEN += &let {
|
||||||
|
proc : bool = $context.connection.proc_gssapi_neg_token(this);
|
||||||
|
};
|
56
src/analyzer/protocol/gssapi/gssapi-protocol.pac
Normal file
56
src/analyzer/protocol/gssapi/gssapi-protocol.pac
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN(is_orig: bool) = record {
|
||||||
|
wrapper : ASN1EncodingMeta;
|
||||||
|
have_oid : case is_init of {
|
||||||
|
true -> oid : ASN1Encoding;
|
||||||
|
false -> no_oid : empty;
|
||||||
|
};
|
||||||
|
have_init_wrapper : case is_init of {
|
||||||
|
true -> init_wrapper : ASN1EncodingMeta;
|
||||||
|
false -> no_init_wrapper : empty;
|
||||||
|
};
|
||||||
|
msg_type : case is_init of {
|
||||||
|
true -> init : GSSAPI_NEG_TOKEN_INIT;
|
||||||
|
false -> resp : GSSAPI_NEG_TOKEN_RESP;
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
is_init: bool = wrapper.tag == 0x60;
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_INIT = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_INIT_Arg[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_INIT_Arg = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_INIT_Arg_Data(seq_meta.index) &length=seq_meta.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_INIT_Arg_Data(index: uint8) = case index of {
|
||||||
|
0 -> mech_type_list : ASN1Encoding;
|
||||||
|
1 -> req_flags : ASN1Encoding;
|
||||||
|
2 -> mech_token : bytestring &restofdata;
|
||||||
|
3 -> mech_list_mic : ASN1OctetString;
|
||||||
|
} &let {
|
||||||
|
fwd: bool = $context.connection.forward_ntlm(mech_token, true) &if(index==2);
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_RESP = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_RESP_Arg[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_RESP_Arg = record {
|
||||||
|
seq_meta : ASN1EncodingMeta;
|
||||||
|
args : GSSAPI_NEG_TOKEN_RESP_Arg_Data(seq_meta.index) &length=seq_meta.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GSSAPI_NEG_TOKEN_RESP_Arg_Data(index: uint8) = case index of {
|
||||||
|
0 -> neg_state : ASN1Integer;
|
||||||
|
1 -> supported_mech : ASN1Encoding;
|
||||||
|
2 -> response_token : bytestring &restofdata;
|
||||||
|
3 -> mech_list_mic : ASN1OctetString;
|
||||||
|
} &let {
|
||||||
|
fwd: bool = $context.connection.forward_ntlm(response_token, false) &if(index==2);
|
||||||
|
};
|
30
src/analyzer/protocol/gssapi/gssapi.pac
Normal file
30
src/analyzer/protocol/gssapi/gssapi.pac
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
%include binpac.pac
|
||||||
|
%include bro.pac
|
||||||
|
|
||||||
|
%extern{
|
||||||
|
#include "analyzer/Manager.h"
|
||||||
|
#include "analyzer/Analyzer.h"
|
||||||
|
|
||||||
|
#include "types.bif.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
analyzer GSSAPI withcontext {
|
||||||
|
connection : GSSAPI_Conn;
|
||||||
|
flow : GSSAPI_Flow;
|
||||||
|
};
|
||||||
|
|
||||||
|
connection GSSAPI_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = GSSAPI_Flow(true);
|
||||||
|
downflow = GSSAPI_Flow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include gssapi-protocol.pac
|
||||||
|
%include ../asn1/asn1.pac
|
||||||
|
|
||||||
|
# Now we define the flow:
|
||||||
|
flow GSSAPI_Flow(is_orig: bool) {
|
||||||
|
datagram = GSSAPI_NEG_TOKEN(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include gssapi-analyzer.pac
|
0
src/analyzer/protocol/gssapi/types.bif
Normal file
0
src/analyzer/protocol/gssapi/types.bif
Normal file
15
src/analyzer/protocol/ntlm/CMakeLists.txt
Normal file
15
src/analyzer/protocol/ntlm/CMakeLists.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
include(BroPlugin)
|
||||||
|
|
||||||
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
bro_plugin_begin(Bro NTLM)
|
||||||
|
bro_plugin_cc(NTLM.cc Plugin.cc)
|
||||||
|
bro_plugin_bif(types.bif events.bif)
|
||||||
|
bro_plugin_pac(
|
||||||
|
ntlm.pac
|
||||||
|
ntlm-protocol.pac
|
||||||
|
ntlm-analyzer.pac
|
||||||
|
)
|
||||||
|
bro_plugin_end()
|
||||||
|
|
56
src/analyzer/protocol/ntlm/NTLM.cc
Normal file
56
src/analyzer/protocol/ntlm/NTLM.cc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "NTLM.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
|
||||||
|
using namespace analyzer::ntlm;
|
||||||
|
|
||||||
|
NTLM_Analyzer::NTLM_Analyzer(Connection* c)
|
||||||
|
: tcp::TCP_ApplicationAnalyzer("NTLM", c)
|
||||||
|
{
|
||||||
|
interp = new binpac::NTLM::NTLM_Conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NTLM_Analyzer::~NTLM_Analyzer()
|
||||||
|
{
|
||||||
|
delete interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::Done()
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Done();
|
||||||
|
|
||||||
|
interp->FlowEOF(true);
|
||||||
|
interp->FlowEOF(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::EndpointEOF(bool is_orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||||
|
interp->FlowEOF(is_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
|
||||||
|
assert(TCP());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
interp->NewData(orig, data, data + len);
|
||||||
|
ProtocolConfirmation();
|
||||||
|
}
|
||||||
|
catch ( const binpac::Exception& e )
|
||||||
|
{
|
||||||
|
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTLM_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
||||||
|
{
|
||||||
|
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||||
|
interp->NewGap(orig, len);
|
||||||
|
}
|
39
src/analyzer/protocol/ntlm/NTLM.h
Normal file
39
src/analyzer/protocol/ntlm/NTLM.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#ifndef ANALYZER_PROTOCOL_NTLM_NTLM_H
|
||||||
|
#define ANALYZER_PROTOCOL_NTLM_NTLM_H
|
||||||
|
|
||||||
|
#include "events.bif.h"
|
||||||
|
#include "analyzer/protocol/tcp/TCP.h"
|
||||||
|
|
||||||
|
#include "ntlm_pac.h"
|
||||||
|
|
||||||
|
namespace analyzer { namespace ntlm {
|
||||||
|
|
||||||
|
class NTLM_Analyzer
|
||||||
|
|
||||||
|
: public tcp::TCP_ApplicationAnalyzer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
NTLM_Analyzer(Connection* conn);
|
||||||
|
virtual ~NTLM_Analyzer();
|
||||||
|
|
||||||
|
// Overriden from Analyzer.
|
||||||
|
virtual void Done();
|
||||||
|
|
||||||
|
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||||
|
virtual void Undelivered(uint64 seq, int len, bool orig);
|
||||||
|
|
||||||
|
// Overriden from tcp::TCP_ApplicationAnalyzer.
|
||||||
|
virtual void EndpointEOF(bool is_orig);
|
||||||
|
|
||||||
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
|
{ return new NTLM_Analyzer(conn); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
binpac::NTLM::NTLM_Conn* interp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // namespace analyzer::*
|
||||||
|
|
||||||
|
#endif
|
24
src/analyzer/protocol/ntlm/Plugin.cc
Normal file
24
src/analyzer/protocol/ntlm/Plugin.cc
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// See the file in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "plugin/Plugin.h"
|
||||||
|
|
||||||
|
#include "NTLM.h"
|
||||||
|
|
||||||
|
namespace plugin {
|
||||||
|
namespace Bro_NTLM {
|
||||||
|
|
||||||
|
class Plugin : public plugin::Plugin {
|
||||||
|
public:
|
||||||
|
plugin::Configuration Configure()
|
||||||
|
{
|
||||||
|
AddComponent(new ::analyzer::Component("NTLM", ::analyzer::ntlm::NTLM_Analyzer::Instantiate));
|
||||||
|
|
||||||
|
plugin::Configuration config;
|
||||||
|
config.name = "Bro::NTLM";
|
||||||
|
config.description = "NTLM analyzer";
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
} plugin;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
23
src/analyzer/protocol/ntlm/events.bif
Normal file
23
src/analyzer/protocol/ntlm/events.bif
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
## Generated for NTLM messages of type *negotiate*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||||
|
##
|
||||||
|
event ntlm_negotiate%(c: connection, negotiate: NTLM::Negotiate%);
|
||||||
|
|
||||||
|
## Generated for NTLM messages of type *challenge*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## negotiate: The parsed data of the NTLM message. See init-bare for more details.
|
||||||
|
##
|
||||||
|
event ntlm_challenge%(c: connection, challenge: NTLM::Challenge%);
|
||||||
|
|
||||||
|
## Generated for NTLM messages of type *authenticate*.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## request: The parsed data of the NTLM message. See init-bare for more details.
|
||||||
|
##
|
||||||
|
event ntlm_authenticate%(c: connection, request: NTLM::Authenticate%);
|
223
src/analyzer/protocol/ntlm/ntlm-analyzer.pac
Normal file
223
src/analyzer/protocol/ntlm/ntlm-analyzer.pac
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
|
||||||
|
%extern{
|
||||||
|
#include "ConvertUTF.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
refine connection NTLM_Conn += {
|
||||||
|
|
||||||
|
# This is copied from the RDP analyzer :(
|
||||||
|
function utf16_to_utf8_val(utf16: bytestring): StringVal
|
||||||
|
%{
|
||||||
|
std::string resultstring;
|
||||||
|
|
||||||
|
size_t utf8size = (3 * utf16.length() + 1);
|
||||||
|
|
||||||
|
if ( utf8size > resultstring.max_size() )
|
||||||
|
{
|
||||||
|
bro_analyzer()->Weird("excessive_utf16_length");
|
||||||
|
// If the conversion didn't go well, return the original data.
|
||||||
|
return bytestring_to_val(utf16);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultstring.resize(utf8size, '\0');
|
||||||
|
|
||||||
|
// We can't assume that the string data is properly aligned
|
||||||
|
// here, so make a copy.
|
||||||
|
UTF16 utf16_copy[utf16.length()]; // Twice as much memory than necessary.
|
||||||
|
memcpy(utf16_copy, utf16.begin(), utf16.length());
|
||||||
|
|
||||||
|
const char* utf16_copy_end = reinterpret_cast<const char*>(utf16_copy) + utf16.length();
|
||||||
|
const UTF16* sourcestart = utf16_copy;
|
||||||
|
const UTF16* sourceend = reinterpret_cast<const UTF16*>(utf16_copy_end);
|
||||||
|
|
||||||
|
UTF8* targetstart = reinterpret_cast<UTF8*>(&resultstring[0]);
|
||||||
|
UTF8* targetend = targetstart + utf8size;
|
||||||
|
|
||||||
|
ConversionResult res = ConvertUTF16toUTF8(&sourcestart,
|
||||||
|
sourceend,
|
||||||
|
&targetstart,
|
||||||
|
targetend,
|
||||||
|
lenientConversion);
|
||||||
|
if ( res != conversionOK )
|
||||||
|
{
|
||||||
|
bro_analyzer()->Weird("utf16_conversion_failed");
|
||||||
|
// If the conversion didn't go well, return the original data.
|
||||||
|
return bytestring_to_val(utf16);
|
||||||
|
}
|
||||||
|
|
||||||
|
*targetstart = 0;
|
||||||
|
|
||||||
|
// We're relying on no nulls being in the string.
|
||||||
|
//return new StringVal(resultstring.length(), (const char *) resultstring.data());
|
||||||
|
return new StringVal(resultstring.c_str());
|
||||||
|
%}
|
||||||
|
|
||||||
|
# This is replicated from the SMB analyzer. :(
|
||||||
|
function filetime2brotime(ts: uint64): Val
|
||||||
|
%{
|
||||||
|
double secs = (ts / 10000000.0);
|
||||||
|
|
||||||
|
// Bro can't support times back to the 1600's
|
||||||
|
// so we subtract a lot of seconds.
|
||||||
|
Val* bro_ts = new Val(secs - 11644473600.0, TYPE_TIME);
|
||||||
|
|
||||||
|
return bro_ts;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function build_version_record(val: NTLM_Version): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Version);
|
||||||
|
result->Assign(0, new Val(${val.major_version}, TYPE_COUNT));
|
||||||
|
result->Assign(1, new Val(${val.minor_version}, TYPE_COUNT));
|
||||||
|
result->Assign(2, new Val(${val.build_number}, TYPE_COUNT));
|
||||||
|
result->Assign(3, new Val(${val.ntlm_revision}, TYPE_COUNT));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function build_av_record(val: NTLM_AV_Pair_Sequence): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::AVs);
|
||||||
|
for ( uint i = 0; ${val.pairs[i].id} != 0; i++ )
|
||||||
|
{
|
||||||
|
switch ( ${val.pairs[i].id} )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
result->Assign(0, utf16_to_utf8_val(${val.pairs[i].nb_computer_name.data}));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result->Assign(1, utf16_to_utf8_val(${val.pairs[i].nb_domain_name.data}));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
result->Assign(2, utf16_to_utf8_val(${val.pairs[i].dns_computer_name.data}));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
result->Assign(3, utf16_to_utf8_val(${val.pairs[i].dns_domain_name.data}));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
result->Assign(4, utf16_to_utf8_val(${val.pairs[i].dns_tree_name.data}));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
result->Assign(5, new Val(${val.pairs[i].constrained_auth}, TYPE_BOOL));
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
result->Assign(6, filetime2brotime(${val.pairs[i].timestamp}));
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
result->Assign(7, new Val(${val.pairs[i].single_host.machine_id}, TYPE_COUNT));
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
result->Assign(8, utf16_to_utf8_val(${val.pairs[i].target_name.data}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function build_negotiate_flag_record(val: NTLM_Negotiate_Flags): BroVal
|
||||||
|
%{
|
||||||
|
RecordVal* flags = new RecordVal(BifType::Record::NTLM::NegotiateFlags);
|
||||||
|
flags->Assign(0, new Val(${val.negotiate_56}, TYPE_BOOL));
|
||||||
|
flags->Assign(1, new Val(${val.negotiate_key_exch}, TYPE_BOOL));
|
||||||
|
flags->Assign(2, new Val(${val.negotiate_128}, TYPE_BOOL));
|
||||||
|
flags->Assign(3, new Val(${val.negotiate_version}, TYPE_BOOL));
|
||||||
|
flags->Assign(4, new Val(${val.negotiate_target_info}, TYPE_BOOL));
|
||||||
|
flags->Assign(5, new Val(${val.request_non_nt_session_key}, TYPE_BOOL));
|
||||||
|
flags->Assign(6, new Val(${val.negotiate_identify}, TYPE_BOOL));
|
||||||
|
flags->Assign(7, new Val(${val.negotiate_extended_sessionsecurity}, TYPE_BOOL));
|
||||||
|
flags->Assign(8, new Val(${val.target_type_server}, TYPE_BOOL));
|
||||||
|
flags->Assign(9, new Val(${val.target_type_domain}, TYPE_BOOL));
|
||||||
|
flags->Assign(10, new Val(${val.negotiate_always_sign}, TYPE_BOOL));
|
||||||
|
flags->Assign(11, new Val(${val.negotiate_oem_workstation_supplied}, TYPE_BOOL));
|
||||||
|
flags->Assign(12, new Val(${val.negotiate_oem_domain_supplied}, TYPE_BOOL));
|
||||||
|
flags->Assign(13, new Val(${val.negotiate_anonymous_connection}, TYPE_BOOL));
|
||||||
|
flags->Assign(14, new Val(${val.negotiate_ntlm}, TYPE_BOOL));
|
||||||
|
flags->Assign(15, new Val(${val.negotiate_lm_key}, TYPE_BOOL));
|
||||||
|
flags->Assign(16, new Val(${val.negotiate_datagram}, TYPE_BOOL));
|
||||||
|
flags->Assign(17, new Val(${val.negotiate_seal}, TYPE_BOOL));
|
||||||
|
flags->Assign(18, new Val(${val.negotiate_sign}, TYPE_BOOL));
|
||||||
|
flags->Assign(19, new Val(${val.request_target}, TYPE_BOOL));
|
||||||
|
flags->Assign(20, new Val(${val.negotiate_oem}, TYPE_BOOL));
|
||||||
|
flags->Assign(21, new Val(${val.negotiate_unicode}, TYPE_BOOL));
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_ntlm_negotiate(val: NTLM_Negotiate): bool
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Negotiate);
|
||||||
|
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_oem_domain_supplied} )
|
||||||
|
result->Assign(1, utf16_to_utf8_val(${val.domain_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_oem_workstation_supplied} )
|
||||||
|
result->Assign(2, utf16_to_utf8_val(${val.workstation.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_version} )
|
||||||
|
result->Assign(3, build_version_record(${val.version}));
|
||||||
|
|
||||||
|
BifEvent::generate_ntlm_negotiate(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
result);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_ntlm_challenge(val: NTLM_Challenge): bool
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Challenge);
|
||||||
|
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||||
|
|
||||||
|
if ( ${val.flags.request_target} )
|
||||||
|
result->Assign(1, utf16_to_utf8_val(${val.target_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_version} )
|
||||||
|
result->Assign(2, build_version_record(${val.version}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_target_info} )
|
||||||
|
result->Assign(3, build_av_record(${val.target_info}));
|
||||||
|
|
||||||
|
BifEvent::generate_ntlm_challenge(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
result);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_ntlm_authenticate(val: NTLM_Authenticate): bool
|
||||||
|
%{
|
||||||
|
RecordVal* result = new RecordVal(BifType::Record::NTLM::Authenticate);
|
||||||
|
result->Assign(0, build_negotiate_flag_record(${val.flags}));
|
||||||
|
|
||||||
|
if ( ${val.domain_name_fields.length} > 0 )
|
||||||
|
result->Assign(1, utf16_to_utf8_val(${val.domain_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.user_name_fields.length} > 0 )
|
||||||
|
result->Assign(2, utf16_to_utf8_val(${val.user_name.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.workstation_fields.length} > 0 )
|
||||||
|
result->Assign(3, utf16_to_utf8_val(${val.workstation.string.data}));
|
||||||
|
|
||||||
|
if ( ${val.flags.negotiate_version} )
|
||||||
|
result->Assign(4, build_version_record(${val.version}));
|
||||||
|
|
||||||
|
BifEvent::generate_ntlm_authenticate(bro_analyzer(),
|
||||||
|
bro_analyzer()->Conn(),
|
||||||
|
result);
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
}
|
||||||
|
|
||||||
|
refine typeattr NTLM_Negotiate += &let {
|
||||||
|
proc = $context.connection.proc_ntlm_negotiate(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr NTLM_Challenge += &let {
|
||||||
|
proc : bool = $context.connection.proc_ntlm_challenge(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
refine typeattr NTLM_Authenticate += &let {
|
||||||
|
proc : bool = $context.connection.proc_ntlm_authenticate(this);
|
||||||
|
};
|
||||||
|
|
201
src/analyzer/protocol/ntlm/ntlm-protocol.pac
Normal file
201
src/analyzer/protocol/ntlm/ntlm-protocol.pac
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
|
||||||
|
type NTLM_SSP_Token(is_orig: bool) = record {
|
||||||
|
meta : ASN1EncodingMeta;
|
||||||
|
signature : bytestring &length=8;
|
||||||
|
msg_type : uint32;
|
||||||
|
msg : case msg_type of {
|
||||||
|
1 -> negotiate : NTLM_Negotiate(offsetof(msg) - offsetof(signature));
|
||||||
|
2 -> challenge : NTLM_Challenge(offsetof(msg) - offsetof(signature));
|
||||||
|
3 -> authenticate : NTLM_Authenticate(offsetof(msg) - offsetof(signature));
|
||||||
|
default -> def : bytestring &restofdata &transient;
|
||||||
|
};
|
||||||
|
} &byteorder=littleendian;
|
||||||
|
|
||||||
|
type NTLM_Negotiate(offset: uint16) = record {
|
||||||
|
flags : NTLM_Negotiate_Flags;
|
||||||
|
domain_name_fields : NTLM_StringData;
|
||||||
|
workstation_fields : NTLM_StringData;
|
||||||
|
version_present : case flags.negotiate_version of {
|
||||||
|
true -> version : NTLM_Version;
|
||||||
|
false -> no_version : empty;
|
||||||
|
};
|
||||||
|
payload : bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||||
|
domain_name : NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_domain_supplied);
|
||||||
|
workstation : NTLM_String(workstation_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_oem_workstation_supplied);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Challenge(offset: uint16) = record {
|
||||||
|
target_name_fields : NTLM_StringData;
|
||||||
|
flags : NTLM_Negotiate_Flags;
|
||||||
|
challenge : uint64;
|
||||||
|
reserved : padding[8];
|
||||||
|
target_info_fields : NTLM_StringData;
|
||||||
|
version_present : case flags.negotiate_version of {
|
||||||
|
true -> version : NTLM_Version;
|
||||||
|
false -> no_version : empty;
|
||||||
|
};
|
||||||
|
payload : bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||||
|
target_name : NTLM_String(target_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.request_target);
|
||||||
|
target_info : NTLM_AV_Pair_Sequence(target_info_fields.offset - absolute_offset) withinput payload &if(flags.negotiate_target_info);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Authenticate(offset: uint16) = record {
|
||||||
|
lm_challenge_response_fields : NTLM_StringData;
|
||||||
|
nt_challenge_response_fields : NTLM_StringData;
|
||||||
|
domain_name_fields : NTLM_StringData;
|
||||||
|
user_name_fields : NTLM_StringData;
|
||||||
|
workstation_fields : NTLM_StringData;
|
||||||
|
encrypted_session_key_fields : NTLM_StringData;
|
||||||
|
flags : NTLM_Negotiate_Flags;
|
||||||
|
version_present : case flags.negotiate_version of {
|
||||||
|
true -> version : NTLM_Version;
|
||||||
|
false -> no_version : empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Windows NT, 2000, XP, and 2003 don't have the MIC field
|
||||||
|
# TODO - figure out how to parse this for those that do have it
|
||||||
|
# mic : bytestring &length=16;
|
||||||
|
|
||||||
|
payload : bytestring &restofdata;
|
||||||
|
} &let {
|
||||||
|
absolute_offset : uint16 = offsetof(payload) + offset;
|
||||||
|
domain_name : NTLM_String(domain_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(domain_name_fields.length > 0);
|
||||||
|
user_name : NTLM_String(user_name_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(user_name_fields.length > 0);
|
||||||
|
workstation : NTLM_String(workstation_fields, absolute_offset , flags.negotiate_unicode) withinput payload &if(workstation_fields.length > 0);
|
||||||
|
encrypted_session_key : NTLM_String(encrypted_session_key_fields, absolute_offset, flags.negotiate_unicode) withinput payload &if(flags.negotiate_key_exch);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Version = record {
|
||||||
|
major_version : uint8;
|
||||||
|
minor_version : uint8;
|
||||||
|
build_number : uint16;
|
||||||
|
reserved : padding[3];
|
||||||
|
ntlm_revision : uint8;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_StringData = record {
|
||||||
|
length : uint16;
|
||||||
|
max_length : uint16;
|
||||||
|
offset : uint32;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Fixed_Length_String(unicode: bool) = record {
|
||||||
|
data: bytestring &restofdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_String(fields: NTLM_StringData, offset: uint16, unicode: bool) = record {
|
||||||
|
pad1 : padding to fields.offset - offset;
|
||||||
|
string : Fixed_Length_String(unicode) &length=fields.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_AV_Pair_Sequence(offset: uint16) = record {
|
||||||
|
pad1 : padding to offset;
|
||||||
|
pairs : NTLM_AV_Pair[] &until($element.last);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_AV_Pair = record {
|
||||||
|
id : uint16;
|
||||||
|
length : uint16;
|
||||||
|
value_case : case id of {
|
||||||
|
0x0000 -> av_eol : empty;
|
||||||
|
0x0001 -> nb_computer_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0002 -> nb_domain_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0003 -> dns_computer_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0004 -> dns_domain_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0005 -> dns_tree_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x0006 -> av_flags : uint32;
|
||||||
|
0x0007 -> timestamp : uint64;
|
||||||
|
0x0008 -> single_host : NTLM_Single_Host;
|
||||||
|
0x0009 -> target_name : Fixed_Length_String(true) &length=length;
|
||||||
|
0x000a -> channel_bindings : uint16;
|
||||||
|
};
|
||||||
|
} &let {
|
||||||
|
last : bool = (id == 0x0000);
|
||||||
|
# av_flags refinement
|
||||||
|
constrained_auth : bool = (av_flags & 0x00000001) > 0 &if(id == 0x0006);
|
||||||
|
mic_present : bool = (av_flags & 0x00000002) > 0 &if(id == 0x0006);
|
||||||
|
untrusted_source : bool = (av_flags & 0x00000004) > 0 &if(id == 0x0006);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Single_Host = record {
|
||||||
|
size : uint32;
|
||||||
|
padpad : padding[4];
|
||||||
|
data_present : uint32;
|
||||||
|
optional : case custom_data_present of {
|
||||||
|
true -> custom_data : bytestring &length=4;
|
||||||
|
false -> nothing : empty;
|
||||||
|
};
|
||||||
|
machine_id : uint32;
|
||||||
|
} &let {
|
||||||
|
custom_data_present: bool = (data_present & 0x00000001) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LM_Response(offset: uint16) = record {
|
||||||
|
# This can be either LM (24 byte response) or
|
||||||
|
# LMv2 (16 byte response + 8 byte client challenge. No way to
|
||||||
|
# know for sure.
|
||||||
|
padpad : padding to offset;
|
||||||
|
response : bytestring &length=24;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Response(offset: uint16) = record {
|
||||||
|
padpad : padding to offset;
|
||||||
|
response : bytestring &length=24;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLMv2_Response(flags: NTLM_Negotiate_Flags, offset: uint16) = record {
|
||||||
|
padpad : padding to offset;
|
||||||
|
response : bytestring &length=16;
|
||||||
|
client_challenge : NTLMv2_Client_Challenge(flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLMv2_Client_Challenge(flags: NTLM_Negotiate_Flags) = record {
|
||||||
|
resp_type : uint8;
|
||||||
|
max_resp_type : uint8;
|
||||||
|
reserved : padding[6];
|
||||||
|
timestamp : uint64;
|
||||||
|
client_challenge : bytestring &length=8;
|
||||||
|
reserved2 : padding[4];
|
||||||
|
av_pairs : NTLM_AV_Pair_Sequence(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NTLM_Negotiate_Flags = record {
|
||||||
|
flags: uint32;
|
||||||
|
} &let {
|
||||||
|
negotiate_56 : bool = (flags & 0x80000000) > 0;
|
||||||
|
negotiate_key_exch : bool = (flags & 0x40000000) > 0;
|
||||||
|
negotiate_128 : bool = (flags & 0x20000000) > 0;
|
||||||
|
|
||||||
|
negotiate_version : bool = (flags & 0x02000000) > 0;
|
||||||
|
|
||||||
|
negotiate_target_info : bool = (flags & 0x00800000) > 0;
|
||||||
|
request_non_nt_session_key : bool = (flags & 0x00400000) > 0;
|
||||||
|
negotiate_identify : bool = (flags & 0x00100000) > 0;
|
||||||
|
|
||||||
|
negotiate_extended_sessionsecurity : bool = (flags & 0x00040000) > 0;
|
||||||
|
target_type_server : bool = (flags & 0x00020000) > 0;
|
||||||
|
target_type_domain : bool = (flags & 0x00010000) > 0;
|
||||||
|
|
||||||
|
negotiate_always_sign : bool = (flags & 0x00008000) > 0;
|
||||||
|
negotiate_oem_workstation_supplied : bool = (flags & 0x00002000) > 0;
|
||||||
|
negotiate_oem_domain_supplied : bool = (flags & 0x00001000) > 0;
|
||||||
|
|
||||||
|
negotiate_anonymous_connection : bool = (flags & 0x00000400) > 0;
|
||||||
|
negotiate_ntlm : bool = (flags & 0x00000100) > 0;
|
||||||
|
|
||||||
|
negotiate_lm_key : bool = (flags & 0x00000080) > 0;
|
||||||
|
negotiate_datagram : bool = (flags & 0x00000040) > 0;
|
||||||
|
negotiate_seal : bool = (flags & 0x00000020) > 0;
|
||||||
|
|
||||||
|
negotiate_sign : bool = (flags & 0x00000008) > 0;
|
||||||
|
request_target : bool = (flags & 0x00000004) > 0;
|
||||||
|
negotiate_oem : bool = (flags & 0x00000002) > 0;
|
||||||
|
negotiate_unicode : bool = (flags & 0x00000001) > 0;
|
||||||
|
|
||||||
|
is_oem : bool = !negotiate_unicode && negotiate_oem;
|
||||||
|
is_invalid : bool = !negotiate_unicode && !negotiate_oem;
|
||||||
|
};
|
30
src/analyzer/protocol/ntlm/ntlm.pac
Normal file
30
src/analyzer/protocol/ntlm/ntlm.pac
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
%include binpac.pac
|
||||||
|
%include bro.pac
|
||||||
|
|
||||||
|
%extern{
|
||||||
|
#include "analyzer/Manager.h"
|
||||||
|
#include "analyzer/Analyzer.h"
|
||||||
|
|
||||||
|
#include "types.bif.h"
|
||||||
|
#include "events.bif.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
analyzer NTLM withcontext {
|
||||||
|
connection : NTLM_Conn;
|
||||||
|
flow : NTLM_Flow;
|
||||||
|
};
|
||||||
|
|
||||||
|
connection NTLM_Conn(bro_analyzer: BroAnalyzer) {
|
||||||
|
upflow = NTLM_Flow(true);
|
||||||
|
downflow = NTLM_Flow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include ntlm-protocol.pac
|
||||||
|
%include ../asn1/asn1.pac
|
||||||
|
|
||||||
|
# Now we define the flow:
|
||||||
|
flow NTLM_Flow(is_orig: bool) {
|
||||||
|
datagram = NTLM_SSP_Token(is_orig) withcontext(connection, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
%include ntlm-analyzer.pac
|
9
src/analyzer/protocol/ntlm/types.bif
Normal file
9
src/analyzer/protocol/ntlm/types.bif
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
module NTLM;
|
||||||
|
|
||||||
|
type NTLM::Negotiate: record;
|
||||||
|
type NTLM::Challenge: record;
|
||||||
|
type NTLM::Authenticate: record;
|
||||||
|
type NTLM::NegotiateFlags: record;
|
||||||
|
type NTLM::Version: record;
|
||||||
|
type NTLM::AVs: record;
|
Loading…
Add table
Add a link
Reference in a new issue