mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-30 03:34:29 +03:00
Adds offset regression tests and assorted fixes on var's offsets
This commit is contained in:
committed by
Felipe Zimmerle
parent
795994bb0e
commit
4ad3574cf2
@@ -13,6 +13,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
#define SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
|
||||
|
||||
#ifdef WITH_YAJL
|
||||
|
||||
@@ -24,8 +27,6 @@
|
||||
#include "modsecurity/transaction.h"
|
||||
#include "modsecurity/rules.h"
|
||||
|
||||
#ifndef SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
#define SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
|
||||
|
||||
namespace modsecurity {
|
||||
@@ -82,7 +83,6 @@ class JSON {
|
||||
} // namespace RequestBodyProcessor
|
||||
} // namespace modsecurity
|
||||
|
||||
#endif // WITH_YAJL
|
||||
|
||||
#endif // SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
|
||||
#endif // WITH_YAJL
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "modsecurity/collection/collections.h"
|
||||
#include "modsecurity/rules.h"
|
||||
@@ -212,7 +213,7 @@ void Multipart::validate_quotes(const char *data) {
|
||||
}
|
||||
|
||||
|
||||
int Multipart::parse_content_disposition(const char *c_d_value) {
|
||||
int Multipart::parse_content_disposition(const char *c_d_value, int offset) {
|
||||
const char *p = NULL;
|
||||
|
||||
/* accept only what we understand */
|
||||
@@ -342,7 +343,8 @@ int Multipart::parse_content_disposition(const char *c_d_value) {
|
||||
if (name == "name") {
|
||||
validate_quotes(value.c_str());
|
||||
|
||||
m_transaction->m_variableMultiPartName.set(value, value, 0);
|
||||
m_transaction->m_variableMultiPartName.set(value, value,
|
||||
offset + ((p - c_d_value) - value.size()));
|
||||
|
||||
if (!m_mpp->m_name.empty()) {
|
||||
debug(4, "Multipart: Warning: Duplicate Content-Disposition " \
|
||||
@@ -350,10 +352,12 @@ int Multipart::parse_content_disposition(const char *c_d_value) {
|
||||
return -14;
|
||||
}
|
||||
m_mpp->m_name.assign(value);
|
||||
m_mpp->m_nameOffset = offset + ((p - c_d_value) - value.size());
|
||||
debug(9, "Multipart: Content-Disposition name: " + value + ".");
|
||||
} else if (name == "filename") {
|
||||
validate_quotes(value.c_str());
|
||||
m_transaction->m_variableMultiPartFileName.set(value, value, 0);
|
||||
m_transaction->m_variableMultiPartFileName.set(value, value, \
|
||||
offset + ((p - c_d_value) - value.size()));
|
||||
|
||||
if (!m_mpp->m_filename.empty()) {
|
||||
debug(4, "Multipart: Warning: Duplicate Content-Disposition " \
|
||||
@@ -361,6 +365,7 @@ int Multipart::parse_content_disposition(const char *c_d_value) {
|
||||
return -15;
|
||||
}
|
||||
m_mpp->m_filename.assign(value);
|
||||
m_mpp->m_filenameOffset = offset + ((p - c_d_value) - value.size());
|
||||
|
||||
debug(9, "Multipart: Content-Disposition filename: " \
|
||||
+ value + ".");
|
||||
@@ -432,7 +437,7 @@ int Multipart::tmp_file_name(std::string *filename) const {
|
||||
}
|
||||
|
||||
|
||||
int Multipart::process_part_data(std::string *error) {
|
||||
int Multipart::process_part_data(std::string *error, size_t offset) {
|
||||
char *p = m_buf + (MULTIPART_BUF_SIZE - m_bufleft);
|
||||
char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */
|
||||
int bytes_reserved = 0;
|
||||
@@ -525,7 +530,11 @@ int Multipart::process_part_data(std::string *error) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_mpp->m_tmp_file_size += m_reserve[0];
|
||||
m_mpp->m_tmp_file_size.first += m_reserve[0];
|
||||
if (m_mpp->m_tmp_file_size.second == 0) {
|
||||
m_mpp->m_tmp_file_size.second = offset \
|
||||
- m_mpp->m_tmp_file_size.first;
|
||||
}
|
||||
m_mpp->m_length += m_reserve[0];
|
||||
}
|
||||
|
||||
@@ -541,12 +550,26 @@ int Multipart::process_part_data(std::string *error) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_mpp->m_tmp_file_size += (MULTIPART_BUF_SIZE - m_bufleft);
|
||||
m_mpp->m_value.append(std::string(m_buf,
|
||||
MULTIPART_BUF_SIZE - m_bufleft));
|
||||
m_mpp->m_valueOffset = offset - (MULTIPART_BUF_SIZE - m_bufleft);
|
||||
|
||||
m_mpp->m_tmp_file_size.first += (MULTIPART_BUF_SIZE - m_bufleft);
|
||||
if (m_mpp->m_tmp_file_size.second == 0) {
|
||||
m_mpp->m_tmp_file_size.second = offset \
|
||||
- m_mpp->m_tmp_file_size.first;
|
||||
}
|
||||
|
||||
m_mpp->m_length += (MULTIPART_BUF_SIZE - m_bufleft);
|
||||
} else {
|
||||
/* just keep track of the file size */
|
||||
m_mpp->m_tmp_file_size += (MULTIPART_BUF_SIZE - m_bufleft) \
|
||||
m_mpp->m_tmp_file_size.first += (MULTIPART_BUF_SIZE - m_bufleft) \
|
||||
+ m_reserve[0];
|
||||
if (m_mpp->m_tmp_file_size.second == 0) {
|
||||
m_mpp->m_tmp_file_size.second = offset \
|
||||
- m_mpp->m_tmp_file_size.first;
|
||||
}
|
||||
|
||||
m_mpp->m_length += (MULTIPART_BUF_SIZE - m_bufleft) + m_reserve[0];
|
||||
}
|
||||
} else if (m_mpp->m_type == MULTIPART_FORMDATA) {
|
||||
@@ -573,7 +596,7 @@ int Multipart::process_part_data(std::string *error) {
|
||||
m_mpp->m_length += d.size();
|
||||
}
|
||||
|
||||
m_mpp->m_value_parts.push_back(d);
|
||||
m_mpp->m_value_parts.push_back(std::make_pair(d, m_buf_offset));
|
||||
|
||||
debug(9, "Multipart: Added data to variable: " + d);
|
||||
} else {
|
||||
@@ -601,7 +624,7 @@ int Multipart::process_part_data(std::string *error) {
|
||||
}
|
||||
|
||||
|
||||
int Multipart::process_part_header(std::string *error) {
|
||||
int Multipart::process_part_header(std::string *error, int offset) {
|
||||
int i, len;
|
||||
|
||||
/* Check for nul bytes. */
|
||||
@@ -614,6 +637,7 @@ int Multipart::process_part_header(std::string *error) {
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
/* The buffer is data so increase the data length counter. */
|
||||
m_reqbody_no_files_length += (MULTIPART_BUF_SIZE - m_bufleft);
|
||||
|
||||
@@ -639,9 +663,10 @@ int Multipart::process_part_header(std::string *error) {
|
||||
"Content-Disposition header.");
|
||||
return false;
|
||||
}
|
||||
header_value = m_mpp->m_headers.at("Content-Disposition");
|
||||
header_value = m_mpp->m_headers.at("Content-Disposition").second;
|
||||
|
||||
rc = parse_content_disposition(header_value.c_str());
|
||||
rc = parse_content_disposition(header_value.c_str(),
|
||||
m_mpp->m_headers.at("Content-Disposition").first);
|
||||
if (rc < 0) {
|
||||
debug(1, "Multipart: Invalid Content-Disposition header ("
|
||||
+ std::to_string(rc) + "): " + header_value);
|
||||
@@ -714,15 +739,17 @@ int Multipart::process_part_header(std::string *error) {
|
||||
m_flag_invalid_header_folding = 1;
|
||||
}
|
||||
data++;
|
||||
i++;
|
||||
}
|
||||
|
||||
new_value = std::string(data);
|
||||
utils::string::chomp(&new_value);
|
||||
|
||||
/* update the header value in the table */
|
||||
header_value = m_mpp->m_headers.at(m_mpp->m_last_header_name);
|
||||
header_value = m_mpp->m_headers.at(
|
||||
m_mpp->m_last_header_name).second;
|
||||
new_value = header_value + " " + new_value;
|
||||
m_mpp->m_headers.at(m_mpp->m_last_header_name) = new_value;
|
||||
m_mpp->m_headers.at(m_mpp->m_last_header_name).second = new_value;
|
||||
|
||||
debug(9, "Multipart: Continued folder header \"" \
|
||||
+ m_mpp->m_last_header_name + "\" with \"" \
|
||||
@@ -742,6 +769,7 @@ int Multipart::process_part_header(std::string *error) {
|
||||
data = m_buf;
|
||||
while ((*data != ':') && (*data != '\0')) {
|
||||
data++;
|
||||
i++;
|
||||
}
|
||||
if (*data == '\0') {
|
||||
debug(1, "Multipart: Invalid part header (colon missing): " \
|
||||
@@ -763,8 +791,10 @@ int Multipart::process_part_header(std::string *error) {
|
||||
|
||||
/* extract the value value */
|
||||
data++;
|
||||
i++;
|
||||
while ((*data == '\t') || (*data == ' ')) {
|
||||
data++;
|
||||
i++;
|
||||
}
|
||||
header_value = std::string(data);
|
||||
utils::string::chomp(&header_value);
|
||||
@@ -780,7 +810,8 @@ int Multipart::process_part_header(std::string *error) {
|
||||
|
||||
|
||||
m_mpp->m_headers.emplace(
|
||||
std::string(header_name), std::string(header_value));
|
||||
std::string(header_name), std::make_pair(offset - len + i,
|
||||
std::string(header_value)));
|
||||
|
||||
|
||||
debug(9, "Multipart: Added part header \"" + header_name \
|
||||
@@ -805,8 +836,11 @@ int Multipart::process_boundary(int last_part) {
|
||||
|
||||
if (m_mpp->m_type != MULTIPART_FILE) {
|
||||
/* now construct a single string out of the parts */
|
||||
for (std::string &i : m_mpp->m_value_parts) {
|
||||
m_mpp->m_value.append(i);
|
||||
for (const auto &i : m_mpp->m_value_parts) {
|
||||
if (m_mpp->m_valueOffset == 0) {
|
||||
m_mpp->m_valueOffset = i.second;
|
||||
}
|
||||
m_mpp->m_value.append(i.first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -986,6 +1020,7 @@ int Multipart::multipart_complete(std::string *error) {
|
||||
if (m->m_name.empty()) {
|
||||
continue;
|
||||
}
|
||||
size_t offset = m_transaction->m_variableOffset + 1;
|
||||
|
||||
if (m->m_type == MULTIPART_FILE) {
|
||||
std::string tmp_name;
|
||||
@@ -996,25 +1031,36 @@ int Multipart::multipart_complete(std::string *error) {
|
||||
if (!m->m_filename.empty()) {
|
||||
name.assign(m->m_filename);
|
||||
}
|
||||
|
||||
m_transaction->m_variableFiles.set(m->m_filename,
|
||||
m->m_filename, 0);
|
||||
m_transaction->m_variableFilesNames.set(m->m_name,
|
||||
m->m_name, 0);
|
||||
m->m_filename, m->m_filenameOffset);
|
||||
|
||||
m_transaction->m_variableFilesNames.set(m->m_filename,
|
||||
m->m_filename, m->m_filenameOffset);
|
||||
|
||||
m_transaction->m_variableFilesSizes.set(m->m_name,
|
||||
std::to_string(m->m_tmp_file_size), 0);
|
||||
m_transaction->m_variableFilesTmpContent.set(m->m_name,
|
||||
m->m_value, 0);
|
||||
m_transaction->m_variableFilesTmpContent.set(m->m_name,
|
||||
m->m_value, 0);
|
||||
m_transaction->m_variableFilesTmpNames.set(m->m_name,
|
||||
m->m_value, 0);
|
||||
file_combined_size = file_combined_size + m->m_tmp_file_size;
|
||||
std::to_string(m->m_tmp_file_size.first),
|
||||
m->m_tmp_file_size.second,
|
||||
m->m_tmp_file_size.first);
|
||||
|
||||
m_transaction->m_variableFilesTmpContent.set(m->m_filename,
|
||||
m->m_value, m->m_valueOffset);
|
||||
|
||||
m_transaction->m_variableFilesTmpNames.set(m->m_filename,
|
||||
m->m_filename, m->m_filenameOffset);
|
||||
|
||||
file_combined_size = file_combined_size + m->m_tmp_file_size.first;
|
||||
|
||||
m_transaction->m_variableFilesCombinedSize.set(
|
||||
std::to_string(file_combined_size),
|
||||
m->m_tmp_file_size.second, m->m_tmp_file_size.first);
|
||||
} else {
|
||||
debug(4, "Adding request argument (BODY): name \"" +
|
||||
m->m_name + "\", value \"" + m->m_value + "\"");
|
||||
m_transaction->m_variableArgs.set(m->m_name, m->m_value,
|
||||
m_transaction->m_variableOffset);
|
||||
m_transaction->m_variableArgsPost.set(m->m_name, m->m_value, 0);
|
||||
offset + m->m_valueOffset);
|
||||
m_transaction->m_variableArgsPost.set(m->m_name, m->m_value,
|
||||
offset + m->m_valueOffset);
|
||||
}
|
||||
#if 0
|
||||
if (m_transaction->m_namesArgs->empty()) {
|
||||
@@ -1036,9 +1082,7 @@ int Multipart::multipart_complete(std::string *error) {
|
||||
std::to_string(m_transaction->->m_ARGScombinedSize));
|
||||
#endif
|
||||
}
|
||||
m_transaction->m_variableFilesCombinedSize.set(
|
||||
std::to_string(file_combined_size),
|
||||
m_transaction->m_variableOffset);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1256,12 +1300,13 @@ bool Multipart::init(std::string *error) {
|
||||
* Assuming that all data is on data. We are not processing chunks.
|
||||
*
|
||||
*/
|
||||
bool Multipart::process(const std::string& data, std::string *error) {
|
||||
bool Multipart::process(const std::string& data, std::string *error,
|
||||
int offset) {
|
||||
const char *inptr = data.c_str();
|
||||
unsigned int inleft = data.size();
|
||||
size_t z = 0;
|
||||
|
||||
if (data.size() == 0) return true;
|
||||
|
||||
m_seen_data = true;
|
||||
|
||||
if (m_is_complete) {
|
||||
@@ -1285,6 +1330,8 @@ bool Multipart::process(const std::string& data, std::string *error) {
|
||||
char c = *inptr;
|
||||
int process_buffer = 0;
|
||||
|
||||
z++;
|
||||
|
||||
if ((c == '\r') && (m_bufleft == 1)) {
|
||||
/* we don't want to take \r as the last byte in the buffer */
|
||||
process_buffer = 1;
|
||||
@@ -1443,13 +1490,13 @@ bool Multipart::process(const std::string& data, std::string *error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process_part_header(error) < 0) {
|
||||
if (process_part_header(error, offset + z) < 0) {
|
||||
m_flag_error = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (process_part_data(error) < 0) {
|
||||
if (process_part_data(error, offset + z) < 0) {
|
||||
m_flag_error = 1;
|
||||
return false;
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#ifndef SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
|
||||
#define SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
|
||||
@@ -58,9 +59,14 @@ class MultipartPart {
|
||||
MultipartPart()
|
||||
: m_type(MULTIPART_FORMDATA),
|
||||
m_tmp_file_fd(0),
|
||||
m_tmp_file_size(0),
|
||||
m_offset(0),
|
||||
m_length(0) { }
|
||||
m_filenameOffset(0),
|
||||
m_nameOffset(0),
|
||||
m_valueOffset(0),
|
||||
m_length(0) {
|
||||
m_tmp_file_size.first = 0;
|
||||
m_tmp_file_size.second = 0;
|
||||
}
|
||||
|
||||
~MultipartPart() {
|
||||
m_headers.clear();
|
||||
@@ -72,10 +78,13 @@ class MultipartPart {
|
||||
|
||||
/* the name */
|
||||
std::string m_name;
|
||||
size_t m_nameOffset;
|
||||
|
||||
/* variables only, variable value */
|
||||
std::string m_value;
|
||||
std::list<std::string> m_value_parts;
|
||||
size_t m_valueOffset;
|
||||
|
||||
std::list<std::pair<std::string, int>> m_value_parts;
|
||||
|
||||
/* files only, the content type (where available) */
|
||||
/* std::string m_content_type; */
|
||||
@@ -83,13 +92,15 @@ class MultipartPart {
|
||||
/* files only, the name of the temporary file holding data */
|
||||
std::string m_tmp_file_name;
|
||||
int m_tmp_file_fd;
|
||||
unsigned int m_tmp_file_size;
|
||||
std::pair<size_t, size_t> m_tmp_file_size;
|
||||
|
||||
/* files only, filename as supplied by the browser */
|
||||
std::string m_filename;
|
||||
size_t m_filenameOffset;
|
||||
|
||||
std::string m_last_header_name;
|
||||
std::unordered_map<std::string, std::string, MyHash, MyEqual> m_headers;
|
||||
std::unordered_map<std::string, std::pair<size_t, std::string>,
|
||||
MyHash, MyEqual> m_headers;
|
||||
|
||||
unsigned int m_offset;
|
||||
unsigned int m_length;
|
||||
@@ -108,11 +119,11 @@ class Multipart {
|
||||
int is_token_char(unsigned char c);
|
||||
int multipart_complete(std::string *err);
|
||||
|
||||
int parse_content_disposition(const char *c_d_value);
|
||||
bool process(const std::string& data, std::string *err);
|
||||
int parse_content_disposition(const char *c_d_value, int offset);
|
||||
bool process(const std::string& data, std::string *err, int offset);
|
||||
int process_boundary(int last_part);
|
||||
int process_part_header(std::string *error);
|
||||
int process_part_data(std::string *error);
|
||||
int process_part_header(std::string *error, int offset);
|
||||
int process_part_data(std::string *error, size_t offset);
|
||||
|
||||
int tmp_file_name(std::string *filename) const;
|
||||
|
||||
|
Reference in New Issue
Block a user