Merge branch 'topic/awelzel/mysql-start-tls'

* topic/awelzel/mysql-start-tls:
  mysql: Recognize when client/server negotiate SSL
This commit is contained in:
Arne Welzel 2023-01-31 14:49:29 +01:00
commit 87d6efafb0
18 changed files with 167 additions and 14 deletions

View file

@ -3,6 +3,7 @@
#include "zeek/analyzer/protocol/mysql/MySQL.h"
#include "zeek/Reporter.h"
#include "zeek/analyzer/Manager.h"
#include "zeek/analyzer/protocol/mysql/events.bif.h"
#include "zeek/analyzer/protocol/tcp/TCP_Reassembler.h"
@ -13,6 +14,7 @@ MySQL_Analyzer::MySQL_Analyzer(Connection* c) : analyzer::tcp::TCP_ApplicationAn
{
interp = new binpac::MySQL::MySQL_Conn(this);
had_gap = false;
tls_active = false;
}
MySQL_Analyzer::~MySQL_Analyzer()
@ -31,13 +33,34 @@ void MySQL_Analyzer::Done()
void MySQL_Analyzer::EndpointEOF(bool is_orig)
{
analyzer::tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
if ( tls_active )
ForwardEndOfData(is_orig);
interp->FlowEOF(is_orig);
}
void MySQL_Analyzer::StartTLS()
{
tls_active = true;
Analyzer* ssl = analyzer_mgr->InstantiateAnalyzer("SSL", Conn());
if ( ssl )
AddChildAnalyzer(ssl);
}
void MySQL_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
analyzer::tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
if ( tls_active )
{
// If TLS has been initiated, forward to child and
// short-circuit further processing
ForwardStream(len, data, orig);
return;
}
if ( TCP() && TCP()->IsPartial() )
return;
@ -60,6 +83,10 @@ void MySQL_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
void MySQL_Analyzer::Undelivered(uint64_t seq, int len, bool orig)
{
analyzer::tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
if ( tls_active )
ForwardUndelivered(seq, len, orig);
had_gap = true;
interp->NewGap(orig, len);
}

View file

@ -25,11 +25,14 @@ public:
// Overridden from analyzer::tcp::TCP_ApplicationAnalyzer.
void EndpointEOF(bool is_orig) override;
void StartTLS();
static analyzer::Analyzer* Instantiate(Connection* conn) { return new MySQL_Analyzer(conn); }
protected:
binpac::MySQL::MySQL_Conn* interp;
bool had_gap;
bool tls_active;
};
} // namespace zeek::analyzer::mysql

View file

@ -22,12 +22,19 @@ refine flow MySQL_Flow += {
if ( ${msg.version} == 9 || ${msg.version == 10} )
connection()->zeek_analyzer()->AnalyzerConfirmation();
// If the client requested SSL and didn't provide credentials, switch to SSL
if ( ${msg.version} == 10 && ( ${msg.v10_response.cap_flags} & CLIENT_SSL ) && ${msg.v10_response.credentials}->empty() )
{
connection()->zeek_analyzer()->StartTLS();
return true;
}
if ( mysql_handshake )
{
if ( ${msg.version} == 10 )
if ( ${msg.version} == 10 && ${msg.v10_response.credentials}->size() > 0 )
zeek::BifEvent::enqueue_mysql_handshake(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),
zeek::make_intrusive<zeek::StringVal>(c_str(${msg.v10_response.username})));
zeek::make_intrusive<zeek::StringVal>(c_str(${msg.v10_response.credentials[0].username})));
if ( ${msg.version} == 9 )
zeek::BifEvent::enqueue_mysql_handshake(connection()->zeek_analyzer(),
connection()->zeek_analyzer()->Conn(),

View file

@ -158,7 +158,8 @@ enum EOFType {
};
enum Client_Capabilities {
# Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
CLIENT_SSL = 0x00000800,
# Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
CLIENT_DEPRECATE_EOF = 0x01000000,
};
@ -237,13 +238,17 @@ type Handshake_Response_Packet = case $context.connection.get_version() of {
version: uint8 = $context.connection.get_version();
};
type Handshake_Credentials_v10 = record {
username : NUL_String;
password : bytestring &restofdata;
};
type Handshake_Response_Packet_v10 = record {
cap_flags : uint32;
max_pkt_size: uint32;
char_set : uint8;
pad : padding[23];
username : NUL_String;
password : bytestring &restofdata;
credentials : Handshake_Credentials_v10[] &until($input.length() == 0);
} &let {
deprecate_eof: bool = $context.connection.set_deprecate_eof(cap_flags & CLIENT_DEPRECATE_EOF);
};

View file

@ -8,16 +8,26 @@
%include zeek.pac
%extern{
#include "zeek/analyzer/protocol/mysql/events.bif.h"
namespace zeek::analyzer::mysql { class MySQL_Analyzer; }
namespace binpac { namespace MySQL { class MySQL_Conn; } }
using MySQLAnalyzer = zeek::analyzer::mysql::MySQL_Analyzer*;
#include "zeek/analyzer/protocol/mysql/MySQL.h"
#include "zeek/analyzer/protocol/mysql/events.bif.h"
%}
extern type MySQLAnalyzer;
analyzer MySQL withcontext {
connection: MySQL_Conn;
flow: MySQL_Flow;
};
# Our connection consists of two flows, one in each direction.
connection MySQL_Conn(zeek_analyzer: ZeekAnalyzer) {
connection MySQL_Conn(zeek_analyzer: MySQLAnalyzer) {
upflow = MySQL_Flow(true);
downflow = MySQL_Flow(false);
};