From cc51eec59dfd1e9294b13fc85f462d7816542f46 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 20 Feb 2013 16:13:40 +0100 Subject: [PATCH] Use new libhtp query string normalization. Bug #739. --- configure.ac | 3 +- src/app-layer-htp.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 947c2d9889..8ed39655b4 100644 --- a/configure.ac +++ b/configure.ac @@ -1017,7 +1017,7 @@ AC_INIT(configure.ac) AC_CHECK_LIB([htp], [htp_config_register_request_uri_normalize],AC_DEFINE_UNQUOTED([HAVE_HTP_URI_NORMALIZE_HOOK],[1],[Found htp_config_register_request_uri_normalize function in libhtp]) ,,[-lhtp]) # check for htp_tx_get_response_headers_raw AC_CHECK_LIB([htp], [htp_tx_get_response_headers_raw],AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Found htp_tx_get_response_headers_raw in libhtp]) ,,[-lhtp]) - + AC_CHECK_LIB([htp], [htp_decode_query_inplace],AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Found htp_decode_query_inplace function in libhtp]) ,,[-lhtp]) ]) # even if we are using an installed htp lib we still need to gen Makefiles inside of htp @@ -1026,6 +1026,7 @@ AC_INIT(configure.ac) AS_IF([test "x$enable_non_bundled_htp" = "xno"], [ AC_DEFINE_UNQUOTED([HAVE_HTP_URI_NORMALIZE_HOOK],[1],[Assuming htp_config_register_request_uri_normalize function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Assuming htp_tx_get_response_headers_raw function in bundled libhtp]) + AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Assuming htp_decode_query_inplace function in bundled libhtp]) ]) diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 072b40cbe6..fea12a25fd 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -823,8 +823,13 @@ static int HTPCallbackRequestUriNormalizeQuery(htp_connp_t *c) /* uri normalize the query string as well */ if (c->in_tx->parsed_uri->query != NULL) { +#ifdef HAVE_HTP_DECODE_QUERY_INPLACE + htp_decode_query_inplace(c->cfg, c->in_tx, + c->in_tx->parsed_uri->query); +#else htp_decode_path_inplace(c->cfg, c->in_tx, c->in_tx->parsed_uri->query); +#endif /* HAVE_HTP_DECODE_QUERY_INPLACE */ } SCReturnInt(HOOK_OK); } @@ -2152,6 +2157,9 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, * our query string callback also the query string) to lowercase. * Signatures do not expect this, so override it. */ htp_config_set_path_case_insensitive(cfg_prec->cfg, 0); +#ifdef HAVE_HTP_DECODE_QUERY_INPLACE + htp_config_set_query_case_insensitive(cfg_prec->cfg, 0); +#endif } else { SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Unknown personality " "\"%s\", ignoring", p->val); @@ -4442,6 +4450,210 @@ end: return result; } +/** \test Test http:// in query profile IDS + */ +static int HTPParserDecodingTest04(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /abc/def?a=http://www.abc.com/ HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + + StreamTcpInitConfig(TRUE); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) flags = STREAM_TOSERVER|STREAM_START; + else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; + else flags = STREAM_TOSERVER; + + r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", u, r); + result = 0; + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + uint8_t ref1[] = "/abc/def?a=http://www.abc.com/"; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); + if (tx != NULL && tx->request_uri_normalized != NULL) { + if (reflen != bstr_size(tx->request_uri_normalized)) { + printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, + (uintmax_t)reflen, + (uintmax_t)bstr_size(tx->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, + bstr_size(tx->request_uri_normalized)) != 0) + { + printf("normalized uri \""); + PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(TRUE); + if (htp_state != NULL) + HTPStateFree(htp_state); + UTHFreeFlow(f); + return result; +} + +/** \test Test \ char in query profile IDS. Bug 739 + */ +static int HTPParserDecodingTest05(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = + "GET /index?id=\\\" HTTP/1.1\r\nHost: www.domain.ltd\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + + HtpState *htp_state = NULL; + int r = 0; + char input[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ + personality: IDS\n\ + double-decode-path: yes\n\ + double-decode-query: yes\n\ +"; + + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + ConfYamlLoadString(input, strlen(input)); + HTPConfigure(); + char *addr = "4.3.2.1"; + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", addr, 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + + StreamTcpInitConfig(TRUE); + + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) flags = STREAM_TOSERVER|STREAM_START; + else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; + else flags = STREAM_TOSERVER; + + r = AppLayerParse(NULL, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", u, r); + result = 0; + goto end; + } + } + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + uint8_t ref1[] = "/index?id=\\\""; + size_t reflen = sizeof(ref1) - 1; + + htp_tx_t *tx = list_get(htp_state->connp->conn->transactions, 0); + if (tx != NULL && tx->request_uri_normalized != NULL) { + if (reflen != bstr_size(tx->request_uri_normalized)) { + printf("normalized uri len should be %"PRIuMAX", is %"PRIuMAX, + (uintmax_t)reflen, + (uintmax_t)bstr_size(tx->request_uri_normalized)); + goto end; + } + + if (memcmp(bstr_ptr(tx->request_uri_normalized), ref1, + bstr_size(tx->request_uri_normalized)) != 0) + { + printf("normalized uri \""); + PrintRawUriFp(stdout, (uint8_t *)bstr_ptr(tx->request_uri_normalized), bstr_size(tx->request_uri_normalized)); + printf("\" != \""); + PrintRawUriFp(stdout, ref1, reflen); + printf("\": "); + goto end; + } + } + + result = 1; + +end: + HTPFreeConfig(); + ConfDeInit(); + ConfRestoreContextBackup(); + HtpConfigRestoreBackup(); + + StreamTcpFreeConfig(TRUE); + if (htp_state != NULL) + HTPStateFree(htp_state); + UTHFreeFlow(f); + return result; +} + /** \test BG box crash -- chunks are messed up. Observed for real. */ static int HTPBodyReassemblyTest01(void) { @@ -4599,6 +4811,8 @@ void HTPParserRegisterTests(void) { UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01, 1); UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02, 1); UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03, 1); + UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04, 1); + UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05, 1); UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01, 1);