218 lines
8.6 KiB
Plaintext
218 lines
8.6 KiB
Plaintext
##! Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
##! SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
##! Implements base functionality for TDS analysis.
|
|
##! Generates the tds.log file, containing some information about the TDS headers.
|
|
##! Generates the tds_rpc.log file, containing some information about rpc data.
|
|
##! Generates the tds_sql_batch.log file, containing some information about sql batch data.
|
|
|
|
module TDS;
|
|
|
|
export {
|
|
redef enum Log::ID += {
|
|
Log_TDS,
|
|
Log_TDS_RPC,
|
|
Log_TDS_SQL_Batch
|
|
};
|
|
|
|
## header info
|
|
type TDS: record {
|
|
ts : time &log; ## Timestamp for when the event happened.
|
|
uid : string &log; ## Unique ID for the connection.
|
|
id : conn_id &log; ## The connection's 4-tuple of endpoint addresses/ports.
|
|
|
|
command : string &optional &log; ## Name of the sent TDS command.
|
|
};
|
|
## Event that can be handled to access the tds record as it is sent to the loggin framework.
|
|
global log_tds: event(rec: TDS);
|
|
|
|
## Remote Procedure Call
|
|
type TDS_RPC: record {
|
|
ts : time &log; ## Timestamp for when the event happened.
|
|
uid : string &log; ## Unique ID for the connection.
|
|
id : conn_id &log; ## The connection's 4-tuple of endpoint addresses/ports.
|
|
|
|
procedure_name : string &optional &log;
|
|
parameters : string_vec &optional &log;
|
|
};
|
|
## Event that can be handled to access the tds record as it is sent to the loggin framework.
|
|
global log_tds_rpc: event(rec: TDS_RPC);
|
|
|
|
## SQL Batch
|
|
type TDS_SQL_Batch: record {
|
|
ts : time &log; ## Timestamp for when the event happened.
|
|
uid : string &log; ## Unique ID for the connection.
|
|
id : conn_id &log; ## The connection's 4-tuple of endpoint addresses/ports.
|
|
|
|
header_type : string &optional &log;
|
|
query : string &optional &log;
|
|
};
|
|
## Event that can be handled to access the tds record as it is sent to the loggin framework.
|
|
global log_tds_sql_batch: event(rec: TDS_SQL_Batch);
|
|
}
|
|
|
|
redef record connection += {
|
|
tds : TDS &optional;
|
|
tds_rpc : TDS_RPC &optional;
|
|
tds_sql_batch : TDS_SQL_Batch &optional;
|
|
};
|
|
|
|
## define listening ports
|
|
const ports = {
|
|
1433/tcp
|
|
};
|
|
redef likely_server_ports += {
|
|
ports
|
|
};
|
|
|
|
event zeek_init() &priority=5 {
|
|
Log::create_stream(TDS::Log_TDS,
|
|
[$columns=TDS,
|
|
$ev=log_tds,
|
|
$path="tds"]);
|
|
Log::create_stream(TDS::Log_TDS_RPC,
|
|
[$columns=TDS_RPC,
|
|
$ev=log_tds_rpc,
|
|
$path="tds_rpc"]);
|
|
Log::create_stream(TDS::Log_TDS_SQL_Batch,
|
|
[$columns=TDS_SQL_Batch,
|
|
$ev=log_tds_sql_batch,
|
|
$path="tds_sql_batch"]);
|
|
Analyzer::register_for_ports(Analyzer::ANALYZER_TDS, ports);
|
|
}
|
|
|
|
##! general tds header
|
|
event tds(c: connection, is_orig: bool, command: count) {
|
|
if(!c?$tds) {
|
|
c$tds = [$ts=network_time(), $uid=c$uid, $id=c$id];
|
|
}
|
|
|
|
c$tds$ts = network_time();
|
|
c$tds$command = commands[command];
|
|
|
|
Log::write(Log_TDS, c$tds);
|
|
delete c$tds;
|
|
}
|
|
|
|
##! general tds rpc
|
|
event tds_rpc(c: connection, is_orig: bool,
|
|
procedure_name: string,
|
|
parameters: string) {
|
|
if(!c?$tds_rpc) {
|
|
c$tds_rpc = [$ts=network_time(), $uid=c$uid, $id=c$id];
|
|
}
|
|
|
|
c$tds_rpc$ts = network_time();
|
|
c$tds_rpc$procedure_name = subst_string(procedure_name, "\x00", "");
|
|
local params_size: count = |parameters|;
|
|
if (params_size > 0) {
|
|
local params: string_vec;
|
|
local params_index: count=0;
|
|
local param_index: count=0;
|
|
local param_name: string="";
|
|
local param_type: count=0;
|
|
local param_data: string;
|
|
local param_len: count=0;
|
|
while (param_index < params_size) {
|
|
param_len = bytestring_to_count(parameters[param_index])*2;
|
|
param_index += 1;
|
|
param_name = subst_string(parameters[param_index: param_index+param_len], "\x00", "");
|
|
param_index += param_len;
|
|
param_index += 1; ##! status
|
|
param_type = bytestring_to_count(parameters[param_index]);
|
|
param_index += 1;
|
|
param_data = "";
|
|
switch (param_type) {
|
|
case 0x24, ##! GUID
|
|
0x26, ##! int
|
|
0x68, ##! bit
|
|
0x6d, ##! float
|
|
0x6f: ##! DateTime
|
|
param_index += 1; ##! max length
|
|
param_len = bytestring_to_count(parameters[param_index]);
|
|
param_index += 1;
|
|
switch (param_type) {
|
|
case 0x24: ##! GUID
|
|
param_data = bytestring_to_hexstr(parameters[param_index+3]);
|
|
param_data += bytestring_to_hexstr(parameters[param_index+2]);
|
|
param_data += bytestring_to_hexstr(parameters[param_index+1]);
|
|
param_data += bytestring_to_hexstr(parameters[param_index]);
|
|
param_data += "-";
|
|
param_data += bytestring_to_hexstr(parameters[param_index+5]);
|
|
param_data += bytestring_to_hexstr(parameters[param_index+4]);
|
|
param_data += "-";
|
|
param_data += bytestring_to_hexstr(parameters[param_index+7]);
|
|
param_data += bytestring_to_hexstr(parameters[param_index+6]);
|
|
param_data += "-";
|
|
param_data += bytestring_to_hexstr(parameters[param_index+8:param_index+10]);
|
|
param_data += "-";
|
|
param_data += bytestring_to_hexstr(parameters[param_index+10:param_index+param_len]);
|
|
break;
|
|
case 0x68: ##! bit
|
|
if (bytestring_to_count(parameters[param_index]) == 1) {
|
|
param_data = "True";
|
|
}
|
|
else {
|
|
param_data = "False";
|
|
}
|
|
break;
|
|
case 0x6d: ##! float
|
|
param_data = fmt("%f", bytestring_to_double(parameters[param_index:param_index+param_len]));
|
|
break;
|
|
default:
|
|
if (param_index >= params_size) {
|
|
break;
|
|
}
|
|
param_data = fmt("%d", bytestring_to_count(parameters[param_index:param_index+param_len], T));
|
|
break;
|
|
}
|
|
param_index += param_len;
|
|
params[params_index] = fmt("%s=%s", param_name, param_data);
|
|
params_index += 1;
|
|
break;
|
|
case 0xa7, ##! VarChar
|
|
0xe7: ##! NVarChar
|
|
param_index += 2; ##! max length
|
|
param_index += 5; ##! collation
|
|
param_len = bytestring_to_count(parameters[param_index:param_index+2], T);
|
|
param_index += 2;
|
|
##! NULL is 65535
|
|
if (param_len > 0 && param_len < 65535) {
|
|
param_data = subst_string(parameters[param_index:param_index+param_len], "\x00", "");
|
|
param_index += param_len;
|
|
}
|
|
params[params_index] = fmt("%s=%s", param_name, param_data);
|
|
params_index += 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
c$tds_rpc$parameters = params;
|
|
}
|
|
|
|
Log::write(Log_TDS_RPC, c$tds_rpc);
|
|
delete c$tds_rpc;
|
|
}
|
|
|
|
event tds_sql_batch(c: connection, is_orig: bool,
|
|
header_type: count,
|
|
query: string) {
|
|
if(!c?$tds_sql_batch) {
|
|
c$tds_sql_batch = [$ts=network_time(), $uid=c$uid, $id=c$id];
|
|
}
|
|
|
|
c$tds_sql_batch$ts = network_time();
|
|
c$tds_sql_batch$header_type = header_types[header_type];
|
|
query = subst_string(query, "\x00", "");
|
|
c$tds_sql_batch$query = query;
|
|
|
|
Log::write(Log_TDS_SQL_Batch, c$tds_sql_batch);
|
|
delete c$tds_sql_batch;
|
|
}
|
|
|
|
event connection_state_remove(c: connection) &priority=-5 {
|
|
if(c?$tds) {
|
|
delete c$tds;
|
|
}
|
|
}
|