ssl: rudimentary decryption for TLS 1.2

Several limitations still apply:
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 is the only supported cipher suite
- Some tests are broken due to a failing assertion regarding bytestring
- No newly written tests for decryption (the patch was tested extensively for our paper)
- Several small open technical questions marked with FIXME
- Architecture in the ssl module might not be optimal
This commit is contained in:
Florian Wilkens 2021-04-19 11:18:59 +02:00
parent db534b79fb
commit 2d950ffde9
21 changed files with 541 additions and 13 deletions

View file

@ -0,0 +1,106 @@
#! Decrypt SSL/TLS payloads
@load base/frameworks/input
@load base/frameworks/notice
@load base/protocols/conn
@load base/protocols/ssl
module SSL;
# Local
const input_stream_name = "input-tls-keylog-file";
type Idx: record {
client_random: string;
};
type Val: record {
secret: string;
};
global randoms: table[string] of string = {};
export {
redef record Info += {
# decryption uses client_random as identifier
client_random: string &log &optional;
};
const keylog_file = getenv("ZEEK_TLS_KEYLOG_FILE") &redef;
global secrets: table[string] of string = {} &redef;
global keys: table[string] of string = {} &redef;
event SSL::add_keys(client_random: string, val: string)
{
SSL::keys[client_random] = val;
}
event SSL::add_secret(client_random: string, val: string)
{
SSL::secrets[client_random] = val;
}
}
event ssl_client_hello(c: connection, version: count, record_version: count, possible_ts: time, client_random: string, session_id: string, ciphers: index_vec, comp_methods: index_vec)
{
c$ssl$client_random = client_random;
if ( client_random in keys )
{
set_keys(c, keys[client_random]);
}
else if ( client_random in secrets )
{
set_secret(c, secrets[client_random]);
}
}
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count, payload: string)
{
if ( c$ssl?$client_random )
{
if ( c$ssl$client_random in keys )
{
set_keys(c, keys[c$ssl$client_random]);
}
else if ( c$ssl$client_random in secrets )
{
set_secret(c, secrets[c$ssl$client_random]);
}
else
{
# FIXME: should this be moved to reporter.log or removed completely?
#print "No suitable key or secret found for random:", randoms[c$uid];
}
}
}
event SSL::tls_input_done()
{
continue_processing();
}
event Input::end_of_data(name: string, source: string)
{
if ( name == input_stream_name )
{
event SSL::tls_input_done();
}
}
event zeek_init()
{
# listen for secrets
Broker::subscribe("/zeek/tls/decryption");
# FIXME: is such a functionality helpful?
# ingest keylog file if the environment is set
if ( keylog_file != "" )
{
suspend_processing();
Input::add_table([$name=input_stream_name, $source=keylog_file, $destination=secrets, $idx=Idx, $val=Val, $want_record=F]);
Input::remove(input_stream_name);
}
}

View file

@ -223,7 +223,7 @@ event ssl_encrypted_heartbeat(c: connection, is_orig: bool, length: count)
} }
} }
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count) event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count, payload: string)
{ {
if ( !c?$ssl ) if ( !c?$ssl )
return; return;

View file

@ -101,6 +101,7 @@
@load protocols/ssh/geo-data.zeek @load protocols/ssh/geo-data.zeek
@load protocols/ssh/interesting-hostnames.zeek @load protocols/ssh/interesting-hostnames.zeek
@load protocols/ssh/software.zeek @load protocols/ssh/software.zeek
#@load protocols/ssl/decryption.zeek
@load protocols/ssl/expiring-certs.zeek @load protocols/ssl/expiring-certs.zeek
@load protocols/ssl/extract-certs-pem.zeek @load protocols/ssl/extract-certs-pem.zeek
@load protocols/ssl/heartbleed.zeek @load protocols/ssl/heartbleed.zeek

View file

@ -1,6 +1,7 @@
@load test-all-policy.zeek @load test-all-policy.zeek
# Scripts which are commented out in test-all-policy.zeek. # Scripts which are commented out in test-all-policy.zeek.
@load protocols/ssl/decryption.zeek
@load protocols/ssl/notary.zeek @load protocols/ssl/notary.zeek
@load frameworks/control/controllee.zeek @load frameworks/control/controllee.zeek
@load frameworks/control/controller.zeek @load frameworks/control/controller.zeek

View file

@ -10,8 +10,8 @@ zeek_plugin_bif(events.bif)
zeek_plugin_bif(functions.bif) zeek_plugin_bif(functions.bif)
zeek_plugin_bif(consts.bif) zeek_plugin_bif(consts.bif)
zeek_plugin_pac(tls-handshake.pac tls-handshake-protocol.pac tls-handshake-analyzer.pac ssl-defs.pac zeek_plugin_pac(tls-handshake.pac tls-handshake-protocol.pac tls-handshake-analyzer.pac ssl-defs.pac
proc-client-hello.pac proc-client-hello-tls.pac
proc-server-hello.pac proc-server-hello-tls.pac
proc-certificate.pac proc-certificate.pac
tls-handshake-signed_certificate_timestamp.pac tls-handshake-signed_certificate_timestamp.pac
) )

View file

@ -72,4 +72,9 @@ void DTLS_Analyzer::SendHandshake(uint16_t raw_tls_version, uint8_t msg_type, ui
} }
} }
bool DTLS_Analyzer::TryDecryptApplicationData(int len, const u_char* data, bool is_orig, uint8_t content_type, uint16_t raw_tls_version)
{
// noop for now as DTLS decryption is currently not supported
}
} // namespace zeek::analyzer::dtls } // namespace zeek::analyzer::dtls

View file

@ -27,6 +27,8 @@ public:
static analyzer::Analyzer* Instantiate(Connection* conn) static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new DTLS_Analyzer(conn); } { return new DTLS_Analyzer(conn); }
bool TryDecryptApplicationData(int len, const u_char* data, bool is_orig, uint8_t content_type, uint16_t raw_tls_version);
protected: protected:
binpac::DTLS::SSL_Conn* interp; binpac::DTLS::SSL_Conn* interp;
binpac::TLSHandshake::Handshake_Conn* handshake_interp; binpac::TLSHandshake::Handshake_Conn* handshake_interp;

View file

@ -1,5 +1,6 @@
#include "zeek/analyzer/protocol/ssl/SSL.h" #include "zeek/analyzer/protocol/ssl/SSL.h"
#include "zeek/analyzer/Manager.h"
#include "zeek/analyzer/protocol/tcp/TCP_Reassembler.h" #include "zeek/analyzer/protocol/tcp/TCP_Reassembler.h"
#include "zeek/Reporter.h" #include "zeek/Reporter.h"
#include "zeek/util.h" #include "zeek/util.h"
@ -8,6 +9,73 @@
#include "zeek/analyzer/protocol/ssl/ssl_pac.h" #include "zeek/analyzer/protocol/ssl/ssl_pac.h"
#include "zeek/analyzer/protocol/ssl/tls-handshake_pac.h" #include "zeek/analyzer/protocol/ssl/tls-handshake_pac.h"
#include <arpa/inet.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#define MSB(a) ((a>>8)&0xff)
#define LSB(a) (a&0xff)
static void fmt_seq(uint32_t num, u_char* buf)
{
memset(buf, 0, 8);
uint32_t netnum = htonl(num);
memcpy(buf+4, &netnum, 4);
}
static void print_hex(std::string name, u_char* data, int len)
{
int i = 0;
printf("%s (%d): ", name.c_str(), len);
if (len > 0)
printf("0x%02x", data[0]);
for (i = 1; i < len; i++)
{
printf(" 0x%02x", data[i]);
}
printf("\n");
}
static bool tls1_prf(const u_char *secret, int secret_len, const char* label,
const u_char* rnd1, int rnd1_len, const u_char* rnd2, int rnd2_len, u_char* out, size_t out_len)
{
// alloc buffers
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
size_t seed_len = strlen(label) + rnd1_len + rnd2_len;
u_char *seed = (u_char*) malloc(seed_len);
u_char *ptr = seed;
// seed = label + rnd1 + rnd2
memcpy(ptr, label, strlen(label));
ptr += strlen(label);
memcpy(ptr, rnd1, rnd1_len);
ptr += rnd1_len;
memcpy(ptr, rnd2, rnd2_len);
ptr += rnd2_len;
if (EVP_PKEY_derive_init(pctx) <= 0)
goto abort; /* Error */
// FIXME: sha384 should not be hardcoded
if (EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_sha384()) <= 0)
goto abort; /* Error */
if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, secret, secret_len) <= 0)
goto abort; /* Error */
if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed, seed_len) <= 0)
goto abort; /* Error */
if (EVP_PKEY_derive(pctx, out, &out_len) <= 0)
goto abort; /* Error */
EVP_PKEY_CTX_free(pctx);
free(seed);
return true;
abort:
EVP_PKEY_CTX_free(pctx);
free(seed);
return false;
}
namespace zeek::analyzer::ssl { namespace zeek::analyzer::ssl {
SSL_Analyzer::SSL_Analyzer(Connection* c) SSL_Analyzer::SSL_Analyzer(Connection* c)
@ -16,12 +84,20 @@ SSL_Analyzer::SSL_Analyzer(Connection* c)
interp = new binpac::SSL::SSL_Conn(this); interp = new binpac::SSL::SSL_Conn(this);
handshake_interp = new binpac::TLSHandshake::Handshake_Conn(this); handshake_interp = new binpac::TLSHandshake::Handshake_Conn(this);
had_gap = false; had_gap = false;
c_seq = 0;
s_seq = 0;
// FIXME: should this be initialized to nullptr?
secret = new zeek::StringVal(0, "");
keys = new zeek::StringVal(0, "");
pia = nullptr;
} }
SSL_Analyzer::~SSL_Analyzer() SSL_Analyzer::~SSL_Analyzer()
{ {
delete interp; delete interp;
delete handshake_interp; delete handshake_interp;
delete secret;
delete keys;
} }
void SSL_Analyzer::Done() void SSL_Analyzer::Done()
@ -98,4 +174,166 @@ void SSL_Analyzer::Undelivered(uint64_t seq, int len, bool orig)
interp->NewGap(orig, len); interp->NewGap(orig, len);
} }
void SSL_Analyzer::SetSecret(const u_char* data, int len)
{
// FIXME: Is this the proper way to initialize a zeek::StringVal?
// the alternative requires a cast: new zeek::StringVal(len, data)
secret = new zeek::StringVal(new zeek::String(data, len, true));
}
void SSL_Analyzer::SetKeys(const u_char* data, int len)
{
keys = new zeek::StringVal(new zeek::String(data, len, true));
}
bool SSL_Analyzer::TryDecryptApplicationData(int len, const u_char* data, bool is_orig, uint8_t content_type, uint16_t raw_tls_version)
{
// Unsupported cipher suite. Currently supported:
// - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 == 0xC030
auto cipher = handshake_interp->chosen_cipher();
if ( cipher != 0xC030 )
{
//printf("Unsupported cipher suite: %d\n", cipher);
return false;
}
// Neither secret or key present: abort
if ( secret->Len() == 0 && keys->Len() == 0 )
{
// FIXME: this is just for debugging
printf("Could not decrypt packet (missing key):\n");
print_hex("->client_random:", handshake_interp->client_random().data(), handshake_interp->client_random().length());
return false;
}
// Secret present, but no keys derived yet: derive keys
if ( secret->Len() != 0 && keys->Len() == 0 )
{
uint32_t ts = htonl((uint32_t) handshake_interp->gmt_unix_time());
u_char crand[32] = {0x00};
u_char keybuf[72];
auto c_rnd = handshake_interp->client_random();
auto s_rnd = handshake_interp->server_random();
memcpy(crand, &(ts), 4);
memcpy(crand + 4, c_rnd.data(), c_rnd.length());
tls1_prf(secret->Bytes(), secret->Len(), "key expansion", s_rnd.data(), s_rnd.length(),
crand, sizeof(crand), keybuf, sizeof(keybuf));
// save derived keys
SetKeys(keybuf, sizeof(keybuf));
}
// Keys present: decrypt TLS application data
if ( keys->Len() != 0 )
{
// session keys & AEAD data
u_char c_wk[32];
u_char s_wk[32];
u_char c_iv[4];
u_char s_iv[4];
u_char s_aead_nonce[12];
u_char s_aead_tag[13];
memcpy(c_wk, keys->Bytes(), 32);
memcpy(s_wk, &(keys->Bytes()[32]), 32);
memcpy(c_iv, &(keys->Bytes()[64]), 4);
memcpy(s_iv, &(keys->Bytes()[68]), 4);
// FIXME: should we change types here?
u_char* encrypted = (u_char*)data;
size_t encrypted_len = len;
// FIXME: should this be moved to SSL_Conn?
if ( is_orig )
c_seq++;
else
s_seq++;
if ( is_orig )
memcpy(s_aead_nonce, c_iv, 4);
else
memcpy(s_aead_nonce, s_iv, 4);
memcpy(&(s_aead_nonce[4]), encrypted, 8);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
EVP_CipherInit(ctx, EVP_aes_256_gcm(), NULL, NULL, 0);
encrypted += 8;
// FIXME: is this because of nonce and aead tag?
encrypted_len -= 8;
encrypted_len -= 16;
if (is_orig)
EVP_DecryptInit(ctx, EVP_aes_256_gcm(), c_wk, s_aead_nonce);
else
EVP_DecryptInit(ctx, EVP_aes_256_gcm(), s_wk, s_aead_nonce);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, encrypted + encrypted_len);
if (is_orig)
fmt_seq(c_seq, s_aead_tag);
else
fmt_seq(s_seq, s_aead_tag);
s_aead_tag[8] = content_type;
s_aead_tag[9] = MSB(raw_tls_version);
s_aead_tag[10] = LSB(raw_tls_version);
s_aead_tag[11] = MSB(encrypted_len);
s_aead_tag[12] = LSB(encrypted_len);
u_char *decrypted = (u_char*)malloc(encrypted_len);
int decrypted_len = 0;
EVP_DecryptUpdate(ctx, NULL, &decrypted_len, s_aead_tag, 13);
EVP_DecryptUpdate(ctx, decrypted, &decrypted_len, (const u_char*) encrypted, encrypted_len);
int res = 0;
if ( ! (res = EVP_DecryptFinal(ctx, NULL, &res)) )
{
printf("Decryption failed with return code %d. Invalid key?\n", res);
EVP_CIPHER_CTX_free(ctx);
free(decrypted);
return false;
}
EVP_CIPHER_CTX_free(ctx);
ForwardDecryptedData(decrypted_len, reinterpret_cast<const u_char*>(decrypted), is_orig);
free(decrypted);
return true;
}
// This is only reached if key derivation somehow failed
return false;
}
void SSL_Analyzer::ForwardDecryptedData(int len, const u_char* data, bool is_orig)
{
if ( ! pia )
{
pia = new analyzer::pia::PIA_TCP(Conn());
if ( AddChildAnalyzer(pia) )
{
pia->FirstPacket(true, nullptr);
pia->FirstPacket(false, nullptr);
}
else
reporter->FatalError("Could not initialize PIA");
// FIXME: Also statically add HTTP/H2 at the moment.
// We should move this bit to scriptland
auto http = analyzer_mgr->InstantiateAnalyzer("HTTP", Conn());
if ( http )
AddChildAnalyzer(http);
auto http2 = analyzer_mgr->InstantiateAnalyzer("HTTP2", Conn());
if ( http2 )
AddChildAnalyzer(http2);
}
ForwardStream(len, data, is_orig);
}
} // namespace zeek::analyzer::ssl } // namespace zeek::analyzer::ssl

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "zeek/analyzer/protocol/pia/PIA.h"
#include "zeek/analyzer/protocol/tcp/TCP.h" #include "zeek/analyzer/protocol/tcp/TCP.h"
#include "zeek/analyzer/protocol/ssl/events.bif.h" #include "zeek/analyzer/protocol/ssl/events.bif.h"
@ -33,11 +34,24 @@ public:
static analyzer::Analyzer* Instantiate(Connection* conn) static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new SSL_Analyzer(conn); } { return new SSL_Analyzer(conn); }
// Key material for decryption
void SetSecret(const u_char* data, int len);
void SetKeys(const u_char* data, int len);
bool TryDecryptApplicationData(int len, const u_char* data, bool is_orig, uint8_t content_type, uint16_t raw_tls_version);
void ForwardDecryptedData(int len, const u_char* data, bool is_orig);
protected: protected:
binpac::SSL::SSL_Conn* interp; binpac::SSL::SSL_Conn* interp;
binpac::TLSHandshake::Handshake_Conn* handshake_interp; binpac::TLSHandshake::Handshake_Conn* handshake_interp;
bool had_gap; bool had_gap;
// FIXME: should this be moved into the connection?
int c_seq;
int s_seq;
zeek::StringVal *secret;
zeek::StringVal *keys;
zeek::analyzer::pia::PIA_TCP *pia;
}; };
} // namespace zeek::analyzer::ssl } // namespace zeek::analyzer::ssl

View file

@ -558,9 +558,11 @@ event ssl_plaintext_data%(c: connection, is_orig: bool, record_version: count, c
## ##
## length: length of the entire message. ## length: length of the entire message.
## ##
## payload: encrypted payload of the SSL/TLS message
##
## .. zeek:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello ## .. zeek:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello
## ssl_alert ssl_heartbeat ssl_probable_encrypted_handshake_message ## ssl_alert ssl_heartbeat ssl_probable_encrypted_handshake_message
event ssl_encrypted_data%(c: connection, is_orig: bool, record_version: count, content_type: count, length: count%); event ssl_encrypted_data%(c: connection, is_orig: bool, record_version: count, content_type: count, length: count, payload: string%);
## This event is generated for application data records of TLS 1.3 connections of which ## This event is generated for application data records of TLS 1.3 connections of which
## we suspect that they contain handshake messages. ## we suspect that they contain handshake messages.

View file

@ -16,3 +16,25 @@ function set_ssl_established%(c: connection%): any
static_cast<zeek::analyzer::ssl::SSL_Analyzer*>(sa)->StartEncryption(); static_cast<zeek::analyzer::ssl::SSL_Analyzer*>(sa)->StartEncryption();
return nullptr; return nullptr;
%} %}
function set_secret%(c: connection, secret: string%): bool
%{
analyzer::Analyzer* sa = c->FindAnalyzer("SSL");
if ( sa )
{
static_cast<zeek::analyzer::ssl::SSL_Analyzer*>(sa)->SetSecret(secret->Bytes(), secret->Len());
return zeek::val_mgr->True();
}
return zeek::val_mgr->False();
%}
function set_keys%(c: connection, keys: string%): bool
%{
analyzer::Analyzer* sa = c->FindAnalyzer("SSL");
if ( sa )
{
static_cast<zeek::analyzer::ssl::SSL_Analyzer*>(sa)->SetKeys(keys->Bytes(), keys->Len());
return zeek::val_mgr->True();
}
return zeek::val_mgr->False();
%}

View file

@ -0,0 +1,56 @@
function proc_client_hello(
version : uint16, ts : double,
client_random : bytestring,
session_id : uint8[],
cipher_suites16 : uint16[],
cipher_suites24 : uint24[],
compression_methods: uint8[]) : bool
%{
if ( ! version_ok(version) )
{
zeek_analyzer()->ProtocolViolation(zeek::util::fmt("unsupported client SSL version 0x%04x", version));
zeek_analyzer()->SetSkip(true);
}
else
zeek_analyzer()->ProtocolConfirmation();
if ( ssl_client_hello )
{
vector<int> cipher_suites;
if ( cipher_suites16 )
std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(cipher_suites));
else
std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(cipher_suites), to_int());
auto cipher_vec = zeek::make_intrusive<zeek::VectorVal>(zeek::id::index_vec);
for ( unsigned int i = 0; i < cipher_suites.size(); ++i )
{
auto ciph = zeek::val_mgr->Count(cipher_suites[i]);
cipher_vec->Assign(i, ciph);
}
auto comp_vec = zeek::make_intrusive<zeek::VectorVal>(zeek::id::index_vec);
if ( compression_methods )
{
for ( unsigned int i = 0; i < compression_methods->size(); ++i )
{
auto comp = zeek::val_mgr->Count((*compression_methods)[i]);
comp_vec->Assign(i, comp);
}
}
set_client_random(client_random);
set_gmt_unix_time(ts);
zeek::BifEvent::enqueue_ssl_client_hello(zeek_analyzer(), zeek_analyzer()->Conn(),
version, record_version(), ts,
zeek::make_intrusive<zeek::StringVal>(client_random.length(),
(const char*) client_random.data()),
{zeek::AdoptRef{}, to_string_val(session_id)},
std::move(cipher_vec), std::move(comp_vec));
}
return true;
%}

View file

@ -0,0 +1,41 @@
function proc_server_hello(
version : uint16, v2 : bool,
server_random : bytestring,
session_id : uint8[],
cipher_suites16 : uint16[],
cipher_suites24 : uint24[],
comp_method : uint8) : bool
%{
if ( ! version_ok(version) )
{
zeek_analyzer()->ProtocolViolation(zeek::util::fmt("unsupported server SSL version 0x%04x", version));
zeek_analyzer()->SetSkip(true);
}
if ( ssl_server_hello )
{
vector<int>* ciphers = new vector<int>();
if ( cipher_suites16 )
std::copy(cipher_suites16->begin(), cipher_suites16->end(), std::back_inserter(*ciphers));
else
std::transform(cipher_suites24->begin(), cipher_suites24->end(), std::back_inserter(*ciphers), to_int());
uint32 ts = 0;
if ( v2 == 0 && server_random.length() >= 4 )
ts = ntohl(*((uint32*)server_random.data()));
set_server_random(server_random);
zeek::BifEvent::enqueue_ssl_server_hello(zeek_analyzer(),
zeek_analyzer()->Conn(),
version, record_version(), ts,
zeek::make_intrusive<zeek::StringVal>(server_random.length(),
(const char*) server_random.data()),
{zeek::AdoptRef{}, to_string_val(session_id)},
ciphers->size()==0 ? 0 : ciphers->at(0), comp_method);
delete ciphers;
}
return true;
%}

View file

@ -43,7 +43,7 @@ refine connection SSL_Conn += {
return true; return true;
%} %}
function proc_ciphertext_record(rec : SSLRecord) : bool function proc_ciphertext_record(rec : SSLRecord, cont: bytestring) : bool
%{ %{
if ( established_ == false && determine_tls13() == 1 ) if ( established_ == false && determine_tls13() == 1 )
{ {
@ -62,8 +62,15 @@ refine connection SSL_Conn += {
} }
if ( ssl_encrypted_data ) if ( ssl_encrypted_data )
{
zeek::BifEvent::enqueue_ssl_encrypted_data(zeek_analyzer(), zeek::BifEvent::enqueue_ssl_encrypted_data(zeek_analyzer(),
zeek_analyzer()->Conn(), ${rec.is_orig}, ${rec.raw_tls_version}, ${rec.content_type}, ${rec.length}); zeek_analyzer()->Conn(), ${rec.is_orig}, ${rec.raw_tls_version}, ${rec.content_type}, ${rec.length},
zeek::make_intrusive<zeek::StringVal>(cont.length(), (const char*) cont.data()));
if (rec->content_type() == APPLICATION_DATA)
{
zeek_analyzer()->TryDecryptApplicationData(cont.length(), cont.data(), rec->is_orig(), rec->content_type(), rec->raw_tls_version());
}
}
return true; return true;
%} %}
@ -123,7 +130,7 @@ refine typeattr UnknownRecord += &let {
}; };
refine typeattr CiphertextRecord += &let { refine typeattr CiphertextRecord += &let {
proc : bool = $context.connection.proc_ciphertext_record(rec); proc : bool = $context.connection.proc_ciphertext_record(rec, cont);
} }
refine typeattr PlaintextRecord += &let { refine typeattr PlaintextRecord += &let {

View file

@ -96,7 +96,7 @@ type UnknownRecord(rec: SSLRecord) = record {
}; };
type CiphertextRecord(rec: SSLRecord) = record { type CiphertextRecord(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient; cont : bytestring &restofdata;
}; };
###################################################################### ######################################################################

View file

@ -25,8 +25,8 @@
refine connection Handshake_Conn += { refine connection Handshake_Conn += {
%include proc-client-hello.pac %include proc-client-hello-tls.pac
%include proc-server-hello.pac %include proc-server-hello-tls.pac
%include proc-certificate.pac %include proc-certificate.pac
function proc_session_ticket_handshake(rec: SessionTicketHandshake, is_orig: bool): bool function proc_session_ticket_handshake(rec: SessionTicketHandshake, is_orig: bool): bool

View file

@ -943,6 +943,9 @@ refine connection Handshake_Conn += {
uint32 chosen_cipher_; uint32 chosen_cipher_;
uint16 chosen_version_; uint16 chosen_version_;
uint16 record_version_; uint16 record_version_;
bytestring client_random_;
bytestring server_random_;
uint32 gmt_unix_time_;
%} %}
%init{ %init{
@ -950,6 +953,10 @@ refine connection Handshake_Conn += {
chosen_version_ = UNKNOWN_VERSION; chosen_version_ = UNKNOWN_VERSION;
record_version_ = 0; record_version_ = 0;
// FIXME: How should bytestrings be initialized?
// client_random_ = ??
// server_random_ = ??
gmt_unix_time_ = 0;
%} %}
function chosen_cipher() : int %{ return chosen_cipher_; %} function chosen_cipher() : int %{ return chosen_cipher_; %}
@ -983,5 +990,29 @@ refine connection Handshake_Conn += {
record_version_ = version; record_version_ = version;
return true; return true;
%} %}
function client_random() : bytestring %{ return client_random_; %}
function set_client_random(client_random: bytestring) : bool
%{
client_random_.init(client_random.data(), client_random.length());
return true;
%}
function server_random() : bytestring %{ return server_random_; %}
function set_server_random(server_random: bytestring) : bool
%{
server_random_.init(server_random.data(), server_random.length());
return true;
%}
function gmt_unix_time() : uint32 %{ return gmt_unix_time_; %}
function set_gmt_unix_time(ts: uint32) : bool
%{
gmt_unix_time_ = ts;
return true;
%}
}; };

View file

@ -9079,6 +9079,7 @@ XXXXXXXXXX.XXXXXX ssl_encrypted_data
[2] record_version: count = 771 [2] record_version: count = 771
[3] content_type: count = 22 [3] content_type: count = 22
[4] length: count = 32 [4] length: count = 32
[5] payload: string = \x1c\x1c\x84S/9\x14e\xb6'\xe5,\x03\x0fY\xdf\x1b\xcfu\xc84\xae\x1a"\xea]9j'\xbeZ\xa7
XXXXXXXXXX.XXXXXX raw_packet XXXXXXXXXX.XXXXXX raw_packet
[0] p: raw_pkt_hdr = [l2=[encap=LINK_ETHERNET, len=91, cap_len=91, src=58:b0:35:86:54:8d, dst=cc:b2:55:f4:62:92, vlan=<uninitialized>, inner_vlan=<uninitialized>, eth_type=2048, proto=L3_IPV4], ip=[hl=20, tos=0, len=77, id=51331, ttl=64, p=6, src=192.168.133.100, dst=17.167.150.73], ip6=<uninitialized>, tcp=[sport=49655/tcp, dport=443/tcp, seq=3289393854, ack=2319612745, hl=20, dl=37, reserved=0, flags=24, win=8192], udp=<uninitialized>, icmp=<uninitialized>] [0] p: raw_pkt_hdr = [l2=[encap=LINK_ETHERNET, len=91, cap_len=91, src=58:b0:35:86:54:8d, dst=cc:b2:55:f4:62:92, vlan=<uninitialized>, inner_vlan=<uninitialized>, eth_type=2048, proto=L3_IPV4], ip=[hl=20, tos=0, len=77, id=51331, ttl=64, p=6, src=192.168.133.100, dst=17.167.150.73], ip6=<uninitialized>, tcp=[sport=49655/tcp, dport=443/tcp, seq=3289393854, ack=2319612745, hl=20, dl=37, reserved=0, flags=24, win=8192], udp=<uninitialized>, icmp=<uninitialized>]
@ -9176,6 +9177,7 @@ XXXXXXXXXX.XXXXXX ssl_encrypted_data
[2] record_version: count = 771 [2] record_version: count = 771
[3] content_type: count = 22 [3] content_type: count = 22
[4] length: count = 32 [4] length: count = 32
[5] payload: string = Z\x99\x17~d\x06\xbd;\xb4\xdf\xe2\xb3~9,|\xac\xdb\xb4\xeb\xcc\x95.\x17\xd2Q\x8a\x96\xdb\x13\x09!
XXXXXXXXXX.XXXXXX raw_packet XXXXXXXXXX.XXXXXX raw_packet
[0] p: raw_pkt_hdr = [l2=[encap=LINK_ETHERNET, len=97, cap_len=97, src=cc:b2:55:f4:62:92, dst=58:b0:35:86:54:8d, vlan=<uninitialized>, inner_vlan=<uninitialized>, eth_type=2048, proto=L3_IPV4], ip=[hl=20, tos=0, len=83, id=50807, ttl=243, p=6, src=17.167.150.73, dst=192.168.133.100], ip6=<uninitialized>, tcp=[sport=443/tcp, dport=49655/tcp, seq=2319612745, ack=3289393891, hl=20, dl=43, reserved=0, flags=24, win=3626], udp=<uninitialized>, icmp=<uninitialized>] [0] p: raw_pkt_hdr = [l2=[encap=LINK_ETHERNET, len=97, cap_len=97, src=cc:b2:55:f4:62:92, dst=58:b0:35:86:54:8d, vlan=<uninitialized>, inner_vlan=<uninitialized>, eth_type=2048, proto=L3_IPV4], ip=[hl=20, tos=0, len=83, id=50807, ttl=243, p=6, src=17.167.150.73, dst=192.168.133.100], ip6=<uninitialized>, tcp=[sport=443/tcp, dport=49655/tcp, seq=2319612745, ack=3289393891, hl=20, dl=43, reserved=0, flags=24, win=3626], udp=<uninitialized>, icmp=<uninitialized>]

View file

@ -27,7 +27,7 @@ event ssl_plaintext_data(c: connection, is_orig: bool, record_version: count, co
print "Plaintext data", c$id$orig_h, c$id$resp_h, is_orig, SSL::version_strings[record_version], content_type, length; print "Plaintext data", c$id$orig_h, c$id$resp_h, is_orig, SSL::version_strings[record_version], content_type, length;
} }
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count) event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count, payload: string)
{ {
print "Encrypted data", c$id$orig_h, c$id$resp_h, is_orig, SSL::version_strings[record_version], content_type, length; print "Encrypted data", c$id$orig_h, c$id$resp_h, is_orig, SSL::version_strings[record_version], content_type, length;
} }

View file

@ -37,7 +37,7 @@ event ssl_established(c: connection)
print "established", c$id; print "established", c$id;
} }
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count) event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count, payload: string)
{ {
print "encrypted", c$id, is_orig, SSL::version_strings[record_version], content_type; print "encrypted", c$id, is_orig, SSL::version_strings[record_version], content_type;
} }

View file

@ -6,7 +6,7 @@
redef SSL::disable_analyzer_after_detection=F; redef SSL::disable_analyzer_after_detection=F;
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count) event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count, payload: string)
{ {
print "encrypted", c$id, is_orig, SSL::version_strings[record_version], content_type; print "encrypted", c$id, is_orig, SSL::version_strings[record_version], content_type;
} }