mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 15:48:19 +00:00
BIT-1314: Add detection for Quantum Insert attacks
TCP_Reassembler can now keep a history of old TCP segments using the `tcp_max_old_segments` option. A value of zero will disable it. An overlapping segment with different data can indicate a possible TCP injection attack. The rexmit_inconsistency event will fire if this is the case.
This commit is contained in:
parent
5147b0bb02
commit
b386b2ba51
5 changed files with 87 additions and 1 deletions
|
@ -49,6 +49,7 @@ double tcp_partial_close_delay;
|
||||||
int tcp_max_initial_window;
|
int tcp_max_initial_window;
|
||||||
int tcp_max_above_hole_without_any_acks;
|
int tcp_max_above_hole_without_any_acks;
|
||||||
int tcp_excessive_data_without_further_acks;
|
int tcp_excessive_data_without_further_acks;
|
||||||
|
int tcp_max_old_segments;
|
||||||
|
|
||||||
RecordType* socks_address;
|
RecordType* socks_address;
|
||||||
|
|
||||||
|
@ -354,6 +355,7 @@ void init_net_var()
|
||||||
opt_internal_int("tcp_max_above_hole_without_any_acks");
|
opt_internal_int("tcp_max_above_hole_without_any_acks");
|
||||||
tcp_excessive_data_without_further_acks =
|
tcp_excessive_data_without_further_acks =
|
||||||
opt_internal_int("tcp_excessive_data_without_further_acks");
|
opt_internal_int("tcp_excessive_data_without_further_acks");
|
||||||
|
tcp_max_old_segments = opt_internal_int("tcp_max_old_segments");
|
||||||
|
|
||||||
socks_address = internal_type("SOCKS::Address")->AsRecordType();
|
socks_address = internal_type("SOCKS::Address")->AsRecordType();
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ extern double tcp_reset_delay;
|
||||||
extern int tcp_max_initial_window;
|
extern int tcp_max_initial_window;
|
||||||
extern int tcp_max_above_hole_without_any_acks;
|
extern int tcp_max_above_hole_without_any_acks;
|
||||||
extern int tcp_excessive_data_without_further_acks;
|
extern int tcp_excessive_data_without_further_acks;
|
||||||
|
extern int tcp_max_old_segments;
|
||||||
|
|
||||||
extern RecordType* socks_address;
|
extern RecordType* socks_address;
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,38 @@ uint64 Reassembler::total_size = 0;
|
||||||
Reassembler::Reassembler(uint64 init_seq)
|
Reassembler::Reassembler(uint64 init_seq)
|
||||||
{
|
{
|
||||||
blocks = last_block = 0;
|
blocks = last_block = 0;
|
||||||
|
old_blocks = last_old_block = 0;
|
||||||
|
total_old_blocks = max_old_blocks = 0;
|
||||||
trim_seq = last_reassem_seq = init_seq;
|
trim_seq = last_reassem_seq = init_seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reassembler::~Reassembler()
|
Reassembler::~Reassembler()
|
||||||
{
|
{
|
||||||
ClearBlocks();
|
ClearBlocks();
|
||||||
|
ClearOldBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reassembler::CheckOverlap(DataBlock *head, DataBlock *tail,
|
||||||
|
uint64 seq, uint64 len, const u_char* data)
|
||||||
|
{
|
||||||
|
if ( ! head || ! tail )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( seq_between(seq, head->seq, tail->upper) )
|
||||||
|
{
|
||||||
|
for ( DataBlock* b = head; b; b = b->next )
|
||||||
|
{
|
||||||
|
if ( seq_between(seq, b->seq, b->upper) )
|
||||||
|
{
|
||||||
|
uint64 overlap_start = seq;
|
||||||
|
uint64 overlap_offset = overlap_start - b->seq;
|
||||||
|
uint64 new_b_len = len;
|
||||||
|
uint64 b_len = b->upper - overlap_start;
|
||||||
|
uint64 overlap_len = min(new_b_len, b_len);
|
||||||
|
Overlap(&b->block[overlap_offset], data, overlap_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reassembler::NewBlock(double t, uint64 seq, uint64 len, const u_char* data)
|
void Reassembler::NewBlock(double t, uint64 seq, uint64 len, const u_char* data)
|
||||||
|
@ -49,6 +75,9 @@ void Reassembler::NewBlock(double t, uint64 seq, uint64 len, const u_char* data)
|
||||||
|
|
||||||
uint64 upper_seq = seq + len;
|
uint64 upper_seq = seq + len;
|
||||||
|
|
||||||
|
CheckOverlap( blocks, last_block, seq, len, data );
|
||||||
|
CheckOverlap( old_blocks, last_old_block, seq, len, data );
|
||||||
|
|
||||||
if ( upper_seq <= trim_seq )
|
if ( upper_seq <= trim_seq )
|
||||||
// Old data, don't do any work for it.
|
// Old data, don't do any work for it.
|
||||||
return;
|
return;
|
||||||
|
@ -119,7 +148,33 @@ uint64 Reassembler::TrimToSeq(uint64 seq)
|
||||||
num_missing += seq - blocks->upper;
|
num_missing += seq - blocks->upper;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete blocks;
|
if (max_old_blocks)
|
||||||
|
{
|
||||||
|
blocks->next = 0;
|
||||||
|
if (last_old_block)
|
||||||
|
{
|
||||||
|
blocks->prev = last_old_block;
|
||||||
|
last_old_block->next = blocks;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blocks->prev = 0;
|
||||||
|
old_blocks = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_old_block = blocks;
|
||||||
|
total_old_blocks++;
|
||||||
|
|
||||||
|
while (old_blocks && total_old_blocks > max_old_blocks)
|
||||||
|
{
|
||||||
|
DataBlock* next = old_blocks->next;
|
||||||
|
delete old_blocks;
|
||||||
|
old_blocks = next;
|
||||||
|
total_old_blocks--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delete blocks;
|
||||||
|
|
||||||
blocks = b;
|
blocks = b;
|
||||||
}
|
}
|
||||||
|
@ -156,6 +211,19 @@ void Reassembler::ClearBlocks()
|
||||||
last_block = 0;
|
last_block = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reassembler::ClearOldBlocks()
|
||||||
|
{
|
||||||
|
while ( old_blocks )
|
||||||
|
{
|
||||||
|
DataBlock* b = old_blocks->next;
|
||||||
|
delete old_blocks;
|
||||||
|
old_blocks = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_old_block = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint64 Reassembler::TotalSize() const
|
uint64 Reassembler::TotalSize() const
|
||||||
{
|
{
|
||||||
uint64 size = 0;
|
uint64 size = 0;
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
|
|
||||||
// Delete all held blocks.
|
// Delete all held blocks.
|
||||||
void ClearBlocks();
|
void ClearBlocks();
|
||||||
|
void ClearOldBlocks();
|
||||||
|
|
||||||
int HasBlocks() const { return blocks != 0; }
|
int HasBlocks() const { return blocks != 0; }
|
||||||
uint64 LastReassemSeq() const { return last_reassem_seq; }
|
uint64 LastReassemSeq() const { return last_reassem_seq; }
|
||||||
|
@ -50,6 +51,8 @@ public:
|
||||||
// Sum over all data buffered in some reassembler.
|
// Sum over all data buffered in some reassembler.
|
||||||
static uint64 TotalMemoryAllocation() { return total_size; }
|
static uint64 TotalMemoryAllocation() { return total_size; }
|
||||||
|
|
||||||
|
void SetMaxOldBlocks(uint32 count) { max_old_blocks = count; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Reassembler() { }
|
Reassembler() { }
|
||||||
|
|
||||||
|
@ -65,10 +68,19 @@ protected:
|
||||||
DataBlock* AddAndCheck(DataBlock* b, uint64 seq,
|
DataBlock* AddAndCheck(DataBlock* b, uint64 seq,
|
||||||
uint64 upper, const u_char* data);
|
uint64 upper, const u_char* data);
|
||||||
|
|
||||||
|
void CheckOverlap(DataBlock *head, DataBlock *tail,
|
||||||
|
uint64 seq, uint64 len, const u_char* data);
|
||||||
|
|
||||||
DataBlock* blocks;
|
DataBlock* blocks;
|
||||||
DataBlock* last_block;
|
DataBlock* last_block;
|
||||||
|
|
||||||
|
DataBlock* old_blocks;
|
||||||
|
DataBlock* last_old_block;
|
||||||
|
|
||||||
uint64 last_reassem_seq;
|
uint64 last_reassem_seq;
|
||||||
uint64 trim_seq; // how far we've trimmed
|
uint64 trim_seq; // how far we've trimmed
|
||||||
|
uint32 max_old_blocks;
|
||||||
|
uint32 total_old_blocks;
|
||||||
|
|
||||||
static uint64 total_size;
|
static uint64 total_size;
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,6 +42,9 @@ TCP_Reassembler::TCP_Reassembler(analyzer::Analyzer* arg_dst_analyzer,
|
||||||
seq_to_skip = 0;
|
seq_to_skip = 0;
|
||||||
in_delivery = false;
|
in_delivery = false;
|
||||||
|
|
||||||
|
if ( tcp_max_old_segments )
|
||||||
|
SetMaxOldBlocks(tcp_max_old_segments);
|
||||||
|
|
||||||
if ( tcp_contents )
|
if ( tcp_contents )
|
||||||
{
|
{
|
||||||
// Val dst_port_val(ntohs(Conn()->RespPort()), TYPE_PORT);
|
// Val dst_port_val(ntohs(Conn()->RespPort()), TYPE_PORT);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue