Skip to content

Commit

Permalink
stream/tcp: handle RST with MD5 or AO header
Browse files Browse the repository at this point in the history
Special handling for RST packets if they have an TCP MD5 or AO header option.
The options hash can't be validated. The end host might be able to validate
it, as it can have a key/password that was communicated out of band.

The sender could use this to move the TCP state to 'CLOSED', leading to
a desync of the TCP session.

This patch builds on top of
843d0b7 ("stream: support RST getting lost/ignored")

It flags the receiver as having received an RST and moves the TCP state
into the CLOSED state. It then reverts this if the sender continues to
send traffic. In this case it sets the following event:

    stream-event:suspected_rst_inject;

Bug: #4710.
  • Loading branch information
victorjulien committed Nov 12, 2021
1 parent 3212fa7 commit 50e2b97
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 1 deletion.
20 changes: 20 additions & 0 deletions src/decode-tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ static void DecodeTCPOptions(Packet *p, const uint8_t *pkt, uint16_t pktlen)
ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN);
}
break;
/* RFC 2385 MD5 option */
case TCP_OPT_MD5:
SCLogDebug("MD5 option, len %u", olen);
if (olen != 18) {
ENGINE_SET_INVALID_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
/* we can't validate the option as the key is out of band */
p->tcpvars.md5_option_present = true;
}
break;
/* RFC 5925 AO option */
case TCP_OPT_AO:
SCLogDebug("AU option, len %u", olen);
if (olen < 4) {
ENGINE_SET_INVALID_EVENT(p,TCP_OPT_INVALID_LEN);
} else {
/* we can't validate the option as the key is out of band */
p->tcpvars.ao_option_present = true;
}
break;
}

pkt += olen;
Expand Down
4 changes: 4 additions & 0 deletions src/decode-tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
#define TCP_OPT_TFO 0x22 /* TCP Fast Open */
#define TCP_OPT_EXP1 0xfd /* Experimental, could be TFO */
#define TCP_OPT_EXP2 0xfe /* Experimental, could be TFO */
#define TCP_OPT_MD5 0x13 /* 19: RFC 2385 TCP MD5 option */
#define TCP_OPT_AO 0x1d /* 29: RFC 5925 TCP AO option */

#define TCP_OPT_SACKOK_LEN 2
#define TCP_OPT_WS_LEN 3
Expand Down Expand Up @@ -153,6 +155,8 @@ typedef struct TCPHdr_
typedef struct TCPVars_
{
/* commonly used and needed opts */
bool md5_option_present;
bool ao_option_present;
bool ts_set;
uint32_t ts_val; /* host-order */
uint32_t ts_ecr; /* host-order */
Expand Down
19 changes: 18 additions & 1 deletion src/stream-tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4433,6 +4433,9 @@ static int StreamTcpPacketStateClosed(ThreadVars *tv, Packet *p,
if (ostream->flags & STREAMTCP_STREAM_FLAG_RST_RECV) {
if (StreamTcpStateDispatch(tv, p, stt, ssn, &stt->pseudo_queue, ssn->pstate) < 0)
return -1;
/* if state is still "closed", it wasn't updated by our dispatch. */
if (ssn->state == TCP_CLOSED)
ssn->state = ssn->pstate;
}
}
return 0;
Expand Down Expand Up @@ -5410,7 +5413,6 @@ TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)

static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
{

uint8_t os_policy;

if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
Expand Down Expand Up @@ -5448,6 +5450,21 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
}
}

/* RFC 2385 md5 signature header or RFC 5925 TCP AO headerpresent. Since we can't
* validate these (requires key that is set/transfered out of band), we can't know
* if the RST will be accepted or rejected by the end host. We accept it, but keep
* tracking if the sender of it ignores it, which would be a sign of injection. */
if (p->tcpvars.md5_option_present || p->tcpvars.ao_option_present) {
TcpStream *receiver_stream;
if (PKT_IS_TOSERVER(p)) {
receiver_stream = &ssn->server;
} else {
receiver_stream = &ssn->client;
}
SCLogDebug("ssn %p: setting STREAMTCP_STREAM_FLAG_RST_RECV on receiver stream", ssn);
receiver_stream->flags |= STREAMTCP_STREAM_FLAG_RST_RECV;
}

if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
if (PKT_IS_TOSERVER(p)) {
if (SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
Expand Down

0 comments on commit 50e2b97

Please sign in to comment.