mirror of
https://github.com/openappsec/openappsec.git
synced 2025-10-01 12:07:43 +03:00
First release of open-appsec source code
This commit is contained in:
278
components/security_apps/waap/waap_clib/Signatures.cc
Executable file
278
components/security_apps/waap/waap_clib/Signatures.cc
Executable file
@@ -0,0 +1,278 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "Signatures.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "waap.h"
|
||||
#include <fstream>
|
||||
|
||||
USE_DEBUG_FLAG(D_WAAP);
|
||||
|
||||
typedef picojson::value::object JsObj;
|
||||
typedef picojson::value JsVal;
|
||||
typedef picojson::value::array JsArr;
|
||||
typedef std::map<std::string, std::vector<std::string>> filtered_parameters_t;
|
||||
|
||||
|
||||
static std::vector<std::string> to_strvec(const picojson::value::array& jsV)
|
||||
{
|
||||
std::vector<std::string> r;
|
||||
|
||||
for (auto it = jsV.begin(); it != jsV.end(); ++it) {
|
||||
r.push_back(it->get<std::string>());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static std::set<std::string> to_strset(const picojson::value::array& jsA)
|
||||
{
|
||||
std::set<std::string> r;
|
||||
|
||||
for (auto it = jsA.begin(); it != jsA.end(); ++it) {
|
||||
r.insert(it->get<std::string>());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static std::map<std::string, Regex*> to_regexmap(const picojson::value::object& jsO, bool& error)
|
||||
{
|
||||
std::map<std::string, Regex*> r;
|
||||
|
||||
for (auto it = jsO.begin(); it != jsO.end(); ++it) {
|
||||
const std::string& n = it->first;
|
||||
// convert name to lowercase now (so we don't need to do it at runtime every time).
|
||||
std::string n_lower;
|
||||
for (std::string::const_iterator pCh = n.begin(); pCh != n.end(); ++pCh) {
|
||||
n_lower += std::tolower(*pCh);
|
||||
}
|
||||
const picojson::value& v = it->second;
|
||||
|
||||
if (error) {
|
||||
// stop loading regexes if there's previous error...
|
||||
break;
|
||||
}
|
||||
|
||||
// Pointers to Regex instances are stored instead of instances themselves to avoid
|
||||
// the need to make the Regex objects copyable.
|
||||
// However, these pointers must be freed by the holder of the returned map!
|
||||
// note: in our case this freeing is happening in the destructor of the WaapAssetState class.
|
||||
r[n] = new Regex(v.get<std::string>(), error, n_lower);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static filtered_parameters_t to_filtermap(const picojson::value::object& JsObj)
|
||||
{
|
||||
filtered_parameters_t result;
|
||||
for (auto it = JsObj.begin(); it != JsObj.end(); ++it)
|
||||
{
|
||||
const std::string parameter = it->first;
|
||||
const picojson::value::array& arr = it->second.get<picojson::value::array>();
|
||||
result[parameter] = to_strvec(arr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string genDelimitedKeyValPattern(const std::string& delim)
|
||||
{
|
||||
std::string pattern = "^([^" + delim + "]+?=[^" + delim + "]+?" + delim + ")+"
|
||||
"([^" + delim + "]+?=[^" + delim + "]+?)" + delim + "?$";
|
||||
return pattern;
|
||||
}
|
||||
|
||||
Signatures::Signatures(const std::string& filepath) :
|
||||
sigsSource(loadSource(filepath)),
|
||||
error(false),
|
||||
m_regexPreconditions(std::make_shared<Waap::RegexPreconditions>(sigsSource, error)),
|
||||
words_regex(
|
||||
to_strvec(sigsSource["words_regex_list"].get<picojson::value::array>()),
|
||||
error,
|
||||
"words_regex_list",
|
||||
m_regexPreconditions
|
||||
),
|
||||
specific_acuracy_keywords_regex(
|
||||
to_strvec(sigsSource["specific_acuracy_keywords_regex_list"].get<picojson::value::array>()),
|
||||
error,
|
||||
"specific_acuracy_keywords_regex_list",
|
||||
m_regexPreconditions
|
||||
),
|
||||
pattern_regex(
|
||||
to_strvec(sigsSource["pattern_regex_list"].get<picojson::value::array>()),
|
||||
error,
|
||||
"pattern_regex_list",
|
||||
m_regexPreconditions
|
||||
),
|
||||
un_escape_pattern(sigsSource["un_escape_pattern"].get<std::string>(), error, "un_escape_pattern"),
|
||||
quotes_ev_pattern(sigsSource["quotes_ev_pattern"].get<std::string>(), error, "quotes_ev_pattern"),
|
||||
comment_ev_pattern(sigsSource["comment_ev_pattern"].get<std::string>(), error, "comment_ev_pattern"),
|
||||
quotes_space_ev_pattern(
|
||||
sigsSource["quotes_space_ev_fast_reg"].get<std::string>(), error,
|
||||
"quotes_space_ev_fast_reg"
|
||||
),
|
||||
allowed_text_re(sigsSource["allowed_text_re"].get<std::string>(), error, "allowed_text_re"),
|
||||
pipe_split_re(
|
||||
"([\\w\\=\\-\\_\\.\\,\\(\\)\\[\\]\\/\\%\\s]+?)\\||([\\w\\=\\-\\_\\.\\,\\(\\)\\[\\]\\/\\%\\s]+)|\\|()",
|
||||
error,
|
||||
"pipe_decode"),
|
||||
semicolon_split_re("([\\w\\=\\-\\_\\.\\,\\(\\)\\%]+?);|([\\w\\=\\-\\_\\.\\,\\(\\)\\%]+)|;()", error, "sem_decode"),
|
||||
longtext_re(sigsSource["longtext_re"].get<std::string>(), error, "longtext_re"),
|
||||
nospaces_long_value_re("^[^\\s]{16,}$", error, "nospaces_long_value_re"),
|
||||
good_header_name_re(sigsSource["good_header_name_re"].get<std::string>(), error, "good_header_name"),
|
||||
good_header_value_re(sigsSource["good_header_value_re"].get<std::string>(), error, "good_header_value"),
|
||||
ignored_for_nospace_long_value(
|
||||
to_strset(sigsSource["ignored_for_nospace_long_value"].get<picojson::value::array>())),
|
||||
global_ignored_keywords(
|
||||
to_strset(
|
||||
sigsSource["global_ignored"].get<picojson::value::object>()["keys"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
global_ignored_patterns(
|
||||
to_strset(
|
||||
sigsSource["global_ignored"].get<picojson::value::object>()["patterns"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
url_ignored_keywords(
|
||||
to_strset(
|
||||
sigsSource["ignored_for_url"].get<picojson::value::object>()["keys"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
url_ignored_patterns(
|
||||
to_strset(
|
||||
sigsSource["ignored_for_url"].get<picojson::value::object>()["patterns"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
url_ignored_re(
|
||||
sigsSource["ignored_for_url"].get<picojson::value::object>()["regex"].get<std::string>(),
|
||||
error,
|
||||
"url_ignored"
|
||||
),
|
||||
header_ignored_keywords(
|
||||
to_strset(
|
||||
sigsSource["ignored_for_headers"].get<picojson::value::object>()["keys"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
header_ignored_patterns(
|
||||
to_strset(
|
||||
sigsSource["ignored_for_headers"].get<picojson::value::object>()
|
||||
["patterns"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
header_ignored_re(
|
||||
sigsSource["ignored_for_headers"].get<picojson::value::object>()["regex"].get<std::string>(),
|
||||
error,
|
||||
"header_ignored"
|
||||
),
|
||||
filter_parameters(
|
||||
to_filtermap(
|
||||
sigsSource["filter_parameters"].get<picojson::object>()
|
||||
)
|
||||
),
|
||||
m_attack_types(
|
||||
to_filtermap(
|
||||
sigsSource["attack_types_map"].get<picojson::object>()
|
||||
)
|
||||
),
|
||||
// Removed by Pavel's request. Leaving here in case he'll want to add this back...
|
||||
#if 0
|
||||
cookie_ignored_keywords(
|
||||
to_strset(
|
||||
sigsSource["ignored_for_cookies"].get<picojson::value::object>()["keys"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
cookie_ignored_patterns(
|
||||
to_strset(
|
||||
sigsSource["ignored_for_cookies"].get<picojson::value::object>()
|
||||
["patterns"].get<picojson::value::array>()
|
||||
)
|
||||
),
|
||||
cookie_ignored_re(
|
||||
sigsSource["ignored_for_cookies"].get<picojson::value::object>()["regex"].get<std::string>(),
|
||||
error,
|
||||
"cookie_ignored"
|
||||
),
|
||||
#endif
|
||||
php_serialize_identifier("^(N;)|^([ibdsOoCcRra]:\\d+)", error, "php_serialize_identifier"),
|
||||
html_regex("(<(?>body|head)\\b.*>(?>.|[\\r\\n]){0,400}){2}|<html", error, "htmlRegex"),
|
||||
uri_parser_regex("(http|https)://([^/ :]+):?([^/ ]*)(/?[^ #?]*)", error, "uriParserRegex"),
|
||||
confluence_macro_re("{[^\"]+:(?>.+\\|)+.+}"),
|
||||
pipes_delimited_key_val_re(genDelimitedKeyValPattern("\\|")),
|
||||
semicolon_delimited_key_val_re(genDelimitedKeyValPattern(";")),
|
||||
asterisk_delimited_key_val_re(genDelimitedKeyValPattern("\\*")),
|
||||
comma_delimited_key_val_re(genDelimitedKeyValPattern(",")),
|
||||
ampersand_delimited_key_val_re(genDelimitedKeyValPattern("&")),
|
||||
headers_re(to_regexmap(sigsSource["headers_re"].get<JsObj>(), error)),
|
||||
format_magic_binary_re(sigsSource["format_magic_binary_re"].get<std::string>(), error, "format_magic_binary_re"),
|
||||
params_type_re(to_regexmap(sigsSource["format_types_regex_list"].get<JsObj>(), error)),
|
||||
resp_hdr_pattern_regex_list(to_strvec(sigsSource["resp_hdr_pattern_regex_list"].get<JsArr>()),
|
||||
error, "resp_hdr_pattern_regex_list", nullptr),
|
||||
resp_hdr_words_regex_list(to_strvec(sigsSource["resp_hdr_words_regex_list"].get<JsArr>()),
|
||||
error, "resp_hdr_words_regex_list", nullptr),
|
||||
resp_body_pattern_regex_list(to_strvec(sigsSource["resp_body_pattern_regex_list"].get<JsArr>()),
|
||||
error, "resp_body_pattern_regex_list", nullptr),
|
||||
resp_body_words_regex_list(to_strvec(sigsSource["resp_body_words_regex_list"].get<JsArr>()),
|
||||
error, "resp_body_words_regex_list", nullptr),
|
||||
remove_keywords_always(
|
||||
to_strset(sigsSource["remove_keywords_always"].get<JsArr>())),
|
||||
user_agent_prefix_re(sigsSource["user_agent_prefix_re"].get<std::string>()),
|
||||
binary_data_kw_filter(sigsSource["binary_data_kw_filter"].get<std::string>()),
|
||||
wbxml_data_kw_filter(sigsSource["wbxml_data_kw_filter"].get<std::string>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Signatures::~Signatures()
|
||||
{
|
||||
}
|
||||
|
||||
bool Signatures::fail()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
picojson::value::object Signatures::loadSource(const std::string& sigsFname)
|
||||
{
|
||||
picojson::value doc;
|
||||
std::ifstream f(sigsFname.c_str());
|
||||
|
||||
if (f.fail()) {
|
||||
dbgError(D_WAAP) << "Failed to open json data file '" << sigsFname << "'!";
|
||||
error = true; // flag an error
|
||||
return picojson::value::object();
|
||||
}
|
||||
|
||||
int length;
|
||||
f.seekg(0, std::ios::end); // go to the end
|
||||
length = f.tellg(); // report location (this is the length)
|
||||
char* buffer = new char[length]; // allocate memory for a buffer of appropriate dimension
|
||||
f.seekg(0, std::ios::beg); // go back to the beginning
|
||||
f.read(buffer, length); // read the whole file into the buffer
|
||||
f.close();
|
||||
|
||||
std::string dataObfuscated(buffer, length);
|
||||
|
||||
delete[] buffer;
|
||||
std::stringstream ss(dataObfuscated);
|
||||
ss >> doc;
|
||||
|
||||
if (!picojson::get_last_error().empty()) {
|
||||
dbgError(D_WAAP) << "WaapAssetState::loadSource('" << sigsFname << "') failed (parse error: '" <<
|
||||
picojson::get_last_error() << "').";
|
||||
error = true; // flag an error
|
||||
return picojson::value::object();
|
||||
}
|
||||
|
||||
return doc.get<picojson::value::object>();
|
||||
}
|
Reference in New Issue
Block a user