mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-10-06 06:16:51 +03:00
More multipart improvements. Added MULTIPART_MISSING_SEMICOLON.
This commit is contained in:
@@ -637,6 +637,12 @@ int multipart_init(modsec_rec *msr, char **error_msg) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) != 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid MIME type.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Count how many times the word "boundary" appears in the C-T header. */
|
/* Count how many times the word "boundary" appears in the C-T header. */
|
||||||
if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 1) {
|
if (multipart_count_boundary_params(msr->mp, msr->request_content_type) > 1) {
|
||||||
msr->mpd->flag_error = 1;
|
msr->mpd->flag_error = 1;
|
||||||
@@ -646,9 +652,28 @@ int multipart_init(modsec_rec *msr, char **error_msg) {
|
|||||||
|
|
||||||
msr->mpd->boundary = strstr(msr->request_content_type, "boundary");
|
msr->mpd->boundary = strstr(msr->request_content_type, "boundary");
|
||||||
if (msr->mpd->boundary != NULL) {
|
if (msr->mpd->boundary != NULL) {
|
||||||
|
char *p = NULL;
|
||||||
char *b = NULL;
|
char *b = NULL;
|
||||||
|
int seen_semicolon = 0;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
|
/* Check for extra characters before the boundary. */
|
||||||
|
for (p = (char *)(msr->request_content_type + 19); p < msr->mpd->boundary; p++) {
|
||||||
|
if (!isspace(*p)) {
|
||||||
|
if ((seen_semicolon == 0)&&(*p == ';')) {
|
||||||
|
seen_semicolon = 1; /* It is OK to have one semicolon. */
|
||||||
|
} else {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary in C-T (malformed).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Have we seen the semicolon in the header? */
|
||||||
|
if (seen_semicolon == 0) {
|
||||||
|
msr->mpd->flag_missing_semicolon = 1;
|
||||||
|
}
|
||||||
|
|
||||||
b = strchr(msr->mpd->boundary + 8, '=');
|
b = strchr(msr->mpd->boundary + 8, '=');
|
||||||
if (b == NULL) {
|
if (b == NULL) {
|
||||||
msr->mpd->flag_error = 1;
|
msr->mpd->flag_error = 1;
|
||||||
@@ -658,7 +683,11 @@ int multipart_init(modsec_rec *msr, char **error_msg) {
|
|||||||
|
|
||||||
/* Check parameter name ends well. */
|
/* Check parameter name ends well. */
|
||||||
if (b != (msr->mpd->boundary + 8)) {
|
if (b != (msr->mpd->boundary + 8)) {
|
||||||
if (isspace(*(msr->mpd->boundary + 8))) {
|
/* Check all characters between the end of the boundary
|
||||||
|
* and the = character.
|
||||||
|
*/
|
||||||
|
for (p = msr->mpd->boundary + 8; p < b; p++) {
|
||||||
|
if (isspace(*p)) {
|
||||||
/* Flag for whitespace after parameter name. */
|
/* Flag for whitespace after parameter name. */
|
||||||
msr->mpd->flag_boundary_whitespace = 1;
|
msr->mpd->flag_boundary_whitespace = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -667,6 +696,7 @@ int multipart_init(modsec_rec *msr, char **error_msg) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b++; /* Go over the = character. */
|
b++; /* Go over the = character. */
|
||||||
len = strlen(b);
|
len = strlen(b);
|
||||||
@@ -874,7 +904,7 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
|
|||||||
log_escape_nq(msr->mp, msr->mpd->buf));
|
log_escape_nq(msr->mp, msr->mpd->buf));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else { /* It looks like a boundary but we couldn't match it. */
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
|
|
||||||
/* Check if an attempt to use quotes around the boundary was made. */
|
/* Check if an attempt to use quotes around the boundary was made. */
|
||||||
@@ -905,6 +935,23 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
|
|||||||
|
|
||||||
msr->mpd->flag_unmatched_boundary = 1;
|
msr->mpd->flag_unmatched_boundary = 1;
|
||||||
}
|
}
|
||||||
|
} else { /* We do not think the buffer contains a boundary. */
|
||||||
|
/* Look into the buffer to see if there's anything
|
||||||
|
* there that resembles a boundary.
|
||||||
|
*/
|
||||||
|
if (msr->mpd->buf_contains_line) {
|
||||||
|
int i, len = (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||||
|
char *p = msr->mpd->buf;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++) {
|
||||||
|
if ((p[i] == '-')&&(i + 1 < len)&&(p[i + 1] == '-')) {
|
||||||
|
if (strncmp(p + i + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) {
|
||||||
|
msr->mpd->flag_unmatched_boundary = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process as data if it was not a boundary. */
|
/* Process as data if it was not a boundary. */
|
||||||
@@ -1069,7 +1116,7 @@ int multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *argument
|
|||||||
if (arg == NULL) return -1;
|
if (arg == NULL) return -1;
|
||||||
|
|
||||||
arg->name = parts[i]->name;
|
arg->name = parts[i]->name;
|
||||||
arg->name_len = strlen(parts[i]->name); // TODO
|
arg->name_len = strlen(parts[i]->name);
|
||||||
arg->value = parts[i]->value;
|
arg->value = parts[i]->value;
|
||||||
arg->value_len = parts[i]->length;
|
arg->value_len = parts[i]->length;
|
||||||
arg->value_origin_offset = parts[i]->offset;
|
arg->value_origin_offset = parts[i]->offset;
|
||||||
@@ -1094,8 +1141,6 @@ char *multipart_reconstruct_urlencoded_body_sanitise(modsec_rec *msr) {
|
|||||||
|
|
||||||
if (msr->mpd == NULL) return NULL;
|
if (msr->mpd == NULL) return NULL;
|
||||||
|
|
||||||
// TODO Cache this data somewhere in the structure
|
|
||||||
|
|
||||||
/* calculate the size of the buffer */
|
/* calculate the size of the buffer */
|
||||||
body_len = 1;
|
body_len = 1;
|
||||||
parts = (multipart_part **)msr->mpd->parts->elts;
|
parts = (multipart_part **)msr->mpd->parts->elts;
|
||||||
|
@@ -108,6 +108,7 @@ struct multipart_data {
|
|||||||
int flag_crlf_line;
|
int flag_crlf_line;
|
||||||
int flag_unmatched_boundary;
|
int flag_unmatched_boundary;
|
||||||
int flag_boundary_whitespace;
|
int flag_boundary_whitespace;
|
||||||
|
int flag_missing_semicolon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1324,6 +1324,18 @@ static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MULTIPART_MISSING_SEMICOLON */
|
||||||
|
|
||||||
|
static int var_multipart_missing_semicolon_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_missing_semicolon != 0)) {
|
||||||
|
return var_simple_generate(var, vartab, mptmp, "1");
|
||||||
|
} else {
|
||||||
|
return var_simple_generate(var, vartab, mptmp, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* MULTIPART_STRICT_ERROR */
|
/* MULTIPART_STRICT_ERROR */
|
||||||
|
|
||||||
static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
||||||
@@ -1338,6 +1350,7 @@ static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, m
|
|||||||
||(msr->mpd->flag_data_after != 0)
|
||(msr->mpd->flag_data_after != 0)
|
||||||
||(msr->mpd->flag_header_folding != 0)
|
||(msr->mpd->flag_header_folding != 0)
|
||||||
||(msr->mpd->flag_lf_line != 0)
|
||(msr->mpd->flag_lf_line != 0)
|
||||||
|
||(msr->mpd->flag_missing_semicolon != 0)
|
||||||
) {
|
) {
|
||||||
return var_simple_generate(var, vartab, mptmp, "1");
|
return var_simple_generate(var, vartab, mptmp, "1");
|
||||||
}
|
}
|
||||||
@@ -2378,6 +2391,17 @@ void msre_engine_register_default_variables(msre_engine *engine) {
|
|||||||
PHASE_REQUEST_BODY
|
PHASE_REQUEST_BODY
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* MULTIPART_MISSING_SEMICOLON */
|
||||||
|
msre_engine_variable_register(engine,
|
||||||
|
"MULTIPART_MISSING_SEMICOLON",
|
||||||
|
VAR_SIMPLE,
|
||||||
|
0, 0,
|
||||||
|
NULL,
|
||||||
|
var_multipart_missing_semicolon_generate,
|
||||||
|
VAR_CACHE,
|
||||||
|
PHASE_REQUEST_BODY
|
||||||
|
);
|
||||||
|
|
||||||
/* MULTIPART_STRICT_ERROR */
|
/* MULTIPART_STRICT_ERROR */
|
||||||
msre_engine_variable_register(engine,
|
msre_engine_variable_register(engine,
|
||||||
"MULTIPART_STRICT_ERROR",
|
"MULTIPART_STRICT_ERROR",
|
||||||
|
Reference in New Issue
Block a user