From: Victor Julien Date: Wed, 22 Feb 2012 16:55:24 +0000 (+0100) Subject: file-inspection: support POST requests that do not use multipart. X-Git-Tag: suricata-1.3beta1~176 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3702a33ae999cd8fbec4febcc1667a1c7ed74063;p=thirdparty%2Fsuricata.git file-inspection: support POST requests that do not use multipart. --- diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index 89ce9df108..c50ba19429 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -924,6 +924,92 @@ end: return result; } +/** \test POST, but not multipart */ +static int HTPFileParserTest07(void) { + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "POST /filename HTTP/1.1\r\n" + "Host: www.server.lan\r\n" + "Content-Length: 11\r\n" + "\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "FILECONTENT"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + + TcpSession ssn; + HtpState *http_state = NULL; + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + + StreamTcpInitConfig(TRUE); + + SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); + int r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); + r = AppLayerParse(NULL, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + htp_tx_t *tx = list_get(http_state->connp->conn->transactions, 0); + if (tx == NULL) { + goto end; + } + + if (tx->request_method == NULL || memcmp(bstr_tocstr(tx->request_method), "POST", 4) != 0) + { + printf("expected method POST, got %s \n", bstr_tocstr(tx->request_method)); + goto end; + } + + if (http_state->files_ts == NULL || http_state->files_ts->tail == NULL || + http_state->files_ts->tail->state != FILE_STATE_CLOSED) { + printf("state != FILE_STATE_CLOSED"); + goto end; + } + + if (http_state->files_ts->head->chunks_head->len != 11) { + printf("expected 11 but file is %u bytes instead: ", + http_state->files_ts->head->chunks_head->len); + PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, + http_state->files_ts->head->chunks_head->len); + goto end; + } + + if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, + http_state->files_ts->head->chunks_head->len) != 0) { + goto end; + } + + result = 1; +end: + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + #endif /* UNITTESTS */ void HTPFileParserRegisterTests(void) { @@ -934,5 +1020,6 @@ void HTPFileParserRegisterTests(void) { UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04, 1); UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05, 1); UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06, 1); + UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07, 1); #endif /* UNITTESTS */ } diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 304dcad6f1..5fa0231844 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1004,7 +1004,8 @@ static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len, * \param d HTTP transaction * \param htud transaction userdata * - * \retval 0 ok + * \retval 1 ok, multipart set up + * \retval 0 ok, not multipart though * \retval -1 error: problem with the boundary * * If the request contains a multipart message, this function will @@ -1044,8 +1045,9 @@ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) { return -1; } } + SCReturnInt(1); } - return 0; + SCReturnInt(0); } /** @@ -1490,7 +1492,61 @@ int HtpRequestBodySetupPUT(htp_tx_data_t *d, HtpTxUserData *htud) { return 0; } -int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud, +/** \internal + * \brief Handle POST, no multipart body data + */ +static int HtpRequestBodyHandlePOST(HtpState *hstate, HtpTxUserData *htud, + htp_tx_t *tx, uint8_t *data, uint32_t data_len) +{ + int result = 0; + + /* see if we need to open the file */ + if (!(htud->flags & HTP_FILENAME_SET)) + { + uint8_t *filename = NULL; + uint32_t filename_len = 0; + + /* get the name */ + if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) { + filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path); + filename_len = bstr_len(tx->parsed_uri->path); + } + + result = HTPFileOpen(hstate, filename, filename_len, data, data_len, + hstate->transaction_cnt, STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + htud->flags |= HTP_DONTSTORE; + } else { + htud->flags |= HTP_FILENAME_SET; + htud->flags &= ~HTP_DONTSTORE; + } + } + else + { + /* otherwise, just store the data */ + + if (!(htud->flags & HTP_DONTSTORE)) { + result = HTPFileStoreChunk(hstate, data, data_len, STREAM_TOSERVER); + if (result == -1) { + goto end; + } else if (result == -2) { + /* we know for sure we're not storing the file */ + htud->flags |= HTP_DONTSTORE; + } + } + } + + return 0; +end: + return -1; +} + +/** \internal + * \brief Handle PUT body data + */ +static int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud, htp_tx_t *tx, uint8_t *data, uint32_t data_len) { int result = 0; @@ -1637,8 +1693,13 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) htud->operation = HTP_BODY_REQUEST; if (d->tx->request_method_number == M_POST) { - if (HtpRequestBodySetupMultipart(d, htud) == 0) { + SCLogDebug("POST"); + int r = HtpRequestBodySetupMultipart(d, htud); + if (r == 1) { htud->request_body.type = HTP_BODY_REQUEST_MULTIPART; + } else if (r == 0) { + htud->request_body.type = HTP_BODY_REQUEST_POST; + SCLogDebug("not multipart"); } } else if (d->tx->request_method_number == M_PUT) { if (HtpRequestBodySetupPUT(d, htud) == 0) { @@ -1691,9 +1752,9 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) goto end; } #ifdef PRINT - printf("REASSCHUNK START: \n"); - PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); - printf("REASSCHUNK END: \n"); + printf("REASSCHUNK START: \n"); + PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len); + printf("REASSCHUNK END: \n"); #endif HtpRequestBodyHandleMultipart(hstate, htud, chunks_buffer, chunks_buffer_len); @@ -1701,6 +1762,8 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) if (chunks_buffer != NULL) { SCFree(chunks_buffer); } + } else if (htud->request_body.type == HTP_BODY_REQUEST_POST) { + HtpRequestBodyHandlePOST(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } else if (htud->request_body.type == HTP_BODY_REQUEST_PUT) { HtpRequestBodyHandlePUT(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 9f7505a6ac..ac27f9034d 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -77,7 +77,8 @@ enum { enum { HTP_BODY_REQUEST_NONE = 0, - HTP_BODY_REQUEST_MULTIPART, + HTP_BODY_REQUEST_MULTIPART, /* POST, MP */ + HTP_BODY_REQUEST_POST, /* POST, no MP */ HTP_BODY_REQUEST_PUT, };