From: Victor Julien Date: Mon, 25 Nov 2019 14:21:32 +0000 (+0100) Subject: http/multipart: process incomplete file data X-Git-Tag: suricata-5.0.1~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54d93e1eb982562964ffb5c99e6b990236fe02af;p=thirdparty%2Fsuricata.git http/multipart: process incomplete file data Start processing multipart data as soon as it is available to allow inspection sooner. --- diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 5a85aa4567..22f3c16c39 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1311,14 +1311,16 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4); /* search for the header start, header end and form end */ - uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len, + const uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len, boundary, expected_boundary_len); + /* end marker belonging to header_start */ uint8_t *header_end = NULL; if (header_start != NULL) { header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), (uint8_t *)"\r\n\r\n", 4); } - uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len, + /* end of the multipart form */ + const uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len, boundary, expected_boundary_end_len); SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, @@ -1329,20 +1331,27 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER); /* if we're in the file storage process, deal with that now */ if (htud->tsflags & HTP_FILENAME_SET) { - if (header_start != NULL || form_end != NULL || (tx_progress > HTP_REQUEST_BODY)) { + if (header_start != NULL || (tx_progress > HTP_REQUEST_BODY)) { SCLogDebug("reached the end of the file"); const uint8_t *filedata = chunks_buffer; uint32_t filedata_len = 0; uint8_t flags = 0; - if (header_start < form_end || (header_start != NULL && form_end == NULL)) { - filedata_len = header_start - filedata - 2; /* 0d 0a */ - } else if (form_end != NULL && form_end < header_start) { - filedata_len = form_end - filedata; - } else if (form_end != NULL && form_end == header_start) { - filedata_len = form_end - filedata - 2; /* 0d 0a */ - } else if (tx_progress > HTP_REQUEST_BODY) { + if (header_start != NULL) { + if (header_start == filedata + 2) { + /* last chunk had all data, but not the boundary */ + SCLogDebug("last chunk had all data, but not the boundary"); + filedata_len = 0; + } else if (header_start > filedata + 2) { + SCLogDebug("some data from last file before the boundary"); + /* some data from last file before the boundary */ + filedata_len = header_start - filedata - 2; + } + } + /* body parsing done, we did not get our form end. Use all data + * we still have and signal to files API we have an issue. */ + if (tx_progress > HTP_REQUEST_BODY) { filedata_len = chunks_buffer_len; flags = FILE_TRUNCATED; } @@ -1413,14 +1422,14 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, uint32_t header_len = header_end - header_start; SCLogDebug("header_len %u", header_len); - uint8_t *header = header_start; + uint8_t *header = (uint8_t *)header_start; /* skip empty records */ if (expected_boundary_len == header_len) { goto next; } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) { header_len -= (expected_boundary_len + 2); - header = header_start + (expected_boundary_len + 2); // + for 0d 0a + header = (uint8_t *)header_start + (expected_boundary_len + 2); // + for 0d 0a } HtpRequestBodyMultipartParseHeader(hstate, htud, header, header_len, @@ -1440,6 +1449,8 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, /* everything until the final boundary is the file */ if (form_end != NULL) { + SCLogDebug("have form_end"); + filedata = header_end + 4; if (form_end == filedata) { HTPSetEvent(hstate, htud, STREAM_TOSERVER, @@ -1507,23 +1518,27 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, PrintRawDataFp(stdout, filedata, filedata_len); printf("FILEDATA END: \n"); #endif - /* form doesn't end in this chunk, but part might. Lets + /* form doesn't end in this chunk, but the part might. Lets * see if have another coming up */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, boundary, expected_boundary_len); SCLogDebug("header_next %p", header_next); if (header_next == NULL) { - /* no, but we'll handle the file data when we see the - * form_end */ - SCLogDebug("more file data to come"); uint32_t offset = (header_end + 4) - chunks_buffer; SCLogDebug("offset %u", offset); htud->request_body.body_parsed += offset; + if (filedata_len >= (uint32_t)(expected_boundary_len + 2)) { + filedata_len -= (uint32_t)(expected_boundary_len + 2 - 1); + SCLogDebug("opening file with partial data"); + } else { + filedata = NULL; + filedata_len = 0; + } result = HTPFileOpen(hstate, filename, filename_len, - NULL, 0, HtpGetActiveRequestTxID(hstate), + filedata, filedata_len, HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); if (result == -1) { goto end; @@ -1531,6 +1546,8 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, htud->tsflags |= HTP_DONTSTORE; } FlagDetectStateNewFile(htud, STREAM_TOSERVER); + htud->request_body.body_parsed += filedata_len; + SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); } else if (header_next - filedata > 2) { filedata_len = header_next - filedata - 2;