From c85773b34384b34dbe60b3029e7a2d0e9d867537 Mon Sep 17 00:00:00 2001 From: ivanr Date: Fri, 10 Aug 2007 09:59:57 +0000 Subject: [PATCH] Added MULTIPART_UNMATCHED_BOUNDARY. Not very reliable, as it detects anything that looks like a boundary, which means any line that begins with -- but we don't think it's a boundary. --- apache2/msc_multipart.c | 116 +++++++++++++++++++++------------------- apache2/msc_multipart.h | 1 + apache2/re_variables.c | 23 ++++++++ 3 files changed, 86 insertions(+), 54 deletions(-) diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 858a400e..a414e164 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -624,7 +624,7 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, return -1; } - /* here we loop through the data available, byte by byte */ + /* here we loop through the available data, one byte at a time */ while(inleft > 0) { char c = *inptr; int process_buffer = 0; @@ -645,71 +645,79 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, * or the end of our internal buffer */ if ((c == 0x0a)||(msr->mpd->bufleft == 0)||(process_buffer)) { + int processed_as_boundary = 0; + *(msr->mpd->bufptr) = 0; - /* boundary preconditions: length of the line greater than - * the length of the boundary + the first two characters - * are dashes "-" - */ - if ( msr->mpd->buf_contains_line - && (strlen(msr->mpd->buf) > strlen(msr->mpd->boundary) + 2) - && (((*(msr->mpd->buf) == '-'))&&(*(msr->mpd->buf + 1) == '-')) - && (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) ) + /* Do we have something that looks like a boundary? */ + if (msr->mpd->buf_contains_line + && (strlen(msr->mpd->buf) > 3) + && (((*(msr->mpd->buf) == '-'))&&(*(msr->mpd->buf + 1) == '-')) ) { - char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); - int is_final = 0; - - /* Is this the final boundary? */ - if ((*boundary_end == '-')&&(*(boundary_end + 1)== '-')) { - is_final = 1; - boundary_end += 2; - - if (msr->mpd->is_complete != 0) { - *error_msg = apr_psprintf(msr->mp, - "Multipart: Invalid boundary (final duplicate)."); - return -1; - } - } - - /* Allow for CRLF and LF line endings. */ - if ( ( (*boundary_end == '\r') - && (*(boundary_end + 1) == '\n') - && (*(boundary_end + 2) == '\0') ) - || ( (*boundary_end == '\n') - && (*(boundary_end + 1) == '\0') ) ) + /* Does it match our boundary? */ + if ((strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2) + && (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) ) { - if (*boundary_end == '\n') { - msr->mpd->flag_lf_line = 1; + char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); + int is_final = 0; + + /* Is this the final boundary? */ + if ((*boundary_end == '-')&&(*(boundary_end + 1)== '-')) { + is_final = 1; + boundary_end += 2; + + if (msr->mpd->is_complete != 0) { + *error_msg = apr_psprintf(msr->mp, + "Multipart: Invalid boundary (final duplicate)."); + return -1; + } } - if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { + /* Allow for CRLF and LF line endings. */ + if ( ( (*boundary_end == '\r') + && (*(boundary_end + 1) == '\n') + && (*(boundary_end + 2) == '\0') ) + || ( (*boundary_end == '\n') + && (*(boundary_end + 1) == '\0') ) ) + { + if (*boundary_end == '\n') { + msr->mpd->flag_lf_line = 1; + } + + if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { + return -1; + } + + if (is_final) { + msr->mpd->is_complete = 1; + } + + processed_as_boundary = 1; + } + else { + /* error */ + *error_msg = apr_psprintf(msr->mp, + "Multipart: Invalid boundary: %s", + log_escape_nq(msr->mp, msr->mpd->buf)); + return -1; + } + } else { + if ( (msr->mpd->flag_boundary_quoted) + && (strlen(msr->mpd->buf) > strlen(msr->mpd->boundary) + 3) + && (((*(msr->mpd->buf) == '-'))&&(*(msr->mpd->buf + 1) == '-')) + && (*(msr->mpd->buf + 2) == '"') + && (strncmp(msr->mpd->buf + 3, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) + ) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (quotes)."); return -1; } - if (is_final) { - msr->mpd->is_complete = 1; - } - } - else { - /* error */ - *error_msg = apr_psprintf(msr->mp, - "Multipart: Invalid boundary: %s", - log_escape_nq(msr->mp, msr->mpd->buf)); - return -1; + msr->mpd->flag_unmatched_boundary = 1; } } - else { - if ( msr->mpd->buf_contains_line - && (msr->mpd->flag_boundary_quoted) - && (strlen(msr->mpd->buf) > strlen(msr->mpd->boundary) + 3) - && (((*(msr->mpd->buf) == '-'))&&(*(msr->mpd->buf + 1) == '-')) - && (*(msr->mpd->buf + 2) == '"') - && (strncmp(msr->mpd->buf + 3, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) - ) { - *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary (quotes)."); - return -1; - } + /* Process as data if it was not a boundary. */ + if (processed_as_boundary == 0) { if (msr->mpd->mpp == NULL) { msr->mpd->flag_data_before = 1; msr_log(msr, 4, "Multipart: Ignoring data before first boundary."); diff --git a/apache2/msc_multipart.h b/apache2/msc_multipart.h index f5b87f86..126f8b4d 100644 --- a/apache2/msc_multipart.h +++ b/apache2/msc_multipart.h @@ -103,6 +103,7 @@ struct multipart_data { int flag_header_folding; int flag_boundary_quoted; int flag_lf_line; + int flag_unmatched_boundary; }; diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 115fa964..7bd69a35 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1308,6 +1308,18 @@ static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, m return var_simple_generate(var, vartab, mptmp, "0"); } +/* MULTIPART_UNMATCHED_BOUNDARY */ + +static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + if ((msr->mpd != NULL)&&(msr->mpd->flag_unmatched_boundary != 0)) { + return var_simple_generate(var, vartab, mptmp, "1"); + } else { + return var_simple_generate(var, vartab, mptmp, "0"); + } +} + /* TIME */ static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, @@ -2306,6 +2318,17 @@ void msre_engine_register_default_variables(msre_engine *engine) { PHASE_REQUEST_BODY ); + /* MULTIPART_UNMATCHED_BOUNDARY */ + msre_engine_variable_register(engine, + "MULTIPART_UNMATCHED_BOUNDARY", + VAR_SIMPLE, + 0, 0, + NULL, + var_multipart_unmatched_boundary_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + /* PATH_INFO */ msre_engine_variable_register(engine, "PATH_INFO",