From: Victor Julien Date: Wed, 24 Jan 2018 14:59:57 +0000 (+0100) Subject: stream: handle data on incomplete 3whs X-Git-Tag: suricata-4.0.4~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97ebd3b05acaab3ed0d0e1430d554443c023715f;p=thirdparty%2Fsuricata.git stream: handle data on incomplete 3whs If we have only seen the SYN and SYN/ACK of the 3whs, accept from server data if it perfectly matches the SEQ/ACK expectations. This might happen in 2 scenarios: 1. packet loss: if we lost the final ACK, we may get data that fits this pattern (e.g. a SMTP EHLO message). 2. MOTS/MITM packet injection: an attacker can send a data packet together with its SYN/ACK packet. The client due to timing almost certainly gets the SYN/ACK before considering the data packet, and will respond with the final ACK before processing the data packet. In IDS mode we will accept the data packet and rely on the reassembly engine to warn us if the packet was indeed injected. In IPS mode we will drop the packet. In the packet loss case we will rely on retransmissions to get the session back up and running. For the injection case we blocked this injection attempt. --- diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 81c46bffbe..863cb3354f 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -1789,6 +1789,7 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, return 0; } + bool ack_indicates_missed_3whs_ack_packet = false; /* Check if the ACK received is in right direction. But when we have * picked up a mid stream session after missing the initial SYN pkt, * in this case the ACK packet can arrive from either client (normal @@ -1801,12 +1802,25 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, SCLogDebug("ssn %p: ACK received on midstream SYN/ACK " "pickup session",ssn); /* fall through */ - } else { - SCLogDebug("ssn %p: ACK received in the wrong direction", - ssn); - StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR); - return -1; + } else { + /* if we missed traffic between the S/SA and the current + * 'wrong direction' ACK, we could end up here. In IPS + * reject it. But in IDS mode we continue. + * + * IPS rejects as it should see all packets, so pktloss + * should lead to retransmissions. As this can also be + * pattern for MOTS/MITM injection attacks, we need to be + * careful. + */ + if (StreamTcpInlineMode()) { + SCLogDebug("ssn %p: ACK received in the wrong direction", + ssn); + + StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR); + return -1; + } + ack_indicates_missed_3whs_ack_packet = true; } } @@ -1940,6 +1954,25 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); + + /* toclient packet: after having missed the 3whs's final ACK */ + } else if (ack_indicates_missed_3whs_ack_packet && + SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack) && + SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) + { + SCLogDebug("ssn %p: packet fits perfectly after a missed 3whs-ACK", ssn); + + StreamTcpUpdateNextSeq(ssn, &ssn->server, (TCP_GET_SEQ(p) + p->payload_len)); + + ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; + ssn->server.next_win = ssn->server.last_ack + ssn->server.window; + + StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); + SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn); + + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->server, p, pq); + } else { SCLogDebug("ssn %p: wrong seq nr on packet", ssn);