From 6f76ac176d70d85fa2a5719dacdc8fef0ef074dc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 11 Oct 2012 21:02:56 +0200 Subject: [PATCH] stream: add option to match on overlapping data Set event on overlapping data segments that have different data. Add stream-events option stream-event:reassembly_overlap_different_data and add an example rule. Issue 603. --- rules/stream-events.rules | 3 +- src/decode-events.h | 2 + src/detect-engine-event.c | 7 ++++ src/detect-engine-event.h | 1 + src/stream-tcp-reassemble.c | 81 ++++++++++++++++++++++++++++++++++++- src/stream-tcp.h | 3 ++ 6 files changed, 95 insertions(+), 2 deletions(-) diff --git a/rules/stream-events.rules b/rules/stream-events.rules index 5d6f913b2e..447885d8b4 100644 --- a/rules/stream-events.rules +++ b/rules/stream-events.rules @@ -56,5 +56,6 @@ alert tcp any any -> any any (msg:"SURICATA STREAM SHUTDOWN RST invalid ack"; st #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly segment before base seq"; stream-event:reassembly_segment_before_base_seq; sid:2210047; rev:1;) # Sequence gap: missing data in the reassembly engine. Usually due to packet loss. Will be very noisy on a overloaded link / sensor. #alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; sid:2210048; rev:1;) -# next sid 2210050 +alert tcp any any -> any any (msg:"SURICATA STREAM reassembly overlap with different data"; stream-event:reassembly_overlap_different_data; sid:2210050; rev:1;) +# next sid 2210051 diff --git a/src/decode-events.h b/src/decode-events.h index 89f8422444..2a1bb69f5c 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -183,6 +183,8 @@ enum { STREAM_REASSEMBLY_SEQ_GAP, + STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, + /* SCTP EVENTS */ SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */ diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index d276313de8..3df8651837 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -34,6 +34,9 @@ #include "util-debug.h" +#include "stream-tcp.h" + + /* Need to get the DEvents[] array */ #define DETECT_EVENTS @@ -172,6 +175,10 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) goto error; de->event = DEvents[i].code; + + if (de->event == STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA) { + StreamTcpReassembleConfigEnableOverlapCheck(); + } return de; error: diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index f8034f96f0..b16d213825 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -171,6 +171,7 @@ struct DetectEngineEvents_ { { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, }, { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, }, { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, }, + { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, }, { NULL, 0 }, }; #endif /* DETECT_EVENTS */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 78ae7b052e..c267692fbe 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -92,6 +92,7 @@ static uint64_t segment_pool_cnt = 0; #endif /* index to the right pool for all packet sizes. */ static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */ +static int check_overlap_different_data = 0; /* Memory use counter */ SC_ATOMIC_DECLARE(uint64_t, ra_memuse); @@ -108,6 +109,12 @@ void StreamTcpSegmentDataCopy(TcpSegment *, TcpSegment *); TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *, uint16_t); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); void StreamTcpReassemblePseudoPacketCreate(TcpStream *, Packet *, PacketQueue *); +static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg, + uint32_t start_point, uint16_t len); + +void StreamTcpReassembleConfigEnableOverlapCheck(void) { + check_overlap_different_data = 1; +} /** * \brief Function to Increment the memory usage counter for the TCP reassembly @@ -1067,6 +1074,12 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr } } + if (check_overlap_different_data && + !StreamTcpSegmentDataCompare(seg, list_seg, list_seg->seq, overlap)) { + /* interesting, overlap with different data */ + StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); + } + if (StreamTcpInlineMode()) { if (StreamTcpInlineSegmentCompare(seg, list_seg) != 0) { StreamTcpInlineSegmentReplacePacket(p, list_seg); @@ -1259,6 +1272,12 @@ static int HandleSegmentStartsAtSameListSegment(ThreadVars *tv, TcpReassemblyThr } } + if (check_overlap_different_data && + !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) { + /* interesting, overlap with different data */ + StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); + } + if (StreamTcpInlineMode()) { if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) { StreamTcpInlineSegmentReplacePacket(p, list_seg); @@ -1460,6 +1479,12 @@ static int HandleSegmentStartsAfterListSegment(ThreadVars *tv, TcpReassemblyThre } } + if (check_overlap_different_data && + !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) { + /* interesting, overlap with different data */ + StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); + } + if (StreamTcpInlineMode()) { if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) { StreamTcpInlineSegmentReplacePacket(p, list_seg); @@ -3454,7 +3479,7 @@ void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg, if (SEQ_GT(start_point, dst_seg->seq)) { dst_pos = start_point - dst_seg->seq; - } else if (SEQ_LT(dst_seg->seq, start_point)) { + } else if (SEQ_LT(start_point, dst_seg->seq)) { dst_pos = dst_seg->seq - start_point; } @@ -3480,6 +3505,60 @@ void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg, " dst_pos %"PRIu16, len, src_pos, dst_pos); } +/** + * \brief Function to compare the data from a specific point up to given length. + * + * \param dst_seg Destination segment to compare the data + * \param src_seg Source segment of which data is to be compared to destination + * \param start_point Starting point to compare the data onwards + * \param len Length up to which data is need to be compared + * + * \retval 1 same + * \retval 0 different + */ +static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg, + uint32_t start_point, uint16_t len) +{ + uint32_t seq; + uint16_t src_pos = 0; + uint16_t dst_pos = 0; + + SCLogDebug("start_point %u dst_seg %u src_seg %u", start_point, dst_seg->seq, src_seg->seq); + + if (SEQ_GT(start_point, dst_seg->seq)) { + SCLogDebug("start_point %u > dst %u", start_point, dst_seg->seq); + dst_pos = start_point - dst_seg->seq; + } else if (SEQ_LT(start_point, dst_seg->seq)) { + SCLogDebug("start_point %u < dst %u", start_point, dst_seg->seq); + dst_pos = dst_seg->seq - start_point; + } + + if (SCLogDebugEnabled()) { + BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len); + } else { + if (((len + dst_pos) - 1) > dst_seg->payload_len) + return 1; + } + + src_pos = (uint16_t)(start_point - src_seg->seq); + + SCLogDebug("Comparing data from dst_pos %"PRIu16", src_pos %u", dst_pos, src_pos); + + for (seq = start_point; SEQ_LT(seq, (start_point + len)) && + src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len; + seq++, dst_pos++, src_pos++) + { + if (dst_seg->payload[dst_pos] != src_seg->payload[src_pos]) { + SCLogDebug("data is different %02x != %02x, dst_pos %u, src_pos %u", dst_seg->payload[dst_pos], src_seg->payload[src_pos], dst_pos, src_pos); + return 0; + } + } + + SCLogDebug("Compared data of size %"PRIu16" up to src_pos %"PRIu16 + " dst_pos %"PRIu16, len, src_pos, dst_pos); + return 1; +} + /** * \brief Function to copy the data from src_seg to dst_seg. * diff --git a/src/stream-tcp.h b/src/stream-tcp.h index 811fdcc862..d346e2adc6 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -57,6 +57,8 @@ typedef struct TcpStreamCnf_ { uint16_t reassembly_toserver_chunk_size; uint16_t reassembly_toclient_chunk_size; + int check_overlap_different_data; + /** reassembly -- inline mode * * sliding window size for raw stream reassembly @@ -115,6 +117,7 @@ Packet *StreamTcpPseudoSetup(Packet *, uint8_t *, uint32_t); int StreamTcpSegmentForEach(Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); +void StreamTcpReassembleConfigEnableOverlapCheck(void); /** ------- Inline functions: ------ */