From fa5af896903efb7dc2c73c26c555167f5eed7a0e Mon Sep 17 00:00:00 2001 From: liuxueli Date: Sat, 6 Nov 2021 21:10:20 +0300 Subject: [PATCH] =?UTF-8?q?TSG-8364:=20=E5=A2=9E=E5=8A=A0=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E9=95=BF=E5=BA=A6=E7=9A=84=E9=80=BB=E8=BE=91=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E5=AF=BC=E8=87=B4=E6=AE=B5=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gquic_process.cpp | 12 +++++-- src/parser_quic.cpp | 75 ++++++++++++++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/gquic_process.cpp b/src/gquic_process.cpp index 79b8efe..e1e5002 100644 --- a/src/gquic_process.cpp +++ b/src/gquic_process.cpp @@ -1,7 +1,7 @@ /* * quic_process.c * - * Created on: 2019Äê4ÔÂ2ÈÕ + * Created on: 2019��4��2�� * Author: root */ @@ -1134,12 +1134,20 @@ int parse_encrypt_parameter(struct _quic_stream *quic_stream, unsigned char *pay case EXT_QUIC_PARAM_USER_AGENT: // 2021-10-20 deprecated quic_stream->ua_idx=quic_stream->ext_tag_num++; length=get_value(payload, &used_len, 1); // length=1 + if(length+used_len>payload_len) + { + return 0; + } get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->ua_idx]), length, EXT_QUIC_PARAM_USER_AGENT, thread_seq); used_len+=length; break; case EXT_QUIC_PARAM_QUIC_VERSION: quic_stream->ver_idx=quic_stream->ext_tag_num++; length=get_value(payload, &used_len, 1); // length=1 + if(length+used_len>payload_len) + { + return 0; + } get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->ver_idx]), length, EXT_QUIC_PARAM_QUIC_VERSION, thread_seq); *(unsigned int *)quic_stream->ext_tags[quic_stream->ver_idx].value=(unsigned int)htonl(*(unsigned int *)quic_stream->ext_tags[quic_stream->ver_idx].value); used_len+=length; @@ -1448,7 +1456,7 @@ int quic_process(struct streaminfo *pstream, struct _quic_context* _context, int { _context->is_decrypt=1; ret=dissect_quic((char *)udp_detail->pdata, udp_detail->datalen, decrypt_payload, &decrypt_payload_len); - if(ret!=1 || decrypt_payload_len>2048 || decrypt_payload_len<0) + if(ret!=1 || decrypt_payload_len>2048 || decrypt_payload_len<=0) { return APP_STATE_GIVEME; } diff --git a/src/parser_quic.cpp b/src/parser_quic.cpp index 926e295..448935f 100644 --- a/src/parser_quic.cpp +++ b/src/parser_quic.cpp @@ -132,6 +132,7 @@ typedef struct _quic_packet_info { guint8 first_byte; } quic_packet_info_t; + /** * Given a QUIC message (header + non-empty payload), the actual packet number, * try to decrypt it using the PP cipher. @@ -168,7 +169,8 @@ static void quic_decrypt_message(quic_pp_cipher *pp_cipher, const char *payload, // buffer_length = length - (header_length + 16); // buffer_length = 297 - (2 + 16); buffer_length = length - (pkn_len + 16); - if (buffer_length == 0 || buffer_length >1500) { + if (buffer_length == 0 || buffer_length >1500) + { *error = (const guchar *)"Decryption not possible, ciphertext is too short or too long"; return; } @@ -669,10 +671,9 @@ static gboolean quic_create_initial_decoders(const quic_cid_t *cid, const gchar return TRUE; } -static int quic_extract_header(const char *payload, unsigned char *long_packet_type, unsigned int *version, quic_cid_t *dcid, quic_cid_t *scid) +static int quic_extract_header(const char *payload, unsigned int payload_len, unsigned char *long_packet_type, unsigned int *version, quic_cid_t *dcid, quic_cid_t *scid) { - unsigned int offset = 0; - + int offset = 0; unsigned char packet_type = payload[offset]; unsigned char is_long_header = packet_type & 0x80; if (is_long_header) @@ -682,7 +683,10 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t // short header form, store dummy value that is not a long packet type. *long_packet_type = QUIC_SHORT_PACKET; offset++; - + if(offset+6>=(int)payload_len) //verion_lenght: 4 ,scid_length_flag: 1 ,dcid_length_flag: 1 + { + return -1; + } *version = pntoh32((unsigned int *)&payload[offset]); if (is_long_header) { @@ -697,16 +701,23 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t // read DCID and SCID (both are prefixed by a length byte). unsigned char dcil = payload[offset]; offset++; + if(offset+dcil+1>=(int)payload_len) //scid_length_flag: +1 + { + return -1; + } if (dcil && dcil <= QUIC_MAX_CID_LENGTH) { memcpy(dcid->cid, &payload[offset], dcil); dcid->len = dcil; } offset += dcil; - + unsigned char scil = payload[offset]; offset++; - + if(offset+scil>=(int)payload_len) + { + return -1; + } if (scil && scil <= QUIC_MAX_CID_LENGTH) { memcpy(scid->cid, &payload[offset], scil); scid->len = scil; @@ -719,6 +730,10 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t // For short headers, the DCID length is unknown and could be 0 or // anything from 1 to 20 bytes. Copy the maximum possible and let the // consumer truncate it as necessary. + if(offset+QUIC_MAX_CID_LENGTH>=(int)payload_len) + { + return -1; + } memcpy(dcid->cid, &payload[offset], QUIC_MAX_CID_LENGTH); dcid->len = QUIC_MAX_CID_LENGTH; offset += QUIC_MAX_CID_LENGTH; @@ -727,6 +742,16 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t return offset; } +static void free_quic_cipher(quic_ciphers *initial_ciphers) +{ + if(initial_ciphers!=NULL) + { + quic_hp_cipher_reset(&(initial_ciphers->hp_cipher)); + quic_pp_cipher_reset(&(initial_ciphers->pp_cipher)); + } + +} + int dissect_quic(const char *payload, unsigned int length, unsigned char *out, unsigned int *out_length) { guint offset = 0; @@ -739,12 +764,12 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u guint8 first_byte = 0; const gboolean from_server = FALSE; quic_ciphers *ciphers = NULL; - int ret; + int ret, out_len; memset(&quic_packet, 0, sizeof(quic_packet_info_t)); memset(&conn, 0, sizeof(quic_info_data_t)); - ret = quic_extract_header(payload, &long_packet_type, &conn.version, &dcid, &scid); + ret = quic_extract_header(payload, length, &long_packet_type, &conn.version, &dcid, &scid); if (ret < 0) { return -1; @@ -760,12 +785,23 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u guint32 pkn32 = 0; // PKN is after type(1) + version(4) + DCIL+DCID + SCIL+SCID guint pn_offset = 1 + 4 + 1 + dcid.len + 1 + scid.len; + if(pn_offset+8>=length) //tvb_get_varint max: 8 + { + free_quic_cipher(&conn.client_initial_ciphers); + free_quic_cipher(&conn.server_initial_ciphers); + return 0; + } pn_offset += tvb_get_varint(payload, pn_offset, 8, &token_length, ENC_VARINT_QUIC); pn_offset += (guint)token_length; - // printf("%d\n", token_length); + if(pn_offset+8>=length) //tvb_get_varint max: 8 + { + free_quic_cipher(&conn.client_initial_ciphers); + free_quic_cipher(&conn.server_initial_ciphers); + return 0; + } pn_offset += tvb_get_varint(payload, pn_offset, 8, &payload_length, ENC_VARINT_QUIC); - if(payload_length==0 || payload_length >1500) + if(payload_length==0 || payload_length >length || pn_offset>=length) { quic_packet.decryption.error = (const guchar*)"Payload length is too small or too long"; } @@ -775,8 +811,12 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u ciphers = &conn.client_initial_ciphers; error = "Header deprotection failed"; if (quic_decrypt_header(payload, pn_offset, &ciphers->hp_cipher, GCRY_CIPHER_AES128, &first_byte, &pkn32)) + { error = NULL; - if (!error) { + } + + if (!error) + { quic_set_full_packet_number(&conn, &quic_packet, from_server, first_byte, pkn32); quic_packet.first_byte = first_byte; } @@ -791,8 +831,9 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u // Out if (!quic_packet.decryption.error) { - memcpy(out, quic_packet.decryption.data, quic_packet.decryption.data_len); - *out_length = quic_packet.decryption.data_len; + out_len=MIN(quic_packet.decryption.data_len, *out_length); + memcpy(out, quic_packet.decryption.data, out_len); + *out_length = out_len; g_free((gpointer)quic_packet.decryption.data); quic_packet.decryption.data = NULL; @@ -804,10 +845,8 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u ret=0; } - quic_hp_cipher_reset(&conn.client_initial_ciphers.hp_cipher); - quic_pp_cipher_reset(&conn.client_initial_ciphers.pp_cipher); - quic_hp_cipher_reset(&conn.server_initial_ciphers.hp_cipher); - quic_pp_cipher_reset(&conn.server_initial_ciphers.pp_cipher); + free_quic_cipher(&conn.client_initial_ciphers); + free_quic_cipher(&conn.server_initial_ciphers); return ret; }