Compare commits

...

107 Commits

Author SHA1 Message Date
Ervin Hegedus
a07ed61e74
Merge pull request #3432 from szedenik-adam/auditlog-header
Add custom leading text to audit log lines
2025-08-13 20:45:19 +03:00
szedenik-adam
4e2788eb47 Merge branch 'v3/master' into auditlog-header 2025-08-13 09:26:21 +02:00
Ervin Hegedus
f9f4011a4b
Merge pull request #3434 from airween/v3/cppcheckfix2
chore: fix cppcheck warning
2025-08-13 10:04:20 +03:00
Ervin Hegedus
62cb73f31d
Add const modifier to variable 2025-08-12 21:36:52 +02:00
Ervin Hegedus
8b3269f4d1
Try to avoid any kind of type casting 2025-08-12 21:05:31 +02:00
Ervin Hegedus
e879711d87
Add extra SonarCloud supression msg; Change type to auto 2025-08-11 23:05:32 +02:00
Ervin Hegedus
9fea1ca454
Change cast type (fix SonarCloud issues) 2025-08-11 22:41:07 +02:00
Ervin Hegedus
47bc24a808
Decrease code nest level 2025-08-11 22:28:22 +02:00
Ervin Hegedus
12809656a6
Remove redundant parenthesis 2025-08-11 22:02:37 +02:00
Ervin Hegedus
ea51a663f1
Move seclang-parser.hh supression to the right place 2025-08-11 17:19:46 +02:00
Ervin Hegedus
d19d3b4785
Supress uninitMemberVar warning in seclang-parser.hh 2025-08-11 16:43:58 +02:00
Ervin Hegedus
67f32a4e63
Fix cppcheck 2.18.0 warnings 2025-08-11 15:51:49 +02:00
szedenik-adam
6c6d94fc66 Renamed SecAuditLogHeader to SecAuditLogPrefix 2025-08-11 10:30:01 +02:00
szedenik-adam
0f402f33fd Adapted AuditLog based on code check hints 2025-08-07 11:01:44 +02:00
szedenik-adam
01c427f6be Replaced initializer list with in-class initializer in AuditLog 2025-08-07 10:23:50 +02:00
szedenik-adam
31fb9390c2 Replaced string parameters with string_view in AuditLog 2025-08-07 10:22:42 +02:00
szedenik-adam
2ee45de2fc Added audit log header 2025-08-04 17:09:49 +02:00
Ervin Hegedus
0ac551b070
Merge pull request #3430 from airween/v3/confvaluepathfix
fix: add Windows specific characters to config value syntax
2025-08-03 11:06:00 +03:00
Ervin Hegedus
013c8c2c7b
Remove escape from meta characters again 2025-08-01 13:28:19 +02:00
Ervin Hegedus
d8574c8c08
Fix date format pattern in auditlog's regression test 2025-08-01 11:38:39 +02:00
Ervin Hegedus
37948704df
Revert "Remove escape from meta characters"
This reverts commit 28bc3a98df54e251861d26dbb9f1374f622b97ea.
2025-08-01 09:33:22 +02:00
Ervin Hegedus
28bc3a98df
Remove escape from meta characters
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-08-01 09:11:20 +02:00
Ervin Hegedus
72e3abdd12
Add Windows specific characters to config value syntax in config parser 2025-07-30 14:37:27 +02:00
Ervin Hegedus
f2170d8576
Merge pull request #3426 from wooffie/fix-rx-476
fix: rx operators better null checks
2025-07-29 15:48:47 +03:00
Burkov Egor
c60709a58c fix: rx operators better null checks 2025-07-29 13:18:48 +03:00
Ervin Hegedus
1ff9f2a943
Merge pull request #3421 from airween/v3/secreqbodylimit
fix: integer type limits, 2nd try
2025-07-28 22:44:47 +03:00
Ervin Hegedus
690355b297
Merge pull request #3424 from wooffie/patch-1
fix: confusing indentation at acmp.cc
2025-07-28 19:07:27 +03:00
Burkov Egor
78b9cb7b57 Add more brackets 2025-07-28 15:11:02 +03:00
Burkov Egor
5d05ba359c
fix: confusing indentation at acmp.cc 2025-07-28 14:23:11 +03:00
Ervin Hegedus
9fb75d2c9a
Reformat code block with brackets
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-07-28 10:38:01 +02:00
Ervin Hegedus
abed778b4a
Remove unused ConfigDouble class 2025-07-27 17:28:26 +02:00
Ervin Hegedus
8d15991fb4
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-07-27 17:14:12 +02:00
Ervin Hegedus
b8a22bb67a
Update error message
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-07-27 17:09:11 +02:00
Ervin Hegedus
7e3c807c0d
Change syntax: add brackets to condition block 2025-07-27 17:07:12 +02:00
Ervin Hegedus
bb70ff06a4
Refactoring the cleaning of MATCHED_VAR* variables 2025-07-27 17:07:12 +02:00
Ervin Hegedus
08b70e006b
Merge pull request #3422 from airween/v3/matchedvarsfix2
Refactoring the cleaning of MATCHED_VAR* variables
2025-07-27 18:00:45 +03:00
Ervin Hegedus
79d55037c0
Refactoring the cleaning of MATCHED_VAR* variables 2025-07-25 14:33:24 +02:00
Ervin Hegedus
9a8ce8b5f5
Refactoring Config*Int types 2025-07-24 19:21:15 +02:00
Ervin Hegedus
cf24aeaead
Merge pull request #3405 from airween/v3/pmfromffix
fix: @pmFromFile with multiple files issue
2025-06-20 09:29:36 +02:00
Ervin Hegedus
6089b6b06b
Fix @pmFromFile with multiple files issue 2025-06-19 21:49:05 +02:00
Ervin Hegedus
31507404e6
Merge pull request #3392 from amezin/macaddr-resource-leak
Fix memory/socket leak in `UniqueId::ethernetMacAddress()`
2025-06-07 13:23:46 +02:00
Ervin Hegedus
f64ea2a708
Merge pull request #3390 from arvedarved/buildsystem-fixes
Buildsystem fixes
2025-06-07 09:06:04 +02:00
Ervin Hegedus
1362479d34
Merge pull request #3393 from JakubOnderka/json-log-hostname
Add hostname to JSON log
2025-05-28 22:55:57 +02:00
Jakub Onderka
8d3b2cacc4 Add hostname to JSON log 2025-05-28 16:24:09 +02:00
Aleksandr Mezin
a17193f7af Fix memory/socket leak in UniqueId::ethernetMacAddress()
Don't jump over `close()`/`free()`
2025-05-27 12:42:36 +03:00
Tilman Keskinöz
de624f9460
Attempt to fix bogus change.
Reported by: CI via Ervin Hegedus
2025-05-23 10:28:38 +02:00
Tilman Keskinöz
7660125da6
buildfix for srcdir != builddir
automake doesn't support wildcards.
See https://www.gnu.org/software/automake/manual/html_node/Wildcards.html
for details.

Use the GNU make $(wildcard ) extension.

Note: this breaks with non-GNU make
2025-05-22 18:59:56 +02:00
Tilman Keskinöz
0caf30679f
buildfix
If libxml2 is in a non-default directory, it needs to be added
to LDFLAGS
2025-05-22 18:59:55 +02:00
Tilman Keskinöz
0bcabf3208
buildfix for srcdir != builddir 2025-05-22 18:59:51 +02:00
Ervin Hegedus
aab47091b1
Merge pull request #3364 from JakubOnderka/json-logging
Simplify code for JSON audit log
2025-05-11 10:54:47 +02:00
Ervin Hegedus
990d99b1fb
Merge pull request #3365 from JakubOnderka/disable-expect
Disable Expect when sending audit logs to remote HTTP server
2025-05-11 10:50:10 +02:00
Ervin Hegedus
220caa5abc
Merge pull request #3363 from airween/v3/xmlargsfeat
feat: improved XMLArgs processing
2025-05-04 19:46:18 +02:00
Ervin Hegedus
a3876e3c99
Avoid unvanted content parse (whitespaces between tags) 2025-05-02 22:34:03 +02:00
Ervin Hegedus
d228ea6607
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-05-01 22:28:27 +02:00
Ervin Hegedus
89442ede16
Change directives in tests; add multibyte test case 2025-04-28 22:35:22 +02:00
Ervin Hegedus
e8dc60ee06
Change node value's parsing to concatenate instead of copy it every time 2025-04-28 22:34:26 +02:00
Ervin Hegedus
bf707de08f
Change directive format to strict camel case 2025-04-28 21:58:18 +02:00
Ervin Hegedus
0b62b7eb85
Align debug messages to fix regression tests 2025-04-27 21:09:49 +02:00
Ervin Hegedus
91a45e79bd
Update error message
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:28:30 +02:00
Ervin Hegedus
2135c8934e
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:28:07 +02:00
Ervin Hegedus
8947346cd4
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:27:47 +02:00
Ervin Hegedus
67429307cc
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:27:26 +02:00
Ervin Hegedus
0c7ea21a26
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:27:04 +02:00
Ervin Hegedus
72de7e8400
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:26:37 +02:00
Ervin Hegedus
0bf60208af
Add explanation
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:26:09 +02:00
Ervin Hegedus
2000f4c048
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:25:20 +02:00
Ervin Hegedus
159f6120aa
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:24:47 +02:00
Ervin Hegedus
bbe7eda693
Update explanation
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:23:02 +02:00
Ervin Hegedus
0fcd257fc4
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:22:14 +02:00
Ervin Hegedus
fedc70983c
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:21:45 +02:00
Ervin Hegedus
5b1c6fbf68
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:21:24 +02:00
Ervin Hegedus
eedfed873e
Update error message
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:21:03 +02:00
Ervin Hegedus
f0aa0700fe
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:20:49 +02:00
Ervin Hegedus
90be54e25e
Update error message
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:20:22 +02:00
Ervin Hegedus
3dc9fe990c
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:19:11 +02:00
Ervin Hegedus
e3678764e5
Update comment
Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com>
2025-04-27 20:18:47 +02:00
Ervin Hegedus
22fee1296d
Change owner in legal text 2025-04-26 20:54:36 +02:00
Jakub Onderka
b82d600049 Disable Expect when sending audit logs to remote HTTP server
This will speed-up sending logs to remote server
2025-04-23 16:19:30 +02:00
Jakub Onderka
797f7dc4b2 Change http_version field in JSON audit log to string
Sometimes m_httpVersion variable can be empty and then invalid JSON is generated
2025-04-23 10:59:10 +02:00
Jakub Onderka
6408bf9237 Test for JSON audit log 2025-04-22 21:09:42 +02:00
Jakub Onderka
37c0de363e Simplify code for JSON audit log 2025-04-22 19:41:08 +02:00
Ervin Hegedus
029684c294
Add nullptr check conditions 2025-04-20 21:35:54 +02:00
Ervin Hegedus
3e95614699
Add nullptr check conditions 2025-04-20 21:10:43 +02:00
Ervin Hegedus
b42602f400
Fix more cppcheck warning 2025-04-20 19:31:20 +02:00
Ervin Hegedus
8ae8374be5
Fix cppcheck errors 2025-04-20 19:01:45 +02:00
Ervin Hegedus
f62de58632
Added new cc and h files 2025-04-20 18:29:59 +02:00
Ervin Hegedus
9e41a53760
Finish XMLArgs processing in v3 2025-04-20 18:21:28 +02:00
Ervin Hegedus
01a0615887
Merge pull request #3354 from cjihrig/patch-1
doc: update testing section of README
2025-03-23 20:31:29 +01:00
Colin Ihrig
80019da75e
doc: update testing section of README
The regression_tests and unit_tests scripts appear to
be named with underscores instead of hyphens. This
commit updates the README to reflect this.
2025-03-23 12:59:02 -04:00
Ervin Hegedus
7a986c7bae
Merge pull request #3350 from airween/v3/cppcheckfix
fix: align code to fix cppcheck errors
2025-03-14 09:06:27 +01:00
Ervin Hegedus
8f00f4700f
Make destructor default; remove impmelentation 2025-03-12 23:07:43 +01:00
Ervin Hegedus
42280d213d
Make function argument const pointer 2025-03-12 22:26:29 +01:00
Ervin Hegedus
c3c2c6f280
Make variable const pointer 2025-03-12 22:19:00 +01:00
Ervin Hegedus
dbdd6318ff
Replace C pointers by shared pointer in fuzzy_hash op code 2025-03-12 22:09:51 +01:00
Ervin Hegedus
d3c1ad7177
Make utf variable const pointer 2025-03-12 22:07:46 +01:00
Ervin Hegedus
dc40880663
Fix cppcheck error in example multi.c 2025-03-12 20:45:47 +01:00
Ervin Hegedus
1a2b13967f
Merge pull request #3321 from gberkes/refactor/default-pcre2
Refactor/default pcre2
2025-03-12 18:16:35 +01:00
Gabor Berkes
d68aef320c refactor: improve maintainability for SonarCloud compliance
- Marked the conversion operator in `Pcre2MatchContextPtr` as `explicit`
  to improve type safety and prevent unintended implicit conversions.
- Ensured consistent use of `nullptr` instead of `NULL` for better readability and modern C++ compliance.

These changes enhance code clarity, maintainability, and adherence to modern C++ best practices.
2025-02-20 12:25:53 +00:00
Gabor Berkes
b97b61b711
Merge branch 'owasp-modsecurity:v3/master' into refactor/default-pcre2 2025-02-20 09:56:01 +01:00
Gabor Berkes
6a2eee629c
Merge branch 'owasp-modsecurity:v3/master' into refactor/default-pcre2 2025-01-06 09:02:00 +01:00
Gabor Berkes
10d1c2be74 Refactor: improve PCRE settings output in configure.ac
Enhanced the `configure.ac` script to provide clearer and more readable output for PCRE and PCRE2 settings during configuration. This change improves usability by ensuring that the configuration process displays relevant details in a structured and user-friendly format.

This update aligns with the broader PCRE to PCRE2 migration effort, making the build configuration process more transparent and consistent.
2024-12-20 08:12:06 +00:00
Gabor Berkes
e92507868e Fix macOS GitHub Actions build: add PCRE2_CFLAGS/LDADD/LDFLAGS
Introduced PCRE2_CFLAGS, PCRE2_LDADD, and PCRE2_LDFLAGS in all relevant Makefile.am files to align with the existing PCRE_* variable usage. This change addresses potential issues with linking and configuration for builds on macOS GitHub runners.

These modifications aim to resolve the build failure observed exclusively in the macOS environment while maintaining compatibility across other platforms. Testing will confirm if this adjustment corrects the issue.
2024-12-11 12:48:20 +00:00
Gabor Berkes
784cf0b64c Debug: increase verbosity in pcre2.m4 for macOS GitHub Actions
Added AC_MSG_NOTICE macros to pcre2.m4 to enhance debugging output. This change aims to identify the cause of build failures on macOS runners in GitHub Actions, which do not occur locally or on other platforms (Linux, Windows).

The added verbosity will help trace the build process and inspect variable values for inconsistencies in the macOS runner environment.
2024-12-11 08:57:43 +00:00
Gabor Berkes
a07d0c7d34 Fix missing libpcre2 dependency on macOS GitHub runner
Identified an issue where the macOS GitHub runner no longer includes the libpcre2 library by default. Updated the workflow configuration to explicitly add libpcre2 as a dependency, ensuring successful builds and compatibility with the updated build system.

This change prevents build failures on macOS environments and aligns the runner's setup with project requirements.
2024-12-10 21:40:09 +00:00
Gabor Berkes
106ed22b6d Fix typo in pcre.m4: corrected PCRE_CFLAGS assignment 2024-12-10 10:58:20 +00:00
Gabor Berkes
c6433df7b2 Refactor build system to use libpcre2 as the default
Updated the build system and related source files to use libpcre2 as the
default regex library instead of the deprecated libpcre. This change
ensures future compatibility and aligns with the library's maintenance status.

To build with the old libpcre, the `--with-pcre` configuration parameter
can be specified.
2024-12-10 10:16:14 +00:00
Gabor Berkes
4fb22466a0 Cleanup: Remove useless/nonfunctional AM_CONDITIONAL macros
- Deleted AM_CONDITIONAL macros from configure.ac that had no functional
  impact on the build system.
2024-12-10 07:32:13 +00:00
71 changed files with 10319 additions and 8058 deletions

View File

@ -26,7 +26,7 @@ jobs:
- {label: "wo geoip", opt: "--without-geoip" }
- {label: "wo ssdeep", opt: "--without-ssdeep" }
- {label: "with lmdb", opt: "--with-lmdb" }
- {label: "with pcre2", opt: "--with-pcre2" }
- {label: "with pcre", opt: "--with-pcre" }
exclude:
- platform: {label: "x32"}
configure: {label: "wo geoip"}
@ -88,7 +88,7 @@ jobs:
- {label: "wo geoip", opt: "--without-geoip" }
- {label: "wo ssdeep", opt: "--without-ssdeep" }
- {label: "with lmdb", opt: "--with-lmdb" }
- {label: "with pcre2", opt: "--with-pcre2" }
- {label: "with pcre", opt: "--with-pcre" }
steps:
- name: Setup Dependencies
# curl, pcre2 not installed because they're already

View File

@ -63,7 +63,7 @@ cppcheck:
--enable=warning,style,performance,portability,unusedFunction,missingInclude \
--inconclusive \
--template="warning: {file},{line},{severity},{id},{message}" \
-I headers -I . -I others -I src -I others/mbedtls/include \
-I headers -I . -I $(top_srcdir)/others -I $(top_srcdir)/src -I $(top_srcdir)/others/mbedtls/include \
--error-exitcode=1 \
-i "src/parser/seclang-parser.cc" -i "src/parser/seclang-scanner.cc" \
-i others \

View File

@ -219,8 +219,8 @@ the utilities, follow the commands listed below:
$ cd /path/to/your/ModSecurity
$ git submodule foreach git pull
$ cd test
$ ./regression-tests
$ ./unit-tests
$ ./regression_tests
$ ./unit_tests
```
### Debugging

View File

@ -21,8 +21,8 @@ AC_ARG_WITH(
[test_paths="${with_pcre}"],
[test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr /opt/local"])
if test "x${with_pcre2}" != "x" && test "x${with_pcre2}" != "xno"; then
AC_MSG_NOTICE([pcre2 specified; omitting check for pcre])
if test "x${with_pcre}" == "x" && test "x${with_pcre}" != "xno"; then
AC_MSG_NOTICE([Support for pcre not requested; omitting check for pcre])
else
AC_MSG_CHECKING([for libpcre config script])
@ -106,6 +106,7 @@ else
LIBS=$save_LIBS
fi
PCRE_CFLAGS="-DWITH_PCRE ${PCRE_CFLAGS}"
AC_SUBST(PCRE_CONFIG)
AC_SUBST(PCRE_VERSION)
AC_SUBST(PCRE_CPPFLAGS)

View File

@ -29,10 +29,12 @@ if test "x${with_pcre2}" == "xno"; then
AC_MSG_NOTICE([Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
PCRE2_DISABLED=yes
else
if test "x${with_pcre2}" == "xyes"; then
PCRE2_MANDATORY=yes
AC_MSG_NOTICE([PCRE2 support was marked as mandatory by the utilization of --with-pcre2=yes])
fi
PCRE2_MANDATORY=yes
AC_MSG_NOTICE([PCRE2 is enabled by default.])
# if test "x${with_pcre2}" == "xyes"; then
# PCRE2_MANDATORY=yes
# AC_MSG_NOTICE([PCRE2 support was marked as mandatory by the utilization of --with-pcre2=yes])
# fi
# for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_PCRE2_AT(${x})
# if test -n "${PCRE2_VERSION}"; then
@ -96,9 +98,14 @@ else
AC_MSG_NOTICE([PCRE2 is disabled by default.])
else
PCRE2_FOUND=1
AC_MSG_NOTICE([using PCRE2 v${PCRE2_VERSION}])
PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}"
PCRE2_CFLAGS="${PCRE2_CFLAGS}"
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
AC_MSG_NOTICE([using PCRE2_VERSION ${PCRE2_VERSION}])
AC_MSG_NOTICE([using PCRE2_LDADD ${PCRE2_LDADD}])
AC_MSG_NOTICE([using PCRE2_LIBS ${PCRE2_LIBS}])
AC_MSG_NOTICE([using PCRE2_LDFLAGS ${PCRE2_LDFLAGS}])
AC_MSG_NOTICE([using PCRE2_CFLAGS ${PCRE2_CFLAGS}])
AC_MSG_NOTICE([using PCRE2_DISPLAY ${PCRE2_DISPLAY}])
AC_SUBST(PCRE2_VERSION)
AC_SUBST(PCRE2_LDADD)
AC_SUBST(PCRE2_LIBS)

View File

@ -42,7 +42,7 @@ AC_PREFIX_DEFAULT([/usr/local/modsecurity])
# General automake options.
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
# Check for dependencies (C++, AR, Lex, Yacc and Make)
@ -109,24 +109,19 @@ AM_CONDITIONAL([YAJL_VERSION], [test "$YAJL_VERSION" != ""])
# Check for LibGeoIP
PROG_GEOIP
AM_CONDITIONAL([GEOIP_CFLAGS], [test "GEOIP_CFLAGS" != ""])
# Check for MaxMind
PROG_MAXMIND
AM_CONDITIONAL([MAXMIND_CFLAGS], [test "MAXMIND_CFLAGS" != ""])
# Check for LMDB
PROG_LMDB
AM_CONDITIONAL([LMDB_CFLAGS], [test "LMDB_CFLAGS" != ""])
# Check for SSDEEP
CHECK_SSDEEP
AM_CONDITIONAL([SSDEEP_CFLAGS], [test "SSDEEP_CFLAGS" != ""])
# Check for LUA
CHECK_LUA
AM_CONDITIONAL([LUA_CFLAGS], [test "LUA_CFLAGS" != ""])
#
@ -146,16 +141,16 @@ CHECK_LIBXML2
#
# Check for libpcre
# Check for libpcre only if explicitly requested
#
CHECK_PCRE
#
# Check for pcre2
#
PROG_PCRE2
AM_CONDITIONAL([PCRE2_CFLAGS], [test "PCRE2_CFLAGS" != ""])
if test "x${with_pcre}" != "x" && test "x${with_pcre}" != "xno"; then
CHECK_PCRE
else
#
# Check for pcre2
#
PROG_PCRE2
fi
# Checks for header files.
@ -587,6 +582,17 @@ if test "x$LUA_FOUND" = "x2"; then
echo " + LUA ....disabled"
fi
##PCRE
if test "x${with_pcre}" != "x" \
&& test "x${with_pcre}" != "xno" \
&& test "x${PCRE_VERSION}" == "x"; then
AC_MSG_NOTICE([*** pcre library not found.])
else
echo " + PCRE ....found "
echo " using pcre v${PCRE_VERSION}"
echo " ${PCRE_LDADD}, ${PCRE_CFLAGS}"
fi
## PCRE2
if test "x$PCRE2_FOUND" = "x0"; then

View File

@ -38,7 +38,7 @@ RulesSet *rules = NULL;
ModSecurity *modsec = NULL;
void process_special_request (int j) {
static void process_special_request (int j) {
Transaction *transaction;
transaction = msc_new_transaction(modsec, rules, NULL);
@ -60,7 +60,7 @@ void process_special_request (int j) {
msc_transaction_cleanup(transaction);
}
void process_request (int j) {
static void process_request (int j) {
int i;
for (i = 0; i < REQUESTS_PER_PROCESS; i++) {

View File

@ -14,6 +14,7 @@ multithread_LDADD = \
$(MAXMIND_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
@ -46,6 +47,7 @@ multithread_CPPFLAGS = \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LIBXML2_CFLAGS)

View File

@ -14,6 +14,7 @@ simple_request_LDADD = \
$(MAXMIND_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
@ -46,6 +47,7 @@ simple_request_CPPFLAGS = \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LIBXML2_CFLAGS)

View File

@ -14,6 +14,7 @@ read_LDADD = \
$(LMDB_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
@ -46,6 +47,7 @@ read_CPPFLAGS = \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LIBXML2_CFLAGS)

View File

@ -14,6 +14,7 @@ simple_request_LDADD = \
$(LMDB_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
@ -46,6 +47,7 @@ simple_request_CPPFLAGS = \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LIBXML2_CFLAGS)
MAINTAINERCLEANFILES = \

View File

@ -153,17 +153,18 @@ class AuditLog {
bool setStorageDirMode(int permission);
bool setFileMode(int permission);
bool setStatus(AuditLogStatus new_status);
bool setRelevantStatus(const std::basic_string<char>& new_relevant_status);
bool setFilePath1(const std::basic_string<char>& path);
bool setFilePath2(const std::basic_string<char>& path);
bool setStorageDir(const std::basic_string<char>& path);
bool setRelevantStatus(std::string_view new_relevant_status);
bool setFilePath1(std::string_view path);
bool setFilePath2(std::string_view path);
bool setStorageDir(std::string_view path);
bool setPrefix(std::string_view prefix);
bool setFormat(AuditLogFormat fmt);
int getDirectoryPermission() const;
int getFilePermission() const;
int getParts() const;
bool setParts(const std::basic_string<char>& new_parts);
bool setParts(std::string_view new_parts);
bool setType(AuditLogType audit_type);
bool init(std::string *error);
@ -173,8 +174,8 @@ class AuditLog {
bool saveIfRelevant(Transaction *transaction, int parts);
bool isRelevant(int status);
static int addParts(int parts, const std::string& new_parts);
static int removeParts(int parts, const std::string& new_parts);
static int addParts(int parts, std::string_view new_parts);
static int removeParts(int parts, std::string_view new_parts);
void setCtlAuditEngineActive() {
m_ctlAuditEngineActive = true;
@ -182,31 +183,32 @@ class AuditLog {
bool merge(AuditLog *from, std::string *error);
std::string m_path1;
std::string m_path2;
std::string m_storage_dir;
std::string m_path1 = std::string("");
std::string m_path2 = std::string("");
std::string m_storage_dir = std::string("");
std::string m_prefix = std::string("");
AuditLogFormat m_format;
AuditLogFormat m_format = NotSetAuditLogFormat;
protected:
int m_parts;
int m_parts = -1;
int m_defaultParts = AAuditLogPart | BAuditLogPart | CAuditLogPart
| FAuditLogPart | HAuditLogPart | ZAuditLogPart;
int m_filePermission;
int m_filePermission = -1;
int m_defaultFilePermission = 0640;
int m_directoryPermission;
int m_directoryPermission = -1;
int m_defaultDirectoryPermission = 0750;
private:
AuditLogStatus m_status;
AuditLogStatus m_status = NotSetLogStatus;
AuditLogType m_type;
std::string m_relevant;
AuditLogType m_type = NotSetAuditLogType;
std::string m_relevant = std::string("");
audit_log::writer::Writer *m_writer;
bool m_ctlAuditEngineActive; // rules have at least one action On or RelevantOnly
audit_log::writer::Writer *m_writer = nullptr;
bool m_ctlAuditEngineActive = false; // rules have at least one action On or RelevantOnly
};

View File

@ -59,7 +59,6 @@ class RuleWithOperator : public RuleWithActions {
static void updateMatchedVars(Transaction *trasn, const std::string &key,
const std::string &value);
static void cleanMatchedVars(Transaction *trasn);
const std::string& getOperatorName() const;

View File

@ -53,8 +53,8 @@ class RulesExceptions {
bool contains(int a);
bool merge(RulesExceptions *from);
bool loadRemoveRuleByMsg(const std::string &msg, std::string *error);
bool loadRemoveRuleByTag(const std::string &msg, std::string *error);
bool loadRemoveRuleByMsg(const std::string &msg, const std::string *error);
bool loadRemoveRuleByTag(const std::string &msg, const std::string *error);
bool loadUpdateTargetByMsg(const std::string &msg,
std::unique_ptr<std::vector<std::unique_ptr<variables::Variable> > > v,

View File

@ -80,6 +80,8 @@ class RulesSet : public RulesSetProperties {
void debug(int level, const std::string &id, const std::string &uri,
const std::string &msg);
static void cleanMatchedVars(Transaction *trans);
RulesSetPhases m_rulesSetPhases;
private:
#ifndef NO_LOGS

View File

@ -13,6 +13,14 @@
*
*/
#ifdef WIN32
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#endif
#ifdef __cplusplus
#include <ctime>
@ -22,6 +30,8 @@
#include <list>
#include <set>
#include <cstring>
#include <limits>
#include <cstdint>
#endif
@ -52,6 +62,11 @@
to = (from == PropertyNotSetBodyLimitAction) ? default : from; \
}
#define merge_xmlargparse_value(to, from, default) \
if (to == PropertyNotSetConfigXMLParseXmlIntoArgs) { \
to = (from == PropertyNotSetConfigXMLParseXmlIntoArgs) ? default : from; \
}
#ifdef __cplusplus
namespace modsecurity {
@ -63,46 +78,132 @@ class Driver;
using modsecurity::debug_log::DebugLog;
using modsecurity::audit_log::AuditLog;
/** @ingroup ModSecurity_CPP_API */
class ConfigInt {
public:
ConfigInt() : m_set(false), m_value(0) { }
bool m_set;
int m_value;
// template for different numeric int types
template <typename T>
class ConfigValue {
public:
bool m_set = false;
T m_value = 0;
void merge(const ConfigInt *from) {
if (m_set == true || from->m_set == false) {
ConfigValue() = default;
void merge(const ConfigValue<T>* from) {
if (m_set || !from->m_set) {
return;
}
m_set = true;
m_value = from->m_value;
return;
}
// default parser
bool parse(const std::string& a, std::string* errmsg = nullptr) {
// use an alias type because the template can convert both signed and unsigned int
using LimitSigned = std::conditional_t<std::is_signed_v<T>, std::int64_t, std::uint64_t>;
LimitSigned val;
// clear errno variable, wee need that later
errno = 0;
try {
if constexpr (std::is_signed_v<T>) {
val = static_cast<std::int64_t>(std::stoll(a));
} else {
val = static_cast<std::uint64_t>(std::stoull(a));
}
}
catch (const std::invalid_argument&) {
// probably can't occur, but we handle it anyway
set_error(errmsg, "Invalid number format (not numeric)");
return false;
}
catch (const std::out_of_range&) {
// the value is out of range, we can not handle it
set_error(errmsg, "Number out of range");
return false;
}
catch (...) { // NOSONAR
// we don't need to handle all exceptions, the engine's BISON parser
// does not allow other symbols than numbers
set_error(errmsg, "An unknown error occurred while parsing number.");
return false;
}
if (
// The first condition will be true when the value is bigger than int64/uint64 maximum value.
// The second condition checks whether the value fits into int64/uint64, but not
// into the designed type, e.g., uint32; in that case the errno will be 0, but
// we must check the value is not bigger than the defined maximum of the class.
(errno == ERANGE && val == std::numeric_limits<LimitSigned>::max())
||
(val > static_cast<LimitSigned>(maxValue()))
) {
set_error(errmsg, "Value is too big.");
return false;
}
if (
// same as above
(errno == ERANGE && val == std::numeric_limits<LimitSigned>::min())
||
(val < static_cast<LimitSigned>(minValue()))
) {
set_error(errmsg, "Value is too small.");
return false;
}
m_value = static_cast<T>(val);
m_set = true;
return true;
}
protected:
// derived classes must implement the maxValue
virtual T maxValue() const = 0;
// minValue is optional
virtual T minValue() const { return 0; }
private:
static inline void set_error(std::string* err, const char* msg) {
if (err) {
*err = msg;
}
}
};
/** @ingroup ModSecurity_CPP_API */
class ConfigDouble {
public:
ConfigDouble() : m_set(false), m_value(0) { }
bool m_set;
double m_value;
class ConfigInt : public ConfigValue<int32_t> {
protected:
int32_t minValue() const override {
return std::numeric_limits<int32_t>::min();
}
int32_t maxValue() const override {
return std::numeric_limits<int32_t>::max();
}
};
void merge(const ConfigDouble *from) {
if (m_set == true || from->m_set == false) {
return;
}
m_set = true;
m_value = from->m_value;
return;
class ConfigUnsignedInt : public ConfigValue<uint32_t> {
protected:
uint32_t maxValue() const override {
return std::numeric_limits<uint32_t>::max();
}
};
class ConfigUnsignedLong : public ConfigValue<uint64_t> {
protected:
uint64_t maxValue() const override {
return std::numeric_limits<uint64_t>::max();
}
};
class ConfigString {
public:
ConfigString() : m_set(false), m_value("") { }
bool m_set;
std::string m_value;
bool m_set = false;
std::string m_value = "";
ConfigString() = default;
void merge(const ConfigString *from) {
if (m_set == true || from->m_set == false) {
@ -117,10 +218,10 @@ class ConfigString {
class ConfigSet {
public:
ConfigSet() : m_set(false), m_clear(false) { }
bool m_set;
bool m_clear;
bool m_set = false;
bool m_clear = false;
std::set<std::string> m_value;
ConfigSet() = default;
};
@ -177,6 +278,7 @@ class RulesSetProperties {
m_secRequestBodyAccess(PropertyNotSetConfigBoolean),
m_secResponseBodyAccess(PropertyNotSetConfigBoolean),
m_secXMLExternalEntity(PropertyNotSetConfigBoolean),
m_secXMLParseXmlIntoArgs(PropertyNotSetConfigXMLParseXmlIntoArgs),
m_tmpSaveUploadedFiles(PropertyNotSetConfigBoolean),
m_uploadKeepFiles(PropertyNotSetConfigBoolean),
m_debugLog(new DebugLog()),
@ -191,6 +293,7 @@ class RulesSetProperties {
m_secRequestBodyAccess(PropertyNotSetConfigBoolean),
m_secResponseBodyAccess(PropertyNotSetConfigBoolean),
m_secXMLExternalEntity(PropertyNotSetConfigBoolean),
m_secXMLParseXmlIntoArgs(PropertyNotSetConfigXMLParseXmlIntoArgs),
m_tmpSaveUploadedFiles(PropertyNotSetConfigBoolean),
m_uploadKeepFiles(PropertyNotSetConfigBoolean),
m_debugLog(debugLog),
@ -218,7 +321,8 @@ class RulesSetProperties {
/**
*
*
* The ConfigBoolean enumerator defines the states for configuration boolean values.
* The default value is PropertyNotSetConfigBoolean.
*/
enum ConfigBoolean {
TrueConfigBoolean,
@ -226,6 +330,18 @@ class RulesSetProperties {
PropertyNotSetConfigBoolean
};
/**
*
* The ConfigXMLParseXmlIntoArgs enumerator defines the states for the configuration
* XMLParseXmlIntoArgs values.
* The default value is PropertyNotSetConfigXMLParseXmlIntoArgs.
*/
enum ConfigXMLParseXmlIntoArgs {
TrueConfigXMLParseXmlIntoArgs,
FalseConfigXMLParseXmlIntoArgs,
OnlyArgsConfigXMLParseXmlIntoArgs,
PropertyNotSetConfigXMLParseXmlIntoArgs
};
/**
*
@ -311,7 +427,7 @@ class RulesSetProperties {
};
static const char *ruleEngineStateString(RuleEngine i) {
static std::string ruleEngineStateString(RuleEngine i) {
switch (i) {
case DisabledRuleEngine:
return "Disabled";
@ -322,7 +438,7 @@ class RulesSetProperties {
case PropertyNotSetRuleEngine:
return "PropertyNotSet/DetectionOnly";
}
return NULL;
return std::string{};
}
@ -338,6 +454,19 @@ class RulesSetProperties {
}
}
static std::string configXMLParseXmlIntoArgsString(ConfigXMLParseXmlIntoArgs i) {
switch (i) {
case TrueConfigXMLParseXmlIntoArgs:
return "True";
case FalseConfigXMLParseXmlIntoArgs:
return "False";
case OnlyArgsConfigXMLParseXmlIntoArgs:
return "OnlyArgs";
case PropertyNotSetConfigXMLParseXmlIntoArgs:
default:
return "Not set";
}
}
static int mergeProperties(RulesSetProperties *from,
RulesSetProperties *to, std::ostringstream *err) {
@ -357,6 +486,10 @@ class RulesSetProperties {
from->m_secXMLExternalEntity,
PropertyNotSetConfigBoolean);
merge_xmlargparse_value(to->m_secXMLParseXmlIntoArgs,
from->m_secXMLParseXmlIntoArgs,
PropertyNotSetConfigXMLParseXmlIntoArgs);
merge_boolean_value(to->m_uploadKeepFiles,
from->m_uploadKeepFiles,
PropertyNotSetConfigBoolean);
@ -464,16 +597,17 @@ class RulesSetProperties {
ConfigBoolean m_secRequestBodyAccess;
ConfigBoolean m_secResponseBodyAccess;
ConfigBoolean m_secXMLExternalEntity;
ConfigXMLParseXmlIntoArgs m_secXMLParseXmlIntoArgs;
ConfigBoolean m_tmpSaveUploadedFiles;
ConfigBoolean m_uploadKeepFiles;
ConfigDouble m_argumentsLimit;
ConfigDouble m_requestBodyJsonDepthLimit;
ConfigDouble m_requestBodyLimit;
ConfigDouble m_requestBodyNoFilesLimit;
ConfigDouble m_responseBodyLimit;
ConfigInt m_pcreMatchLimit;
ConfigInt m_uploadFileLimit;
ConfigInt m_uploadFileMode;
ConfigUnsignedInt m_argumentsLimit;
ConfigUnsignedInt m_requestBodyJsonDepthLimit;
ConfigUnsignedLong m_requestBodyLimit;
ConfigUnsignedLong m_requestBodyNoFilesLimit;
ConfigUnsignedLong m_responseBodyLimit;
ConfigUnsignedInt m_pcreMatchLimit;
ConfigUnsignedInt m_uploadFileLimit;
ConfigUnsignedInt m_uploadFileMode;
DebugLog *m_debugLog;
OnFailedRemoteRulesAction m_remoteRulesActionOnFailed;
RuleEngine m_secRuleEngine;

View File

@ -80,15 +80,14 @@ typedef struct Rules_t RulesSet;
#define LOGFY_ADD(a, b) \
yajl_gen_string(g, reinterpret_cast<const unsigned char*>(a), strlen(a)); \
if (b == NULL) { \
if (b.data() == NULL) { \
yajl_gen_string(g, reinterpret_cast<const unsigned char*>(""), \
strlen("")); \
} else { \
yajl_gen_string(g, reinterpret_cast<const unsigned char*>(b), \
strlen(b)); \
yajl_gen_string(g, reinterpret_cast<const unsigned char*>(b.data()), \
b.length()); \
}
#define LOGFY_ADD_INT(a, b) \
yajl_gen_string(g, reinterpret_cast<const unsigned char*>(a), strlen(a)); \
yajl_gen_number(g, reinterpret_cast<const char*>(b), strlen(b));
@ -412,7 +411,7 @@ class Transaction : public TransactionAnchoredVariables, public TransactionSecMa
int getRuleEngineState() const;
std::string toJSON(int parts);
std::string toOldAuditLogFormat(int parts, const std::string &trailer);
std::string toOldAuditLogFormat(int parts, const std::string &trailer, const std::string &header);
std::string toOldAuditLogFormatIndex(const std::string &filename,
double size, const std::string &md5);
@ -619,6 +618,7 @@ class Transaction : public TransactionAnchoredVariables, public TransactionSecMa
RequestBodyProcessor::JSON *m_json;
int m_secRuleEngine;
int m_secXMLParseXmlIntoArgs;
std::string m_variableDuration;
std::map<std::string, std::string> m_variableEnvs;

View File

@ -28,6 +28,6 @@ libmbedtls_la_SOURCES = \
mbedtls/library/sha1.c \
mbedtls/library/platform_util.c
libmbedtls_la_CFLAGS = -DMBEDTLS_CONFIG_FILE=\"mbedtls/mbedtls_config.h\" -Imbedtls/include
libmbedtls_la_CFLAGS = -DMBEDTLS_CONFIG_FILE=\"mbedtls/mbedtls_config.h\" -I$(top_srcdir)/others/mbedtls/include
libmbedtls_la_CPPFLAGS =
libmbedtls_la_LIBADD =

View File

@ -68,21 +68,21 @@ libmodsecurity_includesub_actions_HEADERS = \
noinst_HEADERS = \
actions/*.h \
actions/ctl/*.h \
actions/data/*.h \
actions/disruptive/*.h \
actions/transformations/*.h \
debug_log/*.h \
audit_log/writer/*.h \
collection/backend/*.h \
operators/*.h \
parser/*.h \
request_body_processor/*.h \
utils/*.h \
variables/*.h \
engine/*.h \
*.h
$(wildcard actions/*.h) \
$(wildcard actions/ctl/*.h) \
$(wildcard actions/data/*.h) \
$(wildcard actions/disruptive/*.h) \
$(wildcard actions/transformations/*.h) \
$(wildcard debug_log/*.h) \
$(wildcard audit_log/writer/*.h) \
$(wildcard collection/backend/*.h) \
$(wildcard operators/*.h) \
$(wildcard parser/*.h) \
$(wildcard request_body_processor/*.h) \
$(wildcard utils/*.h) \
$(wildcard variables/*.h) \
$(wildcard engine/*.h) \
$(wildcard *.h)
ENGINES = \
@ -119,6 +119,7 @@ ACTIONS = \
actions/chain.cc \
actions/ctl/audit_log_parts.cc \
actions/ctl/audit_engine.cc \
actions/ctl/parse_xml_into_args.cc \
actions/ctl/rule_engine.cc \
actions/ctl/request_body_processor_json.cc \
actions/ctl/request_body_processor_xml.cc \
@ -307,13 +308,14 @@ libmodsecurity_la_CFLAGS =
libmodsecurity_la_CPPFLAGS = \
-I.. \
-I$(top_srcdir) \
-I$(top_builddir) \
-g \
-I../others \
-I../others/mbedtls/include \
-I$(top_srcdir)/others \
-I$(top_srcdir)/others/mbedtls/include \
-fPIC \
-O3 \
-I../headers \
-I$(top_srcdir)/headers \
$(CURL_CFLAGS) \
$(GEOIP_CFLAGS) \
$(GLOBAL_CPPFLAGS) \

View File

@ -0,0 +1,63 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2025 OWASP ModSecurity project
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact OWASP.
* directly using the email address modsecurity@owasp.org.
*
*/
#include "src/actions/ctl/parse_xml_into_args.h"
#include <iostream>
#include <string>
#include "modsecurity/rules_set_properties.h"
#include "modsecurity/rules_set.h"
#include "modsecurity/transaction.h"
namespace modsecurity {
namespace actions {
namespace ctl {
bool ParseXmlIntoArgs::init(std::string *error) {
std::string what(m_parser_payload, 17, m_parser_payload.size() - 17);
if (what == "on") {
m_secXMLParseXmlIntoArgs = RulesSetProperties::TrueConfigXMLParseXmlIntoArgs;
} else if (what == "off") {
m_secXMLParseXmlIntoArgs = RulesSetProperties::FalseConfigXMLParseXmlIntoArgs;
} else if (what == "onlyargs") {
m_secXMLParseXmlIntoArgs = RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs;
} else {
error->assign("Internal error. Expected: On, Off or OnlyArgs; " \
"got: " + m_parser_payload);
return false;
}
return true;
}
bool ParseXmlIntoArgs::evaluate(RuleWithActions *rule, Transaction *transaction) {
std::stringstream a;
a << "Setting SecParseXmlIntoArgs to ";
a << modsecurity::RulesSetProperties::configXMLParseXmlIntoArgsString(m_secXMLParseXmlIntoArgs);
a << " as requested by a ctl:parseXmlIntoArgs action";
ms_dbg_a(transaction, 8, a.str());
transaction->m_secXMLParseXmlIntoArgs = m_secXMLParseXmlIntoArgs;
return true;
}
} // namespace ctl
} // namespace actions
} // namespace modsecurity

View File

@ -0,0 +1,48 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2025 OWASP ModSecurity Project
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact OWASP.
* directly using the email address modsecurity@owasp.org
*
*/
#include <string>
#include "modsecurity/rules_set_properties.h"
#include "modsecurity/actions/action.h"
#include "modsecurity/transaction.h"
#ifndef SRC_ACTIONS_CTL_PARSE_XML_INTO_ARGS_H_
#define SRC_ACTIONS_CTL_PARSE_XML_INTO_ARGS_H_
namespace modsecurity {
namespace actions {
namespace ctl {
class ParseXmlIntoArgs : public Action {
public:
explicit ParseXmlIntoArgs(const std::string &action)
: Action(action),
m_secXMLParseXmlIntoArgs(RulesSetProperties::PropertyNotSetConfigXMLParseXmlIntoArgs) { }
bool init(std::string *error) override;
bool evaluate(RuleWithActions *rule, Transaction *transaction) override;
RulesSetProperties::ConfigXMLParseXmlIntoArgs m_secXMLParseXmlIntoArgs;
};
} // namespace ctl
} // namespace actions
} // namespace modsecurity
#endif // SRC_ACTIONS_CTL_PARSE_XML_INTO_ARGS_H_

View File

@ -46,7 +46,7 @@ static inline bool encode(std::string &value) {
int unicode_len = 0;
unsigned int d = 0;
unsigned char c;
auto utf = &input[i];
const auto* utf = &input[i];
c = *utf;

View File

@ -51,25 +51,13 @@ namespace modsecurity {
namespace audit_log {
AuditLog::AuditLog()
: m_path1(""),
m_path2(""),
m_storage_dir(""),
m_format(NotSetAuditLogFormat),
m_parts(-1),
m_filePermission(-1),
m_directoryPermission(-1),
m_status(NotSetLogStatus),
m_type(NotSetAuditLogType),
m_relevant(""),
m_writer(NULL),
m_ctlAuditEngineActive(false) { }
AuditLog::AuditLog() = default;
AuditLog::~AuditLog() {
if (m_writer) {
delete m_writer;
m_writer = NULL;
m_writer = nullptr;
}
}
@ -108,35 +96,42 @@ bool AuditLog::setStatus(AuditLogStatus status) {
}
bool AuditLog::setRelevantStatus(const std::basic_string<char>& status) {
bool AuditLog::setRelevantStatus(std::string_view status) {
this->m_relevant = std::string(status);
return true;
}
bool AuditLog::setStorageDir(const std::basic_string<char>& path) {
bool AuditLog::setStorageDir(std::string_view path) {
this->m_storage_dir = path;
return true;
}
bool AuditLog::setFilePath1(const std::basic_string<char>& path) {
bool AuditLog::setFilePath1(std::string_view path) {
this->m_path1 = path;
return true;
}
bool AuditLog::setFilePath2(const std::basic_string<char>& path) {
bool AuditLog::setFilePath2(std::string_view path) {
this->m_path2 = path;
return true;
}
bool AuditLog::setPrefix(std::string_view prefix) {
this->m_prefix = prefix;
return true;
}
bool AuditLog::setFormat(AuditLogFormat fmt) {
this->m_format = fmt;
return true;
}
int AuditLog::addParts(int parts, const std::string& new_parts) {
int AuditLog::addParts(int parts, std::string_view new_parts) {
PARTS_CONSTAINS('A', AAuditLogPart)
PARTS_CONSTAINS('B', BAuditLogPart)
PARTS_CONSTAINS('C', CAuditLogPart)
@ -154,7 +149,7 @@ int AuditLog::addParts(int parts, const std::string& new_parts) {
}
int AuditLog::removeParts(int parts, const std::string& new_parts) {
int AuditLog::removeParts(int parts, std::string_view new_parts) {
PARTS_CONSTAINS_REM('A', AAuditLogPart)
PARTS_CONSTAINS_REM('B', BAuditLogPart)
PARTS_CONSTAINS_REM('C', CAuditLogPart)
@ -172,7 +167,7 @@ int AuditLog::removeParts(int parts, const std::string& new_parts) {
}
bool AuditLog::setParts(const std::basic_string<char>& new_parts) {
bool AuditLog::setParts(std::string_view new_parts) {
int parts = 0;
PARTS_CONSTAINS('A', AAuditLogPart)
@ -208,7 +203,6 @@ bool AuditLog::setType(AuditLogType audit_type) {
}
bool AuditLog::init(std::string *error) {
audit_log::writer::Writer *tmp_writer;
@ -216,7 +210,7 @@ bool AuditLog::init(std::string *error) {
&& !m_ctlAuditEngineActive) {
if (m_writer) {
delete m_writer;
m_writer = NULL;
m_writer = nullptr;
}
return true;
}
@ -234,7 +228,7 @@ bool AuditLog::init(std::string *error) {
tmp_writer = new audit_log::writer::Serial(this);
}
if (tmp_writer == NULL) {
if (tmp_writer == nullptr) {
error->assign("Writer memory alloc failed!");
return false;
}
@ -312,7 +306,7 @@ bool AuditLog::saveIfRelevant(Transaction *transaction, int parts) {
}
ms_dbg_a(transaction, 5, "Saving this request as part " \
"of the audit logs.");
if (m_writer == NULL) {
if (m_writer == nullptr) {
ms_dbg_a(transaction, 1, "Internal error, audit log writer is null");
} else {
std::string error;
@ -337,6 +331,7 @@ bool AuditLog::merge(AuditLog *from, std::string *error) {
AL_MERGE_STRING_CONF(from->m_path2, m_path2);
AL_MERGE_STRING_CONF(from->m_storage_dir, m_storage_dir);
AL_MERGE_STRING_CONF(from->m_relevant, m_relevant);
AL_MERGE_STRING_CONF(from->m_prefix, m_prefix);
if (from->m_filePermission != -1) {
m_filePermission = from->m_filePermission;

View File

@ -119,7 +119,7 @@ bool Parallel::write(Transaction *transaction, int parts, std::string *error) {
} else {
std::string boundary;
generateBoundary(&boundary);
log = transaction->toOldAuditLogFormat(parts, "-" + boundary + "--");
log = transaction->toOldAuditLogFormat(parts, "-" + boundary + "--", m_audit->m_prefix);
}
const auto &logPath = m_audit->m_storage_dir;

View File

@ -42,7 +42,7 @@ bool Serial::write(Transaction *transaction, int parts, std::string *error) {
} else {
std::string boundary;
generateBoundary(&boundary);
msg = transaction->toOldAuditLogFormat(parts, "-" + boundary + "--");
msg = transaction->toOldAuditLogFormat(parts, "-" + boundary + "--", m_audit->m_prefix);
}
return utils::SharedFiles::getInstance().write(m_audit->m_path1, msg,

View File

@ -27,8 +27,8 @@ bool FuzzyHash::init(const std::string &param2, std::string *error) {
#ifdef WITH_SSDEEP
std::string digit;
std::string file;
std::istream *iss;
struct fuzzy_hash_chunk *chunk, *t;
std::ifstream *iss;
std::shared_ptr<fuzzy_hash_chunk> chunk, t;
std::string err;
auto pos = m_param.find_last_of(' ');
@ -48,18 +48,17 @@ bool FuzzyHash::init(const std::string &param2, std::string *error) {
std::string resource = utils::find_resource(file, param2, &err);
iss = new std::ifstream(resource, std::ios::in);
if (((std::ifstream *)iss)->is_open() == false) {
if (iss->is_open() == false) {
error->assign("Failed to open file: " + m_param + ". " + err);
delete iss;
return false;
}
for (std::string line; std::getline(*iss, line); ) {
chunk = (struct fuzzy_hash_chunk *)calloc(1,
sizeof(struct fuzzy_hash_chunk));
chunk = std::make_shared<fuzzy_hash_chunk>();
chunk->data = strdup(line.c_str());
chunk->next = NULL;
chunk->data = std::shared_ptr<char>(strdup(line.c_str()), free);
chunk->next = nullptr;
if (m_head == NULL) {
m_head = chunk;
@ -83,23 +82,11 @@ bool FuzzyHash::init(const std::string &param2, std::string *error) {
#endif
}
FuzzyHash::~FuzzyHash() {
struct fuzzy_hash_chunk *c = m_head;
while (c) {
struct fuzzy_hash_chunk *t = c;
free(c->data);
c->data = NULL;
c = c->next;
free(t);
}
m_head = NULL;
}
bool FuzzyHash::evaluate(Transaction *t, const std::string &str) {
#ifdef WITH_SSDEEP
char result[FUZZY_MAX_RESULT];
struct fuzzy_hash_chunk *chunk = m_head;
std::shared_ptr<fuzzy_hash_chunk> chunk = m_head;
if (fuzzy_hash_buf((const unsigned char*)str.c_str(),
str.size(), result)) {
@ -108,7 +95,7 @@ bool FuzzyHash::evaluate(Transaction *t, const std::string &str) {
}
while (chunk != NULL) {
int i = fuzzy_compare(chunk->data, result);
int i = fuzzy_compare(chunk->data.get(), result);
if (i >= m_threshold) {
ms_dbg_a(t, 4, "Fuzzy hash: matched " \
"with score: " + std::to_string(i) + ".");

View File

@ -31,8 +31,8 @@ namespace operators {
struct fuzzy_hash_chunk {
char *data;
struct fuzzy_hash_chunk *next;
std::shared_ptr<char> data;
std::shared_ptr<fuzzy_hash_chunk> next;
};
class FuzzyHash : public Operator {
@ -42,14 +42,14 @@ class FuzzyHash : public Operator {
: Operator("FuzzyHash", std::move(param)),
m_threshold(0),
m_head(NULL) { }
~FuzzyHash() override;
~FuzzyHash() override = default;
bool evaluate(Transaction *transaction, const std::string &std) override;
bool init(const std::string &param, std::string *error) override;
private:
int m_threshold;
struct fuzzy_hash_chunk *m_head;
std::shared_ptr<fuzzy_hash_chunk> m_head;
};
} // namespace operators

View File

@ -31,14 +31,14 @@ namespace modsecurity {
namespace operators {
bool InspectFile::init(const std::string &param2, std::string *error) {
std::istream *iss;
std::ifstream *iss;
std::string err;
std::string err_lua;
m_file = utils::find_resource(m_param, param2, &err);
iss = new std::ifstream(m_file, std::ios::in);
if (((std::ifstream *)iss)->is_open() == false) {
if (iss->is_open() == false) {
error->assign("Failed to open file: " + m_param + ". " + err);
delete iss;
return false;

View File

@ -20,7 +20,9 @@
#include "src/operators/operator.h"
#include "src/utils/https_client.h"
#include "src/utils/system.h"
#include "src/utils/string.h"
using namespace modsecurity::utils::string;
namespace modsecurity {
namespace operators {
@ -44,39 +46,44 @@ bool PmFromFile::isComment(const std::string &s) {
}
bool PmFromFile::init(const std::string &config, std::string *error) {
std::istream *iss;
std::vector<std::string> tokens = split(m_param, ' ');
if (m_param.compare(0, 8, "https://") == 0) {
Utils::HttpsClient client;
bool ret = client.download(m_param);
if (ret == false) {
error->assign(client.error);
return false;
for (const auto& token : tokens) {
if (token.empty()) {
continue;
}
iss = new std::stringstream(client.content);
} else {
std::string err;
std::string resource = utils::find_resource(m_param, config, &err);
iss = new std::ifstream(resource, std::ios::in);
if (((std::ifstream *)iss)->is_open() == false) {
error->assign("Failed to open file: " + m_param + ". " + err);
delete iss;
return false;
std::unique_ptr<std::istream> iss;
if (token.compare(0, 8, "https://") == 0) {
Utils::HttpsClient client;
bool ret = client.download(token);
if (ret == false) {
error->assign(client.error);
return false;
}
iss = std::make_unique<std::stringstream>(client.content);
} else {
std::string err;
std::string resource = utils::find_resource(token, config, &err);
auto file = std::make_unique<std::ifstream>(resource, std::ios::in);
if (file->is_open() == false) {
error->assign("Failed to open file: '" + token + "'. " + err);
return false;
}
iss = std::move(file);
}
for (std::string line; std::getline(*iss, line); ) {
if (isComment(line) == false) {
acmp_add_pattern(m_p, line.c_str(), NULL, NULL, line.length());
}
}
}
for (std::string line; std::getline(*iss, line); ) {
if (isComment(line) == false) {
acmp_add_pattern(m_p, line.c_str(), NULL, NULL, line.length());
}
}
while (m_p->is_failtree_done == 0) {
acmp_prepare(m_p);
}
delete iss;
return true;
}

View File

@ -226,9 +226,20 @@ bool Rbl::evaluate(Transaction *t, RuleWithActions *rule,
return false;
}
struct sockaddr *addr = info->ai_addr;
struct sockaddr_in *sin = (struct sockaddr_in *) addr;
furtherInfo(sin, ipStr, t, m_provider);
// SonarCloud suggested to use the init-statement to declare "addr" inside the if statement.
// I think that's not good here, because we need that in the else block
const struct sockaddr *addr = info->ai_addr; // NOSONAR
if (addr->sa_family == AF_INET) { // NOSONAR
struct sockaddr_in sin{}; // initialize an empty struct; we don't need port info
memcpy(&sin.sin_addr, addr->sa_data + 2, sizeof(sin.sin_addr));
sin.sin_family = AF_INET;
furtherInfo(&sin, ipStr, t, m_provider);
}
else {
ms_dbg_a(t, 7, "Unsupported address family: " + std::to_string(addr->sa_family));
freeaddrinfo(info);
return false;
}
freeaddrinfo(info);
if (rule && t && rule->hasCaptureAction()) {

View File

@ -68,19 +68,20 @@ bool Rx::evaluate(Transaction *transaction, RuleWithActions *rule,
// FIXME: DRY regex error reporting. This logic is currently duplicated in other operators.
if (regex_result != Utils::RegexResult::Ok) {
transaction->m_variableMscPcreError.set("1", transaction->m_variableOffset);
if (transaction) {
transaction->m_variableMscPcreError.set("1", transaction->m_variableOffset);
std::string regex_error_str = "OTHER";
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
regex_error_str = "MATCH_LIMIT";
transaction->m_variableMscPcreLimitsExceeded.set("1", transaction->m_variableOffset);
transaction->m_collections.m_tx_collection->storeOrUpdateFirst("MSC_PCRE_LIMITS_EXCEEDED", "1");
ms_dbg_a(transaction, 7, "Set TX.MSC_PCRE_LIMITS_EXCEEDED to 1");
std::string regex_error_str = "OTHER";
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
regex_error_str = "MATCH_LIMIT";
transaction->m_variableMscPcreLimitsExceeded.set("1", transaction->m_variableOffset);
transaction->m_collections.m_tx_collection->storeOrUpdateFirst("MSC_PCRE_LIMITS_EXCEEDED", "1");
ms_dbg_a(transaction, 7, "Set TX.MSC_PCRE_LIMITS_EXCEEDED to 1");
}
ms_dbg_a(transaction, 1, "rx: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
}
ms_dbg_a(transaction, 1, "rx: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
return false;
}

View File

@ -62,18 +62,20 @@ bool RxGlobal::evaluate(Transaction *transaction, RuleWithActions *rule,
// FIXME: DRY regex error reporting. This logic is currently duplicated in other operators.
if (regex_result != Utils::RegexResult::Ok) {
transaction->m_variableMscPcreError.set("1", transaction->m_variableOffset);
if (transaction) {
transaction->m_variableMscPcreError.set("1", transaction->m_variableOffset);
std::string regex_error_str = "OTHER";
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
regex_error_str = "MATCH_LIMIT";
transaction->m_variableMscPcreLimitsExceeded.set("1", transaction->m_variableOffset);
transaction->m_collections.m_tx_collection->storeOrUpdateFirst("MSC_PCRE_LIMITS_EXCEEDED", "1");
ms_dbg_a(transaction, 7, "Set TX.MSC_PCRE_LIMITS_EXCEEDED to 1");
std::string regex_error_str = "OTHER";
if (regex_result == Utils::RegexResult::ErrorMatchLimit) {
regex_error_str = "MATCH_LIMIT";
transaction->m_variableMscPcreLimitsExceeded.set("1", transaction->m_variableOffset);
transaction->m_collections.m_tx_collection->storeOrUpdateFirst("MSC_PCRE_LIMITS_EXCEEDED", "1");
ms_dbg_a(transaction, 7, "Set TX.MSC_PCRE_LIMITS_EXCEEDED to 1");
}
ms_dbg_a(transaction, 1, "rxGlobal: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
}
ms_dbg_a(transaction, 1, "rxGlobal: regex error '" + regex_error_str + "' for pattern '" + re->pattern + "'");
return false;
}

View File

@ -45,7 +45,7 @@ bool ValidateDTD::init(const std::string &file, std::string *error) {
bool ValidateDTD::evaluate(Transaction *transaction, const std::string &str) {
XmlDtdPtrManager dtd(xmlParseDTD(NULL, (const xmlChar *)m_resource.c_str()));
XmlDtdPtrManager dtd(xmlParseDTD(NULL, reinterpret_cast<const xmlChar *>(m_resource.c_str())));
if (dtd.get() == NULL) {
std::string err = std::string("XML: Failed to load DTD: ") \
+ m_resource;

View File

@ -21,11 +21,11 @@
#include "src/operators/operator.h"
#ifndef WITH_PCRE2
#ifdef WITH_PCRE
#if PCRE_HAVE_JIT
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
#else
#define pcre_study_opt 0
constexpr int pcre_study_opt = 0;
#endif
#endif
@ -34,20 +34,20 @@ namespace modsecurity {
namespace operators {
VerifyCC::~VerifyCC() {
#if WITH_PCRE2
#ifndef WITH_PCRE
pcre2_code_free(m_pc);
#else
if (m_pc != NULL) {
if (m_pc != nullptr) {
pcre_free(m_pc);
m_pc = NULL;
m_pc = nullptr;
}
if (m_pce != NULL) {
if (m_pce != nullptr) {
#if PCRE_HAVE_JIT
pcre_free_study(m_pce);
#else
pcre_free(m_pce);
#endif
m_pce = NULL;
m_pce = nullptr;
}
#endif
}
@ -94,33 +94,33 @@ int VerifyCC::luhnVerify(const char *ccnumber, int len) {
bool VerifyCC::init(const std::string &param2, std::string *error) {
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
PCRE2_SPTR pcre2_pattern = reinterpret_cast<PCRE2_SPTR>(m_param.c_str());
uint32_t pcre2_options = (PCRE2_DOTALL|PCRE2_MULTILINE);
int errornumber = 0;
PCRE2_SIZE erroroffset = 0;
m_pc = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
pcre2_options, &errornumber, &erroroffset, NULL);
if (m_pc == NULL) {
pcre2_options, &errornumber, &erroroffset, nullptr);
if (m_pc == nullptr) {
return false;
}
m_pcje = pcre2_jit_compile(m_pc, PCRE2_JIT_COMPLETE);
#else
const char *errptr = NULL;
const char *errptr = nullptr;
int erroffset = 0;
m_pc = pcre_compile(m_param.c_str(), PCRE_DOTALL|PCRE_MULTILINE,
&errptr, &erroffset, NULL);
if (m_pc == NULL) {
&errptr, &erroffset, nullptr);
if (m_pc == nullptr) {
error->assign(errptr);
return false;
}
m_pce = pcre_study(m_pc, pcre_study_opt, &errptr);
if (m_pce == NULL) {
if (errptr == NULL) {
if (m_pce == nullptr) {
if (errptr == nullptr) {
/*
* Per pcre_study(3) m_pce == NULL && errptr == NULL means
* Per pcre_study(3) m_pce == nullptr && errptr == nullptr means
* that no addional information is found, so no need to study
*/
return true;
@ -136,21 +136,21 @@ bool VerifyCC::init(const std::string &param2, std::string *error) {
bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
const std::string& i, RuleMessage &ruleMessage) {
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
PCRE2_SIZE offset = 0;
size_t target_length = i.length();
PCRE2_SPTR pcre2_i = reinterpret_cast<PCRE2_SPTR>(i.c_str());
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, nullptr);
int ret;
for (offset = 0; offset < target_length; offset++) {
if (m_pcje == 0) {
ret = pcre2_jit_match(m_pc, pcre2_i, target_length, offset, 0, match_data, NULL);
ret = pcre2_jit_match(m_pc, pcre2_i, target_length, offset, 0, match_data, nullptr);
}
if (m_pcje != 0 || ret == PCRE2_ERROR_JIT_STACKLIMIT) {
ret = pcre2_match(m_pc, pcre2_i, target_length, offset, PCRE2_NO_JIT, match_data, NULL);
ret = pcre2_match(m_pc, pcre2_i, target_length, offset, PCRE2_NO_JIT, match_data, nullptr);
}
/* If there was no match, then we are done. */
@ -192,7 +192,7 @@ bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
"\" at " + i + ". [offset " +
std::to_string(offset) + "]");
}
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre2_match_data_free(match_data);
#endif
return true;
@ -200,7 +200,7 @@ bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
}
}
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre2_match_data_free(match_data);
#endif

View File

@ -16,7 +16,7 @@
#ifndef SRC_OPERATORS_VERIFY_CC_H_
#define SRC_OPERATORS_VERIFY_CC_H_
#if WITH_PCRE2
#ifndef WITH_PCRE
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#else
@ -38,12 +38,12 @@ class VerifyCC : public Operator {
/** @ingroup ModSecurity_Operator */
explicit VerifyCC(std::unique_ptr<RunTimeString> param)
: Operator("VerifyCC", std::move(param)),
#if WITH_PCRE2
m_pc(NULL),
#ifndef WITH_PCRE
m_pc(nullptr),
m_pcje(PCRE2_ERROR_JIT_BADOPTION) { }
#else
m_pc(NULL),
m_pce(NULL) { }
m_pc(nullptr),
m_pce(nullptr) { }
#endif
~VerifyCC() override;
@ -52,7 +52,7 @@ class VerifyCC : public Operator {
RuleMessage &ruleMessage) override;
bool init(const std::string &param, std::string *error) override;
private:
#if WITH_PCRE2
#ifndef WITH_PCRE
pcre2_code *m_pc;
int m_pcje;
#else

View File

@ -25,6 +25,7 @@ libmodsec_parser_la_CPPFLAGS = \
$(YAJL_CFLAGS) \
$(LMDB_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LIBXML2_CFLAGS)
test.cc: seclang-parser.hh

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@ class Driver;
#include "src/actions/chain.h"
#include "src/actions/ctl/audit_engine.h"
#include "src/actions/ctl/audit_log_parts.h"
#include "src/actions/ctl/parse_xml_into_args.h"
#include "src/actions/ctl/request_body_access.h"
#include "src/actions/ctl/rule_engine.h"
#include "src/actions/ctl/request_body_processor_json.h"
@ -478,7 +479,7 @@ using namespace modsecurity::operators;
OPERATOR_VERIFY_CC "OPERATOR_VERIFY_CC"
OPERATOR_VERIFY_CPF "OPERATOR_VERIFY_CPF"
OPERATOR_VERIFY_SSN "OPERATOR_VERIFY_SSN"
OPERATOR_VERIFY_SVNR "OPERATOR_VERIFY_SVNR"
OPERATOR_VERIFY_SVNR "OPERATOR_VERIFY_SVNR"
OPERATOR_WITHIN "OPERATOR_WITHIN"
CONFIG_DIR_AUDIT_LOG_FMT
@ -502,6 +503,7 @@ using namespace modsecurity::operators;
ACTION_CTL_BDY_XML "ACTION_CTL_BDY_XML"
ACTION_CTL_BDY_URLENCODED "ACTION_CTL_BDY_URLENCODED"
ACTION_CTL_FORCE_REQ_BODY_VAR "ACTION_CTL_FORCE_REQ_BODY_VAR"
ACTION_CTL_PARSE_XML_INTO_ARGS "ACTION_CTL_PARSE_XML_INTO_ARGS"
ACTION_CTL_REQUEST_BODY_ACCESS "ACTION_CTL_REQUEST_BODY_ACCESS"
ACTION_CTL_RULE_REMOVE_BY_ID "ACTION_CTL_RULE_REMOVE_BY_ID"
ACTION_CTL_RULE_REMOVE_BY_TAG "ACTION_CTL_RULE_REMOVE_BY_TAG"
@ -593,6 +595,7 @@ using namespace modsecurity::operators;
CONFIG_DIR_AUDIT_LOG2 "CONFIG_DIR_AUDIT_LOG2"
CONFIG_DIR_AUDIT_LOG_P "CONFIG_DIR_AUDIT_LOG_P"
CONFIG_DIR_AUDIT_STS "CONFIG_DIR_AUDIT_STS"
CONFIG_DIR_AUDIT_PREFIX "CONFIG_DIR_AUDIT_PREFIX"
CONFIG_DIR_AUDIT_TPE "CONFIG_DIR_AUDIT_TPE"
CONFIG_DIR_DEBUG_LOG "CONFIG_DIR_DEBUG_LOG"
CONFIG_DIR_DEBUG_LVL "CONFIG_DIR_DEBUG_LVL"
@ -649,6 +652,7 @@ using namespace modsecurity::operators;
CONFIG_VALUE_ABORT "CONFIG_VALUE_ABORT"
CONFIG_VALUE_DETC "CONFIG_VALUE_DETC"
CONFIG_VALUE_HTTPS "CONFIG_VALUE_HTTPS"
CONFIG_VALUE_ONLYARGS "CONFIG_VALUE_ONLYARGS"
CONFIG_VALUE_OFF "CONFIG_VALUE_OFF"
CONFIG_VALUE_ON "CONFIG_VALUE_ON"
CONFIG_VALUE_PARALLEL "CONFIG_VALUE_PARALLEL"
@ -658,6 +662,7 @@ using namespace modsecurity::operators;
CONFIG_VALUE_SERIAL "CONFIG_VALUE_SERIAL"
CONFIG_VALUE_WARN "CONFIG_VALUE_WARN"
CONFIG_XML_EXTERNAL_ENTITY "CONFIG_XML_EXTERNAL_ENTITY"
CONFIG_XML_PARSE_XML_INTO_ARGS "CONFIG_XML_PARSE_XML_INTO_ARGS"
CONGIG_DIR_RESPONSE_BODY_MP "CONGIG_DIR_RESPONSE_BODY_MP"
CONGIG_DIR_SEC_ARG_SEP "CONGIG_DIR_SEC_ARG_SEP"
CONGIG_DIR_SEC_COOKIE_FORMAT "CONGIG_DIR_SEC_COOKIE_FORMAT"
@ -797,6 +802,13 @@ audit_log:
driver.m_auditLog->setRelevantStatus(relevant_status);
}
/* SecAuditLogPrefix */
| CONFIG_DIR_AUDIT_PREFIX
{
std::string prefix($1);
driver.m_auditLog->setPrefix(prefix);
}
/* SecAuditLogType */
| CONFIG_DIR_AUDIT_TPE CONFIG_VALUE_SERIAL
{
@ -827,13 +839,19 @@ audit_log:
}
| CONFIG_UPLOAD_FILE_LIMIT
{
driver.m_uploadFileLimit.m_set = true;
driver.m_uploadFileLimit.m_value = strtol($1.c_str(), NULL, 10);
std::string errmsg = "";
if (driver.m_uploadFileLimit.parse(std::string($1), &errmsg) != true) {
driver.error(@0, "Failed to parse SecUploadFileLimit: " + errmsg);
YYERROR;
}
}
| CONFIG_UPLOAD_FILE_MODE
{
driver.m_uploadFileMode.m_set = true;
driver.m_uploadFileMode.m_value = strtol($1.c_str(), NULL, 8);
std::string errmsg = "";
if (driver.m_uploadFileMode.parse(std::string($1), &errmsg) != true) {
driver.error(@0, "Failed to parse SecUploadFileMode: " + errmsg);
YYERROR;
}
}
| CONFIG_UPLOAD_DIR
{
@ -1604,13 +1622,19 @@ expression:
/* Body limits */
| CONFIG_DIR_REQ_BODY_LIMIT
{
driver.m_requestBodyLimit.m_set = true;
driver.m_requestBodyLimit.m_value = atoi($1.c_str());
std::string errmsg = "";
if (driver.m_requestBodyLimit.parse(std::string($1), &errmsg) != true) {
driver.error(@0, "Failed to parse SecRequestBodyLimit: " + errmsg);
YYERROR;
}
}
| CONFIG_DIR_REQ_BODY_NO_FILES_LIMIT
{
driver.m_requestBodyNoFilesLimit.m_set = true;
driver.m_requestBodyNoFilesLimit.m_value = atoi($1.c_str());
std::string errmsg = "";
if (driver.m_requestBodyNoFilesLimit.parse(std::string($1), &errmsg) != true) {
driver.error(@0, "Failed to parse SecRequestsBodyNoFilesLimit: " + errmsg);
YYERROR;
}
}
| CONFIG_DIR_REQ_BODY_IN_MEMORY_LIMIT
{
@ -1623,8 +1647,11 @@ expression:
}
| CONFIG_DIR_RES_BODY_LIMIT
{
driver.m_responseBodyLimit.m_set = true;
driver.m_responseBodyLimit.m_value = atoi($1.c_str());
std::string errmsg = "";
if (driver.m_responseBodyLimit.parse(std::string($1), &errmsg) != true) {
driver.error(@0, "Failed to parse SecResponseBodyLimit: " + errmsg);
YYERROR;
}
}
| CONFIG_DIR_REQ_BODY_LIMIT_ACTION CONFIG_VALUE_PROCESS_PARTIAL
{
@ -1657,8 +1684,11 @@ expression:
*/
| CONFIG_DIR_PCRE_MATCH_LIMIT
{
driver.m_pcreMatchLimit.m_set = true;
driver.m_pcreMatchLimit.m_value = atoi($1.c_str());
std::string errmsg = "";
if (driver.m_pcreMatchLimit.parse(std::string($1), &errmsg) != true) {
driver.error(@0, "Failed to parse SecPcreMatchLimit: " + errmsg);
YYERROR;
}
}
| CONGIG_DIR_RESPONSE_BODY_MP
{
@ -1686,6 +1716,18 @@ expression:
{
driver.m_secXMLExternalEntity = modsecurity::RulesSetProperties::TrueConfigBoolean;
}
| CONFIG_XML_PARSE_XML_INTO_ARGS CONFIG_VALUE_ONLYARGS
{
driver.m_secXMLParseXmlIntoArgs = modsecurity::RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs;
}
| CONFIG_XML_PARSE_XML_INTO_ARGS CONFIG_VALUE_OFF
{
driver.m_secXMLParseXmlIntoArgs = modsecurity::RulesSetProperties::FalseConfigXMLParseXmlIntoArgs;
}
| CONFIG_XML_PARSE_XML_INTO_ARGS CONFIG_VALUE_ON
{
driver.m_secXMLParseXmlIntoArgs = modsecurity::RulesSetProperties::TrueConfigXMLParseXmlIntoArgs;
}
| CONGIG_DIR_SEC_TMP_DIR
{
/* Parser error disabled to avoid breaking default installations with modsecurity.conf-recommended
@ -2696,6 +2738,18 @@ act:
//ACTION_NOT_SUPPORTED("CtlForceReequestBody", @0);
ACTION_CONTAINER($$, new actions::Action($1));
}
| ACTION_CTL_PARSE_XML_INTO_ARGS CONFIG_VALUE_ON
{
ACTION_CONTAINER($$, new actions::ctl::ParseXmlIntoArgs("ctl:parseXmlIntoArgs=on"));
}
| ACTION_CTL_PARSE_XML_INTO_ARGS CONFIG_VALUE_OFF
{
ACTION_CONTAINER($$, new actions::ctl::ParseXmlIntoArgs("ctl:parseXmlIntoArgs=off"));
}
| ACTION_CTL_PARSE_XML_INTO_ARGS CONFIG_VALUE_ONLYARGS
{
ACTION_CONTAINER($$, new actions::ctl::ParseXmlIntoArgs("ctl:parseXmlIntoArgs=onlyargs"));
}
| ACTION_CTL_REQUEST_BODY_ACCESS CONFIG_VALUE_ON
{
ACTION_CONTAINER($$, new actions::ctl::RequestBodyAccess($1 + "true"));

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@ ACTION_CTL_BDY_JSON (?i:ctl:requestBodyProcessor=JSO
ACTION_CTL_BDY_XML (?i:ctl:requestBodyProcessor=XML)
ACTION_CTL_BDY_URLENCODED (?i:ctl:requestBodyProcessor=URLENCODED)
ACTION_CTL_FORCE_REQ_BODY_VAR (?i:ctl:forceRequestBodyVariable)
ACTION_CTL_PARSE_XML_INTO_ARGS (?i:ctl:parseXmlIntoArgs)
ACTION_CTL_REQUEST_BODY_ACCESS (?i:ctl:requestBodyAccess)
ACTION_CTL_RULE_ENGINE (?i:ctl:ruleEngine)
ACTION_CTL_RULE_REMOVE_BY_TAG (?i:ctl:ruleRemoveByTag)
@ -345,6 +346,7 @@ CONFIG_DIR_AUDIT_FLE_MOD (?i:SecAuditLogFileMode)
CONFIG_DIR_AUDIT_LOG2 (?i:SecAuditLog2)
CONFIG_DIR_AUDIT_LOG (?i:SecAuditLog)
CONFIG_DIR_AUDIT_LOG_FMT (?i:SecAuditLogFormat)
CONFIG_DIR_AUDIT_PREFIX (?i:SecAuditLogPrefix)
CONFIG_DIR_AUDIT_LOG_P (?i:SecAuditLogParts)
CONFIG_DIR_AUDIT_STS (?i:SecAuditLogRelevantStatus)
CONFIG_DIR_AUDIT_TPE (?i:SecAuditLogType)
@ -400,16 +402,18 @@ CONFIG_VALUE_ABORT (?i:Abort)
CONFIG_VALUE_DETC (?i:DetectionOnly)
CONFIG_VALUE_HTTPS (?i:https)
CONFIG_VALUE_NUMBER [0-9]+
CONFIG_VALUE_ONLYARGS (?i:OnlyArgs)
CONFIG_VALUE_OFF (?i:Off)
CONFIG_VALUE_ON (?i:On)
CONFIG_VALUE_PARALLEL (?i:Parallel|Concurrent)
CONFIG_VALUE_PATH [0-9A-Za-z_\/\.\-\*\:]+
CONFIG_VALUE_PATH (?i:[0-9a-z_/.*: \\()-]+)
CONFIG_VALUE_PROCESS_PARTIAL (?i:ProcessPartial)
CONFIG_VALUE_REJECT (?i:Reject)
CONFIG_VALUE_RELEVANT_ONLY (?i:RelevantOnly)
CONFIG_VALUE_SERIAL (?i:Serial)
CONFIG_VALUE_WARN (?i:Warn)
CONFIG_XML_EXTERNAL_ENTITY (?i:SecXmlExternalEntity)
CONFIG_XML_PARSE_XML_INTO_ARGS (?i:SecParseXmlIntoArgs)
CONGIG_DIR_RESPONSE_BODY_MP (?i:SecResponseBodyMimeType)
CONGIG_DIR_RESPONSE_BODY_MP_CLEAR (?i:SecResponseBodyMimeTypesClear)
CONGIG_DIR_SEC_ARG_SEP (?i:SecArgumentSeparator)
@ -537,6 +541,7 @@ EQUALS_MINUS (?i:=\-)
{ACTION_CTL_BDY_XML} { return p::make_ACTION_CTL_BDY_XML(yytext, *driver.loc.back()); }
{ACTION_CTL_BDY_URLENCODED} { return p::make_ACTION_CTL_BDY_URLENCODED(yytext, *driver.loc.back()); }
{ACTION_CTL_FORCE_REQ_BODY_VAR}= { return p::make_ACTION_CTL_FORCE_REQ_BODY_VAR(yytext, *driver.loc.back()); }
{ACTION_CTL_PARSE_XML_INTO_ARGS}= { return p::make_ACTION_CTL_PARSE_XML_INTO_ARGS(yytext, *driver.loc.back()); }
{ACTION_CTL_REQUEST_BODY_ACCESS}= { return p::make_ACTION_CTL_REQUEST_BODY_ACCESS(yytext, *driver.loc.back()); }
{ACTION_CTL_RULE_ENGINE}= { return p::make_ACTION_CTL_RULE_ENGINE(*driver.loc.back()); }
{ACTION_CTL_RULE_REMOVE_BY_ID}[=]{REMOVE_RULE_BY} { return p::make_ACTION_CTL_RULE_REMOVE_BY_ID(yytext, *driver.loc.back()); }
@ -609,6 +614,7 @@ EQUALS_MINUS (?i:=\-)
{ACTION_LOG_DATA}: { BEGIN(EXPECTING_ACTION_PREDICATE); return p::make_ACTION_LOG_DATA(yytext, *driver.loc.back()); }
{CONFIG_VALUE_DETC} { return p::make_CONFIG_VALUE_DETC(yytext, *driver.loc.back()); }
{CONFIG_VALUE_ONLYARGS} { return p::make_CONFIG_VALUE_ONLYARGS(yytext, *driver.loc.back()); }
{CONFIG_VALUE_OFF} { return p::make_CONFIG_VALUE_OFF(yytext, *driver.loc.back()); }
{CONFIG_VALUE_ON} { return p::make_CONFIG_VALUE_ON(yytext, *driver.loc.back()); }
{CONFIG_VALUE_RELEVANT_ONLY} { return p::make_CONFIG_VALUE_RELEVANT_ONLY(yytext, *driver.loc.back()); }
@ -759,6 +765,8 @@ EQUALS_MINUS (?i:=\-)
{CONFIG_DIR_AUDIT_LOG}[ \t]+["]{CONFIG_VALUE_PATH}["] { return p::make_CONFIG_DIR_AUDIT_LOG(parserSanitizer(strchr(yytext, ' ') + 1), *driver.loc.back()); }
{CONFIG_DIR_AUDIT_STS}[ \t]+{FREE_TEXT_NEW_LINE} { return p::make_CONFIG_DIR_AUDIT_STS(parserSanitizer(strchr(yytext, ' ') + 1), *driver.loc.back()); }
{CONFIG_DIR_AUDIT_STS}[ \t]+["]{NEW_LINE_FREE_TEXT}["] { return p::make_CONFIG_DIR_AUDIT_STS(parserSanitizer(strchr(yytext, ' ') + 1), *driver.loc.back()); }
{CONFIG_DIR_AUDIT_PREFIX}[ \t]+{FREE_TEXT_NEW_LINE} { return p::make_CONFIG_DIR_AUDIT_PREFIX(parserSanitizer(strchr(yytext, ' ') + 1), *driver.loc.back()); }
{CONFIG_DIR_AUDIT_PREFIX}[ \t]+["]{FREE_TEXT_NEW_LINE}["] { return p::make_CONFIG_DIR_AUDIT_PREFIX(parserSanitizer(strchr(yytext, ' ') + 1), *driver.loc.back()); }
{CONFIG_DIR_AUDIT_TPE} { return p::make_CONFIG_DIR_AUDIT_TPE(yytext, *driver.loc.back()); }
@ -805,6 +813,7 @@ EQUALS_MINUS (?i:=\-)
{CONFIG_VALUE_ABORT} { return p::make_CONFIG_VALUE_ABORT(yytext, *driver.loc.back()); }
{CONFIG_VALUE_DETC} { return p::make_CONFIG_VALUE_DETC(yytext, *driver.loc.back()); }
{CONFIG_VALUE_HTTPS} { return p::make_CONFIG_VALUE_HTTPS(yytext, *driver.loc.back()); }
{CONFIG_VALUE_ONLYARGS} { return p::make_CONFIG_VALUE_ONLYARGS(yytext, *driver.loc.back()); }
{CONFIG_VALUE_OFF} { return p::make_CONFIG_VALUE_OFF(yytext, *driver.loc.back()); }
{CONFIG_VALUE_ON} { return p::make_CONFIG_VALUE_ON(yytext, *driver.loc.back()); }
{CONFIG_VALUE_PARALLEL} { return p::make_CONFIG_VALUE_PARALLEL(yytext, *driver.loc.back()); }
@ -814,6 +823,7 @@ EQUALS_MINUS (?i:=\-)
{CONFIG_VALUE_SERIAL} { return p::make_CONFIG_VALUE_SERIAL(yytext, *driver.loc.back()); }
{CONFIG_VALUE_WARN} { return p::make_CONFIG_VALUE_WARN(yytext, *driver.loc.back()); }
{CONFIG_XML_EXTERNAL_ENTITY} { return p::make_CONFIG_XML_EXTERNAL_ENTITY(yytext, *driver.loc.back()); }
{CONFIG_XML_PARSE_XML_INTO_ARGS} { return p::make_CONFIG_XML_PARSE_XML_INTO_ARGS(yytext, *driver.loc.back()); }
{CONGIG_DIR_RESPONSE_BODY_MP}[ \t]+{FREE_TEXT_NEW_LINE} { return p::make_CONGIG_DIR_RESPONSE_BODY_MP(strchr(yytext, ' ') + 1, *driver.loc.back()); }
{CONGIG_DIR_RESPONSE_BODY_MP_CLEAR} { return p::make_CONGIG_DIR_RESPONSE_BODY_MP_CLEAR(*driver.loc.back()); }
{CONGIG_DIR_SEC_ARG_SEP}[ \t]+{FREE_TEXT_NEW_LINE} { return p::make_CONGIG_DIR_SEC_ARG_SEP(yytext, *driver.loc.back()); }

View File

@ -1638,7 +1638,7 @@ bool Multipart::process(const std::string& data, std::string *error,
}
} else { /* It looks like a boundary but */
/* we couldn't match it. */
char *p = NULL;
const char *p = NULL;
/* Check if an attempt to use quotes around the
* boundary was made. */

View File

@ -25,11 +25,138 @@ namespace RequestBodyProcessor {
#ifdef WITH_LIBXML2
/*
* NodeData for parsing XML into args
*/
NodeData::NodeData() {
has_child = false;
}
NodeData::~NodeData() {};
/*
* XMLNodes for parsing XML into args
*/
XMLNodes::XMLNodes(Transaction *transaction)
: nodes{},
node_depth(0),
currpath(""),
currval(""),
currval_is_set(false),
m_transaction(transaction)
{}
XMLNodes::~XMLNodes() {};
/*
* SAX handler for parsing XML into args
*/
class MSCSAXHandler {
public:
void onStartElement(void * ctx, const xmlChar *localname) {
std::string name = reinterpret_cast<const char*>(localname);
XMLNodes* xml_data = static_cast<XMLNodes*>(ctx);
xml_data->nodes.push_back(std::make_shared<NodeData>());
xml_data->node_depth++;
// FIXME - later if we want to check the depth of XML tree
/* if (max_depth > 0 && max_depth > xml_data->node_depth) {
std::cout << "Depth of XML tree reached the given maximum value " << xml_data->node_depth << std::endl;
exit(1);
} */
// if it's not the first (root) item, then append a '.'
// note, the condition should always be true because there is always a pseudo root element: 'xml'
if (xml_data->nodes.size() > 1) {
xml_data->currpath.append(".");
xml_data->nodes[xml_data->nodes.size()-2]->has_child = true;
}
xml_data->currpath.append(name);
// set the current value empty
// this is necessary because if there is any text between the tags (new line, etc)
// it will be added to the current value
xml_data->currval = "";
xml_data->currval_is_set = false;
}
void onEndElement(void * ctx, const xmlChar *localname) {
std::string name = reinterpret_cast<const char*>(localname);
XMLNodes* xml_data = static_cast<XMLNodes*>(ctx);
const std::shared_ptr<NodeData>& nd = xml_data->nodes[xml_data->nodes.size()-1];
if (nd->has_child == false) {
// check the return value
// if false, then stop parsing
// this means the number of arguments reached the limit
if (xml_data->m_transaction->addArgument("XML", xml_data->currpath, xml_data->currval, 0) == false) {
xmlStopParser(xml_data->parsing_ctx_arg);
}
}
if (xml_data->currpath.length() > 0) {
// set an offset to store whether this is the first item, in order to know whether to remove the '.'
int offset = (xml_data->nodes.size() > 1) ? 1 : 0;
xml_data->currpath.erase(xml_data->currpath.length() - (name.length()+offset));
}
xml_data->nodes.pop_back();
xml_data->node_depth--;
xml_data->currval = "";
xml_data->currval_is_set = false;
}
void onCharacters(void *ctx, const xmlChar *ch, int len) {
XMLNodes* xml_data = static_cast<XMLNodes*>(ctx);
std::string content(reinterpret_cast<const char *>(ch), len);
// libxml2 SAX parser will call this function multiple times
// during the parsing of a single node, if the value has multibyte
// characters, so we need to concatenate the values
if (xml_data->currval_is_set == false) {
xml_data->currval = content;
xml_data->currval_is_set = true;
} else {
xml_data->currval += content;
}
}
};
extern "C" {
void MSC_startElement(void *userData,
const xmlChar *name,
const xmlChar *prefix,
const xmlChar *URI,
int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int nb_defaulted,
const xmlChar **attributes) {
MSCSAXHandler* handler = static_cast<MSCSAXHandler*>(userData);
handler->onStartElement(userData, name);
}
void MSC_endElement(
void *userData,
const xmlChar *name,
const xmlChar* prefix,
const xmlChar* URI) {
MSCSAXHandler* handler = static_cast<MSCSAXHandler*>(userData);
handler->onEndElement(userData, name);
}
void MSC_xmlcharacters(void *userData, const xmlChar *ch, int len) {
MSCSAXHandler* handler = static_cast<MSCSAXHandler*>(userData);
handler->onCharacters(userData, ch, len);
}
}
XML::XML(Transaction *transaction)
: m_transaction(transaction) {
m_data.doc = NULL;
m_data.parsing_ctx = NULL;
m_data.sax_handler = NULL;
m_data.xml_error = "";
m_data.parsing_ctx_arg = NULL;
m_data.xml_parser_state = NULL;
}
@ -44,7 +171,6 @@ XML::~XML() {
}
}
bool XML::init() {
//xmlParserInputBufferCreateFilenameFunc entity;
if (m_transaction->m_rules->m_secXMLExternalEntity
@ -55,6 +181,28 @@ bool XML::init() {
/*entity = */xmlParserInputBufferCreateFilenameDefault(
this->unloadExternalEntity);
}
if (m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::TrueConfigXMLParseXmlIntoArgs ||
m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) {
ms_dbg_a(m_transaction, 9,
"XML: SecParseXmlIntoArgs is set to " \
+ RulesSetProperties::configXMLParseXmlIntoArgsString(static_cast<RulesSetProperties::ConfigXMLParseXmlIntoArgs>(m_transaction->m_secXMLParseXmlIntoArgs)));
m_data.sax_handler = std::make_unique<xmlSAXHandler>();
memset(m_data.sax_handler.get(), 0, sizeof(xmlSAXHandler));
m_data.sax_handler->initialized = XML_SAX2_MAGIC;
m_data.sax_handler->startElementNs = &MSC_startElement;
m_data.sax_handler->endElementNs = &MSC_endElement;
m_data.sax_handler->characters = &MSC_xmlcharacters;
// set the parser state struct
m_data.xml_parser_state = std::make_unique<XMLNodes>(m_transaction);
m_data.xml_parser_state->node_depth = 0;
m_data.xml_parser_state->currval = "";
// the XML will contain at least one node, which is the pseudo root node 'xml'
m_data.xml_parser_state->currpath = "xml.";
}
return true;
}
@ -72,7 +220,7 @@ bool XML::processChunk(const char *buf, unsigned int size,
* enable us to pass it the first chunk of data so that
* it can attempt to auto-detect the encoding.
*/
if (m_data.parsing_ctx == NULL) {
if (m_data.parsing_ctx == NULL && m_data.parsing_ctx_arg == NULL) {
/* First invocation. */
ms_dbg_a(m_transaction, 4, "XML: Initialising parser.");
@ -90,27 +238,67 @@ bool XML::processChunk(const char *buf, unsigned int size,
*/
m_data.parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL,
buf, size, "body.xml");
if (m_transaction->m_secXMLParseXmlIntoArgs
!= RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) {
m_data.parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL,
buf, size, "body.xml");
if (m_data.parsing_ctx == NULL) {
ms_dbg_a(m_transaction, 4,
"XML: Failed to create parsing context.");
error->assign("XML: Failed to create parsing context.");
return false;
if (m_data.parsing_ctx == NULL) {
ms_dbg_a(m_transaction, 4,
"XML: Failed to create parsing context.");
error->assign("XML: Failed to create parsing context.");
return false;
}
}
xmlSetGenericErrorFunc(m_data.parsing_ctx, null_error);
if (m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs ||
m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::TrueConfigXMLParseXmlIntoArgs) {
m_data.parsing_ctx_arg = xmlCreatePushParserCtxt(
m_data.sax_handler.get(),
m_data.xml_parser_state.get(),
buf,
size,
NULL);
if (m_data.parsing_ctx_arg == NULL) {
error->assign("XML: Failed to create parsing context for ARGS.");
return false;
}
}
return true;
}
/* Not a first invocation. */
xmlParseChunk(m_data.parsing_ctx, buf, size, 0);
if (m_data.parsing_ctx->wellFormed != 1) {
error->assign("XML: Failed to create parsing context.");
ms_dbg_a(m_transaction, 4, "XML: Failed parsing document.");
return false;
if (m_data.parsing_ctx != NULL &&
m_transaction->m_secXMLParseXmlIntoArgs
!= RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) {
xmlSetGenericErrorFunc(m_data.parsing_ctx, null_error);
xmlParseChunk(m_data.parsing_ctx, buf, size, 0);
m_data.xml_parser_state->parsing_ctx_arg = m_data.parsing_ctx_arg;
if (m_data.parsing_ctx->wellFormed != 1) {
error->assign("XML: Failed to parse document.");
ms_dbg_a(m_transaction, 4, "XML: Failed to parse document.");
return false;
}
}
if (m_data.parsing_ctx_arg != NULL &&
(
m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs
||
m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::TrueConfigXMLParseXmlIntoArgs)
) {
xmlSetGenericErrorFunc(m_data.parsing_ctx_arg, null_error);
xmlParseChunk(m_data.parsing_ctx_arg, buf, size, 0);
if (m_data.parsing_ctx_arg->wellFormed != 1) {
error->assign("XML: Failed to parse document for ARGS.");
ms_dbg_a(m_transaction, 4, "XML: Failed to parse document for ARGS.");
return false;
}
}
return true;
@ -119,24 +307,51 @@ bool XML::processChunk(const char *buf, unsigned int size,
bool XML::complete(std::string *error) {
/* Only if we have a context, meaning we've done some work. */
if (m_data.parsing_ctx != NULL) {
/* This is how we signalise the end of parsing to libxml. */
xmlParseChunk(m_data.parsing_ctx, NULL, 0, 1);
if (m_data.parsing_ctx != NULL || m_data.parsing_ctx_arg != NULL) {
if (m_data.parsing_ctx != NULL &&
m_transaction->m_secXMLParseXmlIntoArgs
!= RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) {
/* This is how we signal the end of parsing to libxml. */
xmlParseChunk(m_data.parsing_ctx, NULL, 0, 1);
/* Preserve the results for our reference. */
m_data.well_formed = m_data.parsing_ctx->wellFormed;
m_data.doc = m_data.parsing_ctx->myDoc;
/* Preserve the results for our reference. */
m_data.well_formed = m_data.parsing_ctx->wellFormed;
m_data.doc = m_data.parsing_ctx->myDoc;
/* Clean up everything else. */
xmlFreeParserCtxt(m_data.parsing_ctx);
m_data.parsing_ctx = NULL;
ms_dbg_a(m_transaction, 4, "XML: Parsing complete (well_formed " \
+ std::to_string(m_data.well_formed) + ").");
/* Clean up everything else. */
xmlFreeParserCtxt(m_data.parsing_ctx);
m_data.parsing_ctx = NULL;
ms_dbg_a(m_transaction, 4, "XML: Parsing complete (well_formed " \
+ std::to_string(m_data.well_formed) + ").");
if (m_data.well_formed != 1) {
error->assign("XML: Failed parsing document.");
ms_dbg_a(m_transaction, 4, "XML: Failed parsing document.");
return false;
if (m_data.well_formed != 1) {
error->assign("XML: Failed to parse document.");
ms_dbg_a(m_transaction, 4, "XML: Failed to parse document.");
return false;
}
}
if (m_data.parsing_ctx_arg != NULL &&
(
m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs
||
m_transaction->m_secXMLParseXmlIntoArgs
== RulesSetProperties::TrueConfigXMLParseXmlIntoArgs)
) {
/* This is how we signale the end of parsing to libxml. */
if (xmlParseChunk(m_data.parsing_ctx_arg, NULL, 0, 1) != 0) {
if (m_data.xml_error != "") {
error->assign(m_data.xml_error);
}
else {
error->assign("XML: Failed to parse document for ARGS.");
}
xmlFreeParserCtxt(m_data.parsing_ctx_arg);
m_data.parsing_ctx_arg = NULL;
return false;
}
xmlFreeParserCtxt(m_data.parsing_ctx_arg);
m_data.parsing_ctx_arg = NULL;
}
}

View File

@ -16,6 +16,7 @@
#ifdef WITH_LIBXML2
#include <libxml/xmlschemas.h>
#include <libxml/xpath.h>
#include <libxml/SAX.h>
#endif
#include <string>
@ -33,12 +34,51 @@ namespace RequestBodyProcessor {
#ifdef WITH_LIBXML2
/*
* NodeData for parsing XML into args
*/
class NodeData {
public:
explicit NodeData();
~NodeData();
bool has_child;
};
/*
* XMLNodes for parsing XML into args
*/
class XMLNodes {
public:
std::vector<std::shared_ptr<NodeData>> nodes;
unsigned long int node_depth;
std::string currpath;
std::string currval;
bool currval_is_set;
Transaction *m_transaction;
// need to store context - this is the same as in xml_data
// need to stop parsing if the number of arguments reached the limit
xmlParserCtxtPtr parsing_ctx_arg;
explicit XMLNodes (Transaction *);
~XMLNodes();
};
struct xml_data {
xmlSAXHandler *sax_handler;
std::unique_ptr<xmlSAXHandler> sax_handler;
xmlParserCtxtPtr parsing_ctx;
xmlDocPtr doc;
unsigned int well_formed;
/* error reporting and XML array flag */
std::string xml_error;
/* additional parser context for arguments */
xmlParserCtxtPtr parsing_ctx_arg;
/* parser state for SAX parser */
std::unique_ptr<XMLNodes> xml_parser_state;
};
typedef struct xml_data xml_data;

View File

@ -90,17 +90,6 @@ void RuleWithOperator::updateMatchedVars(Transaction *trans, const std::string &
}
void RuleWithOperator::cleanMatchedVars(Transaction *trans) {
ms_dbg_a(trans, 9, "Matched vars cleaned.");
// cppcheck-suppress ctunullpointer
trans->m_variableMatchedVar.unset();
trans->m_variableMatchedVars.unset();
trans->m_variableMatchedVarName.unset();
trans->m_variableMatchedVarsNames.unset();
}
bool RuleWithOperator::executeOperatorAt(Transaction *trans, const std::string &key,
const std::string &value, RuleMessage &ruleMessage) {
#if MSC_EXEC_CLOCK_ENABLED
@ -324,7 +313,6 @@ bool RuleWithOperator::evaluate(Transaction *trans,
if (globalRet == false) {
ms_dbg_a(trans, 4, "Rule returned 0.");
cleanMatchedVars(trans);
goto end_clean;
}
ms_dbg_a(trans, 4, "Rule returned 1.");

View File

@ -58,7 +58,7 @@ bool RulesExceptions::loadUpdateActionById(double id,
bool RulesExceptions::loadRemoveRuleByMsg(const std::string &msg,
std::string *error) {
const std::string *error) {
m_remove_rule_by_msg.push_back(msg);
return true;
@ -66,7 +66,7 @@ bool RulesExceptions::loadRemoveRuleByMsg(const std::string &msg,
bool RulesExceptions::loadRemoveRuleByTag(const std::string &msg,
std::string *error) {
const std::string *error) {
m_remove_rule_by_tag.push_back(msg);
return true;

View File

@ -105,6 +105,14 @@ std::string RulesSet::getParserError() {
return this->m_parserError.str();
}
void RulesSet::cleanMatchedVars(Transaction *trans) {
ms_dbg_a(trans, 9, "Matched vars cleaned.");
// cppcheck-suppress ctunullpointer
trans->m_variableMatchedVar.unset();
trans->m_variableMatchedVars.unset();
trans->m_variableMatchedVarName.unset();
trans->m_variableMatchedVarsNames.unset();
}
int RulesSet::evaluate(int phase, Transaction *t) {
if (phase >= modsecurity::Phases::NUMBER_OF_PHASES) {
@ -208,6 +216,7 @@ int RulesSet::evaluate(int phase, Transaction *t) {
}
rule->evaluate(t);
cleanMatchedVars(t);
if (t->m_it.disruptive > 0) {
ms_dbg_a(t, 8, "Skipping this phase as this " \

View File

@ -148,6 +148,7 @@ Transaction::Transaction(ModSecurity *ms, RulesSet *rules, const char *id,
m_json(nullptr),
#endif
m_secRuleEngine(RulesSetProperties::PropertyNotSetRuleEngine),
m_secXMLParseXmlIntoArgs(rules->m_secXMLParseXmlIntoArgs),
m_logCbData(logCbData),
TransactionAnchoredVariables(this) {
m_variableUrlEncodedError.set("0", 0);
@ -1451,7 +1452,7 @@ std::string Transaction::toOldAuditLogFormatIndex(const std::string &filename,
std::string Transaction::toOldAuditLogFormat(int parts,
const std::string &trailer) {
const std::string &trailer, const std::string &prefix) {
std::stringstream audit_log;
struct tm timeinfo;
@ -1460,7 +1461,8 @@ std::string Transaction::toOldAuditLogFormat(int parts,
char tstr[std::size("[dd/Mmm/yyyy:hh:mm:ss shhmm]")];
strftime(tstr, std::size(tstr), "[%d/%b/%Y:%H:%M:%S %z]", &timeinfo);
audit_log << "--" << trailer << "-" << "A--" << std::endl;
audit_log << prefix << "--" << trailer << "-" << "A--" << std::endl;
audit_log << prefix;
audit_log << tstr;
audit_log << " " << m_id;
audit_log << " " << this->m_clientIpAddress;
@ -1471,7 +1473,8 @@ std::string Transaction::toOldAuditLogFormat(int parts,
if (parts & audit_log::AuditLog::BAuditLogPart) {
std::vector<const VariableValue *> l;
audit_log << "--" << trailer << "-" << "B--" << std::endl;
audit_log << prefix << "--" << trailer << "-" << "B--" << std::endl;
audit_log << prefix;
audit_log << utils::string::dash_if_empty(
m_variableRequestMethod.evaluate());
audit_log << " " << this->m_uri.c_str() << " " << "HTTP/";
@ -1480,79 +1483,81 @@ std::string Transaction::toOldAuditLogFormat(int parts,
m_variableRequestHeaders.resolve(&l);
for (auto &h : l) {
size_t pos = strlen("REQUEST_HEADERS:");
audit_log << prefix;
audit_log << h->getKeyWithCollection().c_str() + pos << ": ";
audit_log << h->getValue().c_str() << std::endl;
delete h;
}
audit_log << std::endl;
audit_log << prefix << std::endl;
}
if (parts & audit_log::AuditLog::CAuditLogPart
&& m_requestBody.tellp() > 0) {
std::string body = m_requestBody.str();
audit_log << "--" << trailer << "-" << "C--" << std::endl;
audit_log << prefix << "--" << trailer << "-" << "C--" << std::endl;
if (body.size() > 0) {
audit_log << body << std::endl;
audit_log << prefix << body << std::endl;
}
audit_log << std::endl;
audit_log << prefix << std::endl;
}
if (parts & audit_log::AuditLog::DAuditLogPart) {
audit_log << "--" << trailer << "-" << "D--" << std::endl;
audit_log << std::endl;
audit_log << prefix << "--" << trailer << "-" << "D--" << std::endl;
audit_log << prefix << std::endl;
/** TODO: write audit_log D part. */
}
if (parts & audit_log::AuditLog::EAuditLogPart
&& m_responseBody.tellp() > 0) {
std::string body = utils::string::toHexIfNeeded(m_responseBody.str());
audit_log << "--" << trailer << "-" << "E--" << std::endl;
audit_log << prefix << "--" << trailer << "-" << "E--" << std::endl;
if (body.size() > 0) {
audit_log << body << std::endl;
audit_log << prefix << body << std::endl;
}
audit_log << std::endl;
audit_log << prefix << std::endl;
}
if (parts & audit_log::AuditLog::FAuditLogPart) {
std::vector<const VariableValue *> l;
audit_log << "--" << trailer << "-" << "F--" << std::endl;
audit_log << "HTTP/" << m_httpVersion.c_str() << " ";
audit_log << prefix << "--" << trailer << "-" << "F--" << std::endl;
audit_log << prefix << "HTTP/" << m_httpVersion.c_str() << " ";
audit_log << this->m_httpCodeReturned << std::endl;
m_variableResponseHeaders.resolve(&l);
for (auto &h : l) {
audit_log << prefix;
audit_log << h->getKey().c_str() << ": ";
audit_log << h->getValue().c_str() << std::endl;
delete h;
}
}
audit_log << std::endl;
audit_log << prefix << std::endl;
if (parts & audit_log::AuditLog::GAuditLogPart) {
audit_log << "--" << trailer << "-" << "G--" << std::endl;
audit_log << prefix << "--" << trailer << "-" << "G--" << std::endl;
audit_log << std::endl;
/** TODO: write audit_log G part. */
}
if (parts & audit_log::AuditLog::HAuditLogPart) {
audit_log << "--" << trailer << "-" << "H--" << std::endl;
audit_log << prefix << "--" << trailer << "-" << "H--" << std::endl;
for (const auto &a : m_rulesMessages) {
audit_log << a.log(0, m_httpCodeReturned) << std::endl;
audit_log << prefix << a.log(0, m_httpCodeReturned) << std::endl;
}
audit_log << std::endl;
audit_log << prefix << std::endl;
/** TODO: write audit_log H part. */
}
if (parts & audit_log::AuditLog::IAuditLogPart) {
audit_log << "--" << trailer << "-" << "I--" << std::endl;
audit_log << std::endl;
audit_log << prefix << "--" << trailer << "-" << "I--" << std::endl;
audit_log << prefix << std::endl;
/** TODO: write audit_log I part. */
}
if (parts & audit_log::AuditLog::JAuditLogPart) {
audit_log << "--" << trailer << "-" << "J--" << std::endl;
audit_log << std::endl;
audit_log << prefix << "--" << trailer << "-" << "J--" << std::endl;
audit_log << prefix << std::endl;
/** TODO: write audit_log J part. */
}
if (parts & audit_log::AuditLog::KAuditLogPart) {
audit_log << "--" << trailer << "-" << "K--" << std::endl;
audit_log << std::endl;
audit_log << prefix << "--" << trailer << "-" << "K--" << std::endl;
audit_log << prefix << std::endl;
/** TODO: write audit_log K part. */
}
audit_log << "--" << trailer << "-" << "Z--" << std::endl << std::endl;
audit_log << prefix << "--" << trailer << "-" << "Z--" << std::endl << std::endl;
return audit_log.str();
}
@ -1564,7 +1569,7 @@ std::string Transaction::toJSON(int parts) {
size_t len;
yajl_gen g;
std::string log;
std::string ts = utils::string::ascTime(&m_timeStamp).c_str();
std::string ts = utils::string::ascTime(&m_timeStamp);
std::string uniqueId = UniqueId::uniqueId();
g = yajl_gen_alloc(NULL);
@ -1582,13 +1587,13 @@ std::string Transaction::toJSON(int parts) {
yajl_gen_map_open(g);
/* Part: A (header mandatory) */
LOGFY_ADD("client_ip", m_clientIpAddress.c_str());
LOGFY_ADD("time_stamp", ts.c_str());
LOGFY_ADD("server_id", uniqueId.c_str());
LOGFY_ADD("client_ip", m_clientIpAddress);
LOGFY_ADD("time_stamp", ts);
LOGFY_ADD("server_id", uniqueId);
LOGFY_ADD_NUM("client_port", m_clientPort);
LOGFY_ADD("host_ip", m_serverIpAddress.c_str());
LOGFY_ADD("host_ip", m_serverIpAddress);
LOGFY_ADD_NUM("host_port", m_serverPort);
LOGFY_ADD("unique_id", m_id.c_str());
LOGFY_ADD("unique_id", m_id);
/* request */
yajl_gen_string(g, reinterpret_cast<const unsigned char*>("request"),
@ -1597,14 +1602,15 @@ std::string Transaction::toJSON(int parts) {
LOGFY_ADD("method",
utils::string::dash_if_empty(
m_variableRequestMethod.evaluate()).c_str());
m_variableRequestMethod.evaluate()));
LOGFY_ADD_INT("http_version", m_httpVersion.c_str());
LOGFY_ADD("uri", this->m_uri.c_str());
LOGFY_ADD("http_version", m_httpVersion);
LOGFY_ADD("hostname", m_requestHostName);
LOGFY_ADD("uri", this->m_uri);
if (parts & audit_log::AuditLog::CAuditLogPart) {
// FIXME: check for the binary content size.
LOGFY_ADD("body", this->m_requestBody.str().c_str());
LOGFY_ADD("body", this->m_requestBody.str());
}
/* request headers */
@ -1616,7 +1622,7 @@ std::string Transaction::toJSON(int parts) {
m_variableRequestHeaders.resolve(&l);
for (auto &h : l) {
LOGFY_ADD(h->getKey().c_str(), h->getValue().c_str());
LOGFY_ADD(h->getKey().c_str(), h->getValue());
delete h;
}
@ -1633,7 +1639,7 @@ std::string Transaction::toJSON(int parts) {
yajl_gen_map_open(g);
if (parts & audit_log::AuditLog::EAuditLogPart) {
LOGFY_ADD("body", this->m_responseBody.str().c_str());
LOGFY_ADD("body", this->m_responseBody.str());
}
LOGFY_ADD_NUM("http_code", m_httpCodeReturned);
@ -1646,7 +1652,7 @@ std::string Transaction::toJSON(int parts) {
m_variableResponseHeaders.resolve(&l);
for (auto &h : l) {
LOGFY_ADD(h->getKey().c_str(), h->getValue().c_str());
LOGFY_ADD(h->getKey().c_str(), h->getValue());
delete h;
}
@ -1663,10 +1669,10 @@ std::string Transaction::toJSON(int parts) {
yajl_gen_map_open(g);
/* producer > libmodsecurity */
LOGFY_ADD("modsecurity", m_ms->whoAmI().c_str());
LOGFY_ADD("modsecurity", m_ms->whoAmI());
/* producer > connector */
LOGFY_ADD("connector", m_ms->getConnectorInformation().c_str());
LOGFY_ADD("connector", m_ms->getConnectorInformation());
/* producer > engine state */
LOGFY_ADD("secrules_engine",
@ -1682,7 +1688,7 @@ std::string Transaction::toJSON(int parts) {
for (const auto &a : m_rules->m_components) {
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>
(a.c_str()), a.length());
(a.data()), a.length());
}
yajl_gen_array_close(g);
@ -1696,20 +1702,20 @@ std::string Transaction::toJSON(int parts) {
yajl_gen_array_open(g);
for (auto a : m_rulesMessages) {
yajl_gen_map_open(g);
LOGFY_ADD("message", a.m_message.c_str());
LOGFY_ADD("message", a.m_message);
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>("details"),
strlen("details"));
yajl_gen_map_open(g);
LOGFY_ADD("match", a.m_match.c_str());
LOGFY_ADD("reference", a.m_reference.c_str());
LOGFY_ADD("ruleId", std::to_string(a.m_rule.m_ruleId).c_str());
LOGFY_ADD("file", a.m_rule.getFileName().c_str());
LOGFY_ADD("lineNumber", std::to_string(a.m_rule.getLineNumber()).c_str());
LOGFY_ADD("data", a.m_data.c_str());
LOGFY_ADD("severity", std::to_string(a.m_severity).c_str());
LOGFY_ADD("ver", a.m_rule.m_ver.c_str());
LOGFY_ADD("rev", a.m_rule.m_rev.c_str());
LOGFY_ADD("match", a.m_match);
LOGFY_ADD("reference", a.m_reference);
LOGFY_ADD("ruleId", std::to_string(a.m_rule.m_ruleId));
LOGFY_ADD("file", a.m_rule.getFileName());
LOGFY_ADD("lineNumber", std::to_string(a.m_rule.getLineNumber()));
LOGFY_ADD("data", a.m_data);
LOGFY_ADD("severity", std::to_string(a.m_severity));
LOGFY_ADD("ver", a.m_rule.m_ver);
LOGFY_ADD("rev", a.m_rule.m_rev);
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>("tags"),
@ -1717,13 +1723,13 @@ std::string Transaction::toJSON(int parts) {
yajl_gen_array_open(g);
for (auto b : a.m_tags) {
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>(b.c_str()),
strlen(b.c_str()));
reinterpret_cast<const unsigned char*>(b.data()),
b.length());
}
yajl_gen_array_close(g);
LOGFY_ADD("maturity", std::to_string(a.m_rule.m_maturity).c_str());
LOGFY_ADD("accuracy", std::to_string(a.m_rule.m_accuracy).c_str());
LOGFY_ADD("maturity", std::to_string(a.m_rule.m_maturity));
LOGFY_ADD("accuracy", std::to_string(a.m_rule.m_accuracy));
yajl_gen_map_close(g);
yajl_gen_map_close(g);
}

View File

@ -134,7 +134,7 @@ std::string UniqueId::ethernetMacAddress() {
(unsigned char)LLADDR(sdl)[3],
(unsigned char)LLADDR(sdl)[4],
(unsigned char)LLADDR(sdl)[5]);
goto end;
break;
}
}
@ -177,7 +177,7 @@ std::string UniqueId::ethernetMacAddress() {
(unsigned char)ifr->ifr_addr.sa_data[4],
(unsigned char)ifr->ifr_addr.sa_data[5]);
goto end;
break;
}
}
close(sock);
@ -219,7 +219,7 @@ std::string UniqueId::ethernetMacAddress() {
(unsigned char)pAdapter->Address[3],
(unsigned char)pAdapter->Address[4],
(unsigned char)pAdapter->Address[5]);
goto end;
break;
}
pAdapter = pAdapter->Next;
}
@ -227,9 +227,6 @@ std::string UniqueId::ethernetMacAddress() {
free(pAdapterInfo);
#endif
#if defined(__linux__) || defined(__gnu_linux__) || defined(DARWIN) || defined(WIN32)
end:
#endif
return std::string(reinterpret_cast<const char *>(mac));
#if defined(__linux__) || defined(__gnu_linux__) || defined(DARWIN) || defined(WIN32)
failed:

View File

@ -226,7 +226,7 @@ static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
/* We have array with all children of the node and number of those children
*/
for (i = 0; i < count - 1; i++)
for (i = 0; i < count - 1; i++) {
for (j = i + 1; j < count; j++) {
acmp_node_t *tmp;
@ -236,10 +236,11 @@ static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
nodes[i] = nodes[j];
nodes[j] = tmp;
}
if (node->btree != NULL) {
free(node->btree);
node->btree = NULL;
}
}
if (node->btree != NULL) {
free(node->btree);
node->btree = NULL;
}
node->btree = reinterpret_cast<acmp_btree_node_t *>(calloc(1, sizeof(acmp_btree_node_t)));
/* ENH: Check alloc succeded */

View File

@ -110,15 +110,18 @@ bool HttpsClient::download(const std::string &uri) {
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "ModSecurity3");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers_chunk);
/* We want Curl to return error in case there is an HTTP error code */
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
if (m_requestBody.empty() == false) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, m_requestBody.c_str());
headers_chunk = curl_slist_append(headers_chunk, "Expect:"); // Disable Expect: 100-continue
}
/* set HTTP headers for request */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers_chunk);
res = curl_easy_perform(curl);
curl_slist_free_all(headers_chunk);

View File

@ -23,7 +23,7 @@
#include "src/utils/geo_lookup.h"
#ifndef WITH_PCRE2
#ifdef WITH_PCRE
#if PCRE_HAVE_JIT
// NOTE: Add PCRE_STUDY_EXTRA_NEEDED so studying always yields a pcre_extra strucure
// and we can selectively override match limits using a copy of that structure at runtime.
@ -35,11 +35,11 @@
#endif
#endif
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
class Pcre2MatchContextPtr {
public:
Pcre2MatchContextPtr()
: m_match_context(pcre2_match_context_create(NULL)) {}
: m_match_context(pcre2_match_context_create(nullptr)) {}
Pcre2MatchContextPtr(const Pcre2MatchContextPtr&) = delete;
Pcre2MatchContextPtr& operator=(const Pcre2MatchContextPtr&) = delete;
@ -48,7 +48,7 @@ class Pcre2MatchContextPtr {
pcre2_match_context_free(m_match_context);
}
operator pcre2_match_context*() const {
explicit operator pcre2_match_context*() const {
return m_match_context;
}
@ -62,7 +62,7 @@ namespace Utils {
// Helper function to tell us if the current config indicates CRLF is a valid newline sequence
bool crlfIsNewline() {
#if WITH_PCRE2
#ifndef WITH_PCRE
uint32_t newline = 0;
pcre2_config(PCRE2_CONFIG_NEWLINE, &newline);
bool crlf_is_newline =
@ -89,7 +89,7 @@ bool crlfIsNewline() {
Regex::Regex(const std::string& pattern_, bool ignoreCase)
: pattern(pattern_.empty() ? ".*" : pattern_) {
#if WITH_PCRE2
#ifndef WITH_PCRE
PCRE2_SPTR pcre2_pattern = reinterpret_cast<PCRE2_SPTR>(pattern.c_str());
uint32_t pcre2_options = (PCRE2_DOTALL|PCRE2_MULTILINE);
if (ignoreCase) {
@ -98,10 +98,10 @@ Regex::Regex(const std::string& pattern_, bool ignoreCase)
int errornumber = 0;
PCRE2_SIZE erroroffset = 0;
m_pc = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
pcre2_options, &errornumber, &erroroffset, NULL);
pcre2_options, &errornumber, &erroroffset, nullptr);
m_pcje = pcre2_jit_compile(m_pc, PCRE2_JIT_COMPLETE);
#else
const char *errptr = NULL;
const char *errptr = nullptr;
int erroffset;
int flags = (PCRE_DOTALL|PCRE_MULTILINE);
@ -109,7 +109,7 @@ Regex::Regex(const std::string& pattern_, bool ignoreCase)
flags |= PCRE_CASELESS;
}
m_pc = pcre_compile(pattern.c_str(), flags,
&errptr, &erroffset, NULL);
&errptr, &erroffset, nullptr);
m_pce = pcre_study(m_pc, pcre_study_opt, &errptr);
#endif
@ -117,20 +117,20 @@ Regex::Regex(const std::string& pattern_, bool ignoreCase)
Regex::~Regex() {
#if WITH_PCRE2
#ifndef WITH_PCRE
pcre2_code_free(m_pc);
#else
if (m_pc != NULL) {
if (m_pc != nullptr) {
pcre_free(m_pc);
m_pc = NULL;
m_pc = nullptr;
}
if (m_pce != NULL) {
if (m_pce != nullptr) {
#if PCRE_HAVE_JIT
pcre_free_study(m_pce);
#else
pcre_free(m_pce);
#endif
m_pce = NULL;
m_pce = nullptr;
}
#endif
}
@ -139,20 +139,20 @@ Regex::~Regex() {
std::list<SMatch> Regex::searchAll(const std::string& s) const {
std::list<SMatch> retList;
int rc = 0;
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
PCRE2_SIZE offset = 0;
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, nullptr);
do {
if (m_pcje == 0) {
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(),
offset, 0, match_data, NULL);
offset, 0, match_data, nullptr);
}
if (m_pcje != 0 || rc == PCRE2_ERROR_JIT_STACKLIMIT) {
rc = pcre2_match(m_pc, pcre2_s, s.length(),
offset, PCRE2_NO_JIT, match_data, NULL);
offset, PCRE2_NO_JIT, match_data, nullptr);
}
const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
#else
@ -183,29 +183,29 @@ std::list<SMatch> Regex::searchAll(const std::string& s) const {
}
} while (rc > 0);
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre2_match_data_free(match_data);
#endif
return retList;
}
RegexResult Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit) const {
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
Pcre2MatchContextPtr match_context;
if (match_limit > 0) {
// TODO: What if setting the match limit fails?
pcre2_set_match_limit(match_context, match_limit);
pcre2_set_match_limit(static_cast<pcre2_match_context*>(match_context), match_limit);
}
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, nullptr);
int rc = 0;
if (m_pcje == 0) {
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(), 0, 0, match_data, match_context);
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(), 0, 0, match_data, static_cast<pcre2_match_context*>(match_context));
}
if (m_pcje != 0 || rc == PCRE2_ERROR_JIT_STACKLIMIT) {
rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, PCRE2_NO_JIT, match_data, match_context);
rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, PCRE2_NO_JIT, match_data, static_cast<pcre2_match_context*>(match_context));
}
const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
#else
@ -214,7 +214,7 @@ RegexResult Regex::searchOneMatch(const std::string& s, std::vector<SMatchCaptur
pcre_extra local_pce;
pcre_extra *pce = m_pce;
if (m_pce != NULL && match_limit > 0) {
if (m_pce != nullptr && match_limit > 0) {
local_pce = *m_pce;
local_pce.match_limit = match_limit;
local_pce.flags |= PCRE_EXTRA_MATCH_LIMIT;
@ -235,7 +235,7 @@ RegexResult Regex::searchOneMatch(const std::string& s, std::vector<SMatchCaptur
captures.push_back(capture);
}
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre2_match_data_free(match_data);
#endif
return to_regex_result(rc);
@ -243,24 +243,24 @@ RegexResult Regex::searchOneMatch(const std::string& s, std::vector<SMatchCaptur
RegexResult Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit) const {
bool prev_match_zero_length = false;
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
Pcre2MatchContextPtr match_context;
if (match_limit > 0) {
// TODO: What if setting the match limit fails?
pcre2_set_match_limit(match_context, match_limit);
pcre2_set_match_limit(static_cast<pcre2_match_context*>(match_context), match_limit);
}
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
PCRE2_SIZE startOffset = 0;
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, nullptr);
while (startOffset <= s.length()) {
uint32_t pcre2_options = 0;
if (prev_match_zero_length) {
pcre2_options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
}
int rc = pcre2_match(m_pc, pcre2_s, s.length(),
startOffset, pcre2_options, match_data, match_context);
startOffset, pcre2_options, match_data, static_cast<pcre2_match_context*>(match_context));
const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
#else
@ -268,7 +268,7 @@ RegexResult Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>
pcre_extra local_pce;
pcre_extra *pce = m_pce;
if (m_pce != NULL && match_limit > 0) {
if (m_pce != nullptr && match_limit > 0) {
local_pce = *m_pce;
local_pce.match_limit = match_limit;
local_pce.flags |= PCRE_EXTRA_MATCH_LIMIT;
@ -337,25 +337,25 @@ RegexResult Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>
}
}
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre2_match_data_free(match_data);
#endif
return RegexResult::Ok;
}
int Regex::search(const std::string& s, SMatch *match) const {
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, nullptr);
int ret = 0;
if (m_pcje == 0) {
ret = pcre2_match(m_pc, pcre2_s, s.length(),
0, 0, match_data, NULL) > 0;
0, 0, match_data, nullptr) > 0;
}
if (m_pcje != 0 || ret == PCRE2_ERROR_JIT_STACKLIMIT) {
ret = pcre2_match(m_pc, pcre2_s, s.length(),
0, PCRE2_NO_JIT, match_data, NULL) > 0;
0, PCRE2_NO_JIT, match_data, nullptr) > 0;
}
if (ret > 0) { // match
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
@ -371,23 +371,23 @@ int Regex::search(const std::string& s, SMatch *match) const {
0);
}
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre2_match_data_free(match_data);
#endif
return ret;
}
int Regex::search(const std::string& s) const {
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(m_pc, nullptr);
int rc = 0;
if (m_pcje == 0) {
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(), 0, 0, match_data, NULL);
rc = pcre2_jit_match(m_pc, pcre2_s, s.length(), 0, 0, match_data, nullptr);
}
if (m_pcje != 0 || rc == PCRE2_ERROR_JIT_STACKLIMIT) {
rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, PCRE2_NO_JIT, match_data, NULL);
rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, PCRE2_NO_JIT, match_data, nullptr);
}
pcre2_match_data_free(match_data);
if (rc > 0) {
@ -405,7 +405,7 @@ int Regex::search(const std::string& s) const {
RegexResult Regex::to_regex_result(int pcre_exec_result) const {
if (
pcre_exec_result > 0 ||
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre_exec_result == PCRE2_ERROR_NOMATCH
#else
pcre_exec_result == PCRE_ERROR_NOMATCH
@ -413,7 +413,7 @@ RegexResult Regex::to_regex_result(int pcre_exec_result) const {
) {
return RegexResult::Ok;
} else if(
#ifdef WITH_PCRE2
#ifndef WITH_PCRE
pcre_exec_result == PCRE2_ERROR_MATCHLIMIT
#else
pcre_exec_result == PCRE_ERROR_MATCHLIMIT

View File

@ -12,7 +12,7 @@
* directly using the email address security@modsecurity.org.
*
*/
#if WITH_PCRE2
#ifndef WITH_PCRE
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#else
@ -79,7 +79,7 @@ class Regex {
Regex& operator=(const Regex&) = delete;
bool hasError() const {
return (m_pc == NULL);
return (m_pc == nullptr);
}
std::list<SMatch> searchAll(const std::string& s) const;
RegexResult searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures, unsigned long match_limit = 0) const;
@ -91,12 +91,12 @@ class Regex {
private:
RegexResult to_regex_result(int pcre_exec_result) const;
#if WITH_PCRE2
#ifndef WITH_PCRE
pcre2_code *m_pc;
int m_pcje;
#else
pcre *m_pc = NULL;
pcre_extra *m_pce = NULL;
pcre *m_pc = nullptr;
pcre_extra *m_pce = nullptr;
#endif
};

View File

@ -79,7 +79,7 @@ void XML::evaluate(Transaction *t,
}
/* Process the XPath expression. */
xpathExpr = (const xmlChar*)param.c_str();
xpathExpr = reinterpret_cast<const xmlChar*>(param.c_str());
xpathCtx = xmlXPathNewContext(t->m_xml->m_data.doc);
if (xpathCtx == NULL) {
ms_dbg_a(t, 1, "XML: Unable to create new XPath context. : ");
@ -91,9 +91,9 @@ void XML::evaluate(Transaction *t,
} else {
std::vector<actions::Action *> acts = rule->getActionsByName("xmlns", t);
for (auto &x : acts) {
actions::XmlNS *z = (actions::XmlNS *)x;
if (xmlXPathRegisterNs(xpathCtx, (const xmlChar*)z->m_scope.c_str(),
(const xmlChar*)z->m_href.c_str()) != 0) {
actions::XmlNS *z = static_cast<actions::XmlNS *>(x);
if (xmlXPathRegisterNs(xpathCtx, reinterpret_cast<const xmlChar*>(z->m_scope.c_str()),
reinterpret_cast<const xmlChar*>(z->m_href.c_str())) != 0) {
ms_dbg_a(t, 1, "Failed to register XML namespace href \"" + \
z->m_href + "\" prefix \"" + z->m_scope + "\".");
return;

View File

@ -72,7 +72,7 @@ unit_tests_LDFLAGS = \
unit_tests_CPPFLAGS = \
-Icommon \
-I../ \
-I$(top_srcdir)/ \
-g \
-I$(top_builddir)/headers \
$(CURL_CFLAGS) \
@ -127,7 +127,7 @@ regression_tests_LDFLAGS = \
regression_tests_CPPFLAGS = \
-Icommon \
-I../ \
-I$(top_srcdir) \
-g \
-I$(top_builddir)/headers \
$(CURL_CFLAGS) \
@ -179,7 +179,7 @@ rules_optimization_LDFLAGS = \
rules_optimization_CPPFLAGS = \
-Icommon \
-I../ \
-I$(top_srcdir)/ \
-g \
-I$(top_builddir)/headers \
$(CURL_CFLAGS) \

View File

@ -10,6 +10,7 @@ benchmark_LDADD = \
$(GEOIP_LDADD) \
$(MAXMIND_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(YAJL_LDADD) \
$(LMDB_LDADD) \
$(SSDEEP_LDADD) \
@ -35,6 +36,7 @@ benchmark_CPPFLAGS = \
-I$(top_builddir)/headers \
$(GLOBAL_CPPFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LMDB_CFLAGS) \
$(LIBXML2_CFLAGS)

View File

@ -31,6 +31,8 @@ accessMoved:seclang-parser.hh
returnTempReference:seclang-parser.hh
duplInheritedMember:seclang-parser.hh
constVariableReference:seclang-parser.hh
uninitMemberVar:seclang-parser.hh
unreadVariable:src/operators/rx.cc
unreadVariable:src/operators/rx_global.cc
@ -59,3 +61,4 @@ uselessCallsSubstr
// Examples
memleak:examples/using_bodies_in_chunks/simple_request.cc

View File

@ -18,6 +18,7 @@ afl_fuzzer_LDADD = \
$(CURL_LDADD) \
$(GEOIP_LDFLAGS) $(GEOIP_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(YAJL_LDFLAGS) $(YAJL_LDADD) \
$(LMDB_LDFLAGS) $(LMDB_LDADD) \
$(MAXMIND_LDFLAGS) $(MAXMIND_LDADD) \
@ -44,4 +45,5 @@ afl_fuzzer_CPPFLAGS = \
$(YAJL_CFLAGS) \
$(LMDB_CFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LIBXML2_CFLAGS)

View File

@ -0,0 +1,2 @@
# comment
pattern1

View File

@ -0,0 +1,2 @@
# comment
pattern2

View File

@ -144,7 +144,7 @@
"resource":"libxml2",
"title":"Testing CtlRequestBodyProcessor=XML (3)",
"expected":{
"debug_log": "XML: Failed parsing document."
"debug_log": "XML: Failed to parse document."
},
"client":{
"ip":"200.249.12.31",

View File

@ -172,6 +172,65 @@
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "auditlog : basic parser test - JSON",
"client": {
"ip": "200.249.12.31",
"port": 2313
},
"server": {
"ip": "200.249.12.31",
"port": 80
},
"request": {
"headers": {
"Host": "www.modsecurity.org",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "\/test.pl?param1= test &param2=test2",
"method": "GET",
"http_version": 1.1,
"body": ""
},
"response": {
"headers": {
"Content-Type": "plain\/text\n\r"
},
"body": [
"test"
]
},
"expected": {
"audit_log": "{\"transaction\":{\"client_ip\":\"200.249.12.31\",\"time_stamp\":\"\\S{3} \\S{3} [ \\d]\\d \\d{2}:\\d{2}:\\d{2} \\d{4}\"",
"debug_log": "",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecRule ARGS \"@contains test\" \"id:1,t:trim,deny,auditlog\"",
"SecAuditEngine RelevantOnly",
"SecAuditLogFormat JSON",
"SecAuditLogParts ABCFHZ",
"SecAuditLogStorageDir /tmp/test",
"SecAuditLog /tmp/audit_test_parallel.log",
"SecAuditLogDirMode 0766",
"SecAuditLogFileMode 0600",
"SecAuditLogType Serial",
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
},
{
"enabled": 1,
"version_min": 300000,
@ -418,5 +477,64 @@
"SecAuditLogType Serial",
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
},
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "auditlog : SecAuditLogPrefix",
"client": {
"ip": "200.249.12.31",
"port": 2313
},
"server": {
"ip": "200.249.12.31",
"port": 80
},
"request": {
"headers": {
"Host": "www.modsecurity.org",
"User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)",
"Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Encoding": "gzip,deflate",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive": "300",
"Connection": "keep-alive",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"uri": "\/test.pl?param1= test &param2=test2",
"method": "GET",
"http_version": 1.1,
"body": ""
},
"response": {
"headers": {
"Content-Type": "plain\/text\n\r"
},
"body": [
"test"
]
},
"expected": {
"audit_log": "\\[audit\\.log]:\\ ---.*\\[audit\\.log]:\\ Keep-Alive",
"debug_log": "",
"error_log": "",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecRule ARGS \"@contains test\" \"id:1,t:trim,deny,auditlog\"",
"SecAuditEngine RelevantOnly",
"SecAuditLogPrefix \"[audit.log]: \"",
"SecAuditLogParts ABCFHZ",
"SecAuditLogStorageDir /tmp/test",
"SecAuditLog /tmp/audit_test_prefix.log",
"SecAuditLogDirMode 0766",
"SecAuditLogFileMode 0600",
"SecAuditLogType Serial",
"SecAuditLogRelevantStatus \"^(?:5|4(?!04))\""
]
}
]

View File

@ -0,0 +1,39 @@
[
{
"enabled": 1,
"version_min": 300000,
"version_max": 0,
"title": "pmFromFile operator test",
"client": {
"ip": "10.20.30.40",
"port": 2313
},
"server": {
"ip": "1.2.3.4",
"port": 80
},
"request": {
"headers": {
"Host": "foobar.com"
},
"uri": "\/test.php?param1=pattern2",
"method": "GET",
"http_version": 1.1,
"body": ""
},
"response": {
"headers": {
"Content-Type": "text\/html; charset=utf-8\n\r",
"Content-Length": "10\n\r"
}
},
"expected": {
"debug_log": "Rule returned 1",
"http_code": 403
},
"rules": [
"SecRuleEngine On",
"SecRule ARGS \"@pmFromFile test-cases/data/pattern-file1.data test-cases/data/pattern-file2.data\" \"phase:1,id:999,deny\""
]
}
]

View File

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR (1/2)",
"title":"Testing Variables :: MATCHED_VAR (1/5)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -42,7 +42,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR (2/2)",
"title":"Testing Variables :: MATCHED_VAR (2/5)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -81,6 +81,128 @@
"SecRule MATCHED_VAR \"@contains other_value\" \"id:29,pass\"",
"SecRule MATCHED_VAR \"@contains other_value\" \"id:30,pass\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR (3/5)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VAR \"@eq 1\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR (4/5)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VAR \"@eq 2\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR (5/5)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 403
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,deny,status:403,chain\"",
"SecRule MATCHED_VAR \"@eq 2\""
]
}
]

View File

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS (1/2)",
"title":"Testing Variables :: MATCHED_VARS (1/6)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -43,7 +43,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS (2/2)",
"title":"Testing Variables :: MATCHED_VARS (2/6)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -81,6 +81,169 @@
"SecRule MATCHED_VARS \"@contains asdf\" \"\"",
"SecRule MATCHED_VARS \"@contains value\" \"id:29\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS (3/6)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VARS \"@contains 1\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS (4/6)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VARS \"@contains 2\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS (5/6)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VARS \"@within 1 2\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS (6/6)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 403
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,deny,status:403,chain\"",
"SecRule MATCHED_VARS \"@eq 2\""
]
}
]

View File

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS_NAMES (1/2)",
"title":"Testing Variables :: MATCHED_VARS_NAMES (1/5)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -43,7 +43,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS_NAMES (2/2)",
"title":"Testing Variables :: MATCHED_VARS_NAMES (2/5)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -81,6 +81,128 @@
"SecRule MATCHED_VARS_NAMES \"@contains asdf\" \"\"",
"SecRule MATCHED_VARS_NAMES \"@contains value\" \"id:29\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS_NAMES (3/5)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VARS_NAMES \"@within ARGS:foo ARGS:bar ARGS:baz\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS_NAMES (4/5)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,deny,status:403,chain\"",
"SecRule MATCHED_VARS_NAMES \"@strEq ARGS:foo\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VARS_NAMES (5/5)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 403
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,deny,status:403,chain\"",
"SecRule MATCHED_VARS_NAMES \"@within ARGS:bar ARGS:baz\""
]
}
]

View File

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (1/3)",
"title":"Testing Variables :: MATCHED_VAR_NAME (1/7)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -43,7 +43,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (2/3)",
"title":"Testing Variables :: MATCHED_VAR_NAME (2/7)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -85,7 +85,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (3/3)",
"title":"Testing Variables :: MATCHED_VAR_NAME (3/7)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -121,6 +121,169 @@
"SecRule ARGS_NAMES \"@contains ey1\" \"chain,id:30,pass\"",
"SecRule MATCHED_VAR_NAME \"@contains key1\" \"id:31\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (4/7)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VAR_NAME \"@strEq ARGS:foo\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (5/7)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VAR_NAME \"@strEq ARGS:bar\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (6/7)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 200
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,pass\"",
"SecRule MATCHED_VAR_NAME \"@strEq ARGS:baz\" \"id:3,phase:1,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: MATCHED_VAR_NAME (7/7)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*"
},
"uri":"/?foo=1&bar=2&baz=2",
"method":"GET"
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 403
},
"rules":[
"SecRuleEngine On",
"SecRule ARGS \"@rx 1\" \"id:1,phase:1,pass\"",
"SecRule ARGS \"@rx 2\" \"id:2,phase:1,deny,status:403,chain\"",
"SecRule MATCHED_VAR_NAME \"@within ARGS:baz ARGS:bar\""
]
}
]

View File

@ -70,7 +70,7 @@
]
},
"expected":{
"debug_log":"XML parsing error: XML: Failed parsing document"
"debug_log":"XML parsing error: XML: Failed to parse document"
},
"rules":[
"SecRuleEngine On",

View File

@ -30,7 +30,6 @@
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
@ -42,6 +41,580 @@
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule XML://bookstore/*[local-name()='some-tag'] \"bbb\" \"id:500012,phase:3,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, check if ARGS is populated",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS:xml.bookstore.some-tag \"@rx aaa\" \"id:500012,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, check if XML is populated",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule XML:/* \"@rx aaa\" \"id:500012,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with OnlyArgs, check if ARGS is populated",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs OnlyArgs",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS:xml.bookstore.some-tag \"@rx aaa\" \"id:500012,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with OnlyArgs, check if XML is populated",
"expected":{
"http_code": 200
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs OnlyArgs",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule XML:/* \"@rx aaa\" \"id:500012,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with Off, check if ARGS is populated",
"expected":{
"http_code": 200
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs Off",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS \"@rx aaa\" \"id:500012,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with Off, check if XML is populated",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs Off",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule XML:/* \"@rx aaa\" \"id:500012,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, turn Off with ctl, check ARGS",
"expected":{
"http_code": 200
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS_GET:q \"@rx xml\" \"id:500012,phase:1,t:none,t:lowercase,ctl:parseXmlIntoArgs=Off\"",
"SecRule ARGS:xml.bookstore.some-tag \"@rx aaa\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, turn Off with ctl, check XML",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS_GET:q \"@rx xml\" \"id:500012,phase:1,t:none,t:lowercase,ctl:parseXmlIntoArgs=Off\"",
"SecRule XML:/* \"@rx aaa\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, turn OnlyArgs with ctl, check ARGS",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS_GET:q \"@rx xml\" \"id:500012,phase:1,t:none,t:lowercase,ctl:parseXmlIntoArgs=OnlyArgs\"",
"SecRule ARGS:xml.bookstore.some-tag \"@rx aaa\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, turn OnlyArgs with ctl, check XML",
"expected":{
"http_code": 200
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS_GET:q \"@rx xml\" \"id:500012,phase:1,t:none,t:lowercase,ctl:parseXmlIntoArgs=OnlyArgs\"",
"SecRule XML:/* \"@rx aaa\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with Off, turn On with ctl, check ARGS",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs Off",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS_GET:q \"@rx xml\" \"id:500012,phase:1,t:none,t:lowercase,ctl:parseXmlIntoArgs=On\"",
"SecRule ARGS:xml.bookstore.some-tag \"@rx aaa\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with Off, turn On with ctl, check XML",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
"<!DOCTYPE author [",
"<!ELEMENT book ANY>",
"<!ENTITY js SYSTEM \"/etc/passwd\">",
"]>",
"<bookstore>",
"<some-tag>aaa</some-tag><some-tag>bbb</some-tag>",
"</bookstore>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs Off",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS_GET:q \"@rx xml\" \"id:500012,phase:1,t:none,t:lowercase,ctl:parseXmlIntoArgs=On\"",
"SecRule XML:/* \"@rx aaa\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
},
{
"enabled":1,
"version_min":300000,
"resource":"libxml2",
"title":"Testing XML parsing to ARGS with On, node contains utf8 character",
"expected":{
"http_code": 403
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Type": "text/xml"
},
"uri":"/?q=xml",
"method":"POST",
"body": [
"<pizza>",
"<has>pineapple</has><has>🍍</has>",
"</pizza>"
]
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecRequestBodyAccess On",
"SecParseXmlIntoArgs On",
"SecRule REQUEST_HEADERS:Content-Type \"^text/xml$\" \"id:500011,phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML\"",
"SecRule ARGS \"@rx 🍍\" \"id:500013,phase:2,t:none,t:lowercase,log,deny,status:403\""
]
}
]

View File

@ -86,6 +86,7 @@ TESTS+=test/test-cases/regression/operator-fuzzyhash.json
TESTS+=test/test-cases/regression/operator-inpectFile.json
TESTS+=test/test-cases/regression/operator-ipMatchFromFile.json
TESTS+=test/test-cases/regression/operator-pm.json
TESTS+=test/test-cases/regression/operator-pmfromfile.json
TESTS+=test/test-cases/regression/operator-rx.json
TESTS+=test/test-cases/regression/operator-rxGlobal.json
TESTS+=test/test-cases/regression/operator-UnconditionalMatch.json

View File

@ -15,6 +15,7 @@ modsec_rules_check_LDADD = \
$(LMDB_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(PCRE2_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
@ -25,12 +26,14 @@ modsec_rules_check_LDFLAGS = \
$(LMDB_LDFLAGS) \
$(LUA_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(YAJL_LDFLAGS)
$(YAJL_LDFLAGS) \
$(LIBXML2_LDFLAGS)
modsec_rules_check_CPPFLAGS = \
-I$(top_builddir)/headers \
$(GLOBAL_CPPFLAGS) \
$(PCRE_CFLAGS) \
$(PCRE2_CFLAGS) \
$(LMDB_CFLAGS) \
$(MAXMIND_CFLAGS) \
$(LIBXML2_CFLAGS)