mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 21:36:00 +03:00
407 lines
11 KiB
Perl
407 lines
11 KiB
Perl
### Multipart parser tests
|
|
|
|
# Final CRLF or not, we should still work
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser (final CRLF)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
|
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
|
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
|
),
|
|
match_log => {
|
|
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
2
|
|
-----------------------------69343412719991675451336310646--
|
|
),
|
|
),
|
|
),
|
|
},
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser (no final CRLF)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
|
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
|
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
|
),
|
|
match_log => {
|
|
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
2
|
|
-----------------------------69343412719991675451336310646--),
|
|
),
|
|
),
|
|
},
|
|
|
|
# Should work with a boundary of "boundary"
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser (boundary contains \"boundary\")",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
|
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
|
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
|
),
|
|
match_log => {
|
|
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=------------------------------------------------boundary",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
--------------------------------------------------boundary
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
1
|
|
--------------------------------------------------boundary
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
2
|
|
--------------------------------------------------boundary--
|
|
),
|
|
),
|
|
),
|
|
},
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser (boundary contains \"bOuNdArY\")",
|
|
note => q(
|
|
KHTML Boundary
|
|
),
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
|
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
|
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
|
),
|
|
match_log => {
|
|
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=--------0xKhTmLbOuNdArY",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
----------0xKhTmLbOuNdArY
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
1
|
|
----------0xKhTmLbOuNdArY
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
2
|
|
----------0xKhTmLbOuNdArY--
|
|
),
|
|
),
|
|
),
|
|
},
|
|
|
|
# We should handle data starting with a "--"
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser (data contains \"--\")",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
|
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
|
),
|
|
match_log => {
|
|
debug => [ qr/Adding request argument \(BODY\): name "a", value "--test".*Adding request argument \(BODY\): name "b", value "--"/s, 1 ],
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
--test
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
--
|
|
-----------------------------69343412719991675451336310646--),
|
|
),
|
|
),
|
|
},
|
|
|
|
# We should emit warnings for parsing errors
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser error (no final boundary)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecAuditLog "$ENV{AUDIT_LOG}"
|
|
SecAuditEngine RelevantOnly
|
|
),
|
|
match_log => {
|
|
audit => [ qr/Final boundary missing/, 1 ],
|
|
debug => [ qr/Final boundary missing/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
2
|
|
),
|
|
),
|
|
),
|
|
},
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser error (no disposition)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecAuditLog "$ENV{AUDIT_LOG}"
|
|
SecAuditEngine RelevantOnly
|
|
),
|
|
match_log => {
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
audit => [ qr/Part missing Content-Disposition header/, 1 ],
|
|
debug => [ qr/Part missing Content-Disposition header/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
|
|
2
|
|
-----------------------------69343412719991675451336310646--
|
|
),
|
|
),
|
|
),
|
|
},
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser error (bad disposition)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecAuditLog "$ENV{AUDIT_LOG}"
|
|
SecAuditEngine RelevantOnly
|
|
),
|
|
match_log => {
|
|
audit => [ qr/Invalid Content-Disposition header/, 1 ],
|
|
debug => [ qr/Invalid Content-Disposition header/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data name="a"
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data name="b"
|
|
|
|
2
|
|
-----------------------------69343412719991675451336310646--
|
|
),
|
|
),
|
|
),
|
|
},
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser error (no disposition name)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
SecAuditLog "$ENV{AUDIT_LOG}"
|
|
SecAuditEngine RelevantOnly
|
|
),
|
|
match_log => {
|
|
-debug => [ qr/Multipart error:/, 1 ],
|
|
audit => [ qr/Content-Disposition header missing name field/, 1 ],
|
|
debug => [ qr/Content-Disposition header missing name field/, 1 ],
|
|
|
|
},
|
|
match_response => {
|
|
status => qr/^200$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data;
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data;
|
|
|
|
2
|
|
-----------------------------69343412719991675451336310646--
|
|
),
|
|
),
|
|
),
|
|
},
|
|
# Zero length part name should not crash
|
|
{
|
|
type => "misc",
|
|
comment => "multipart parser (zero length part name)",
|
|
conf => qq(
|
|
SecRuleEngine On
|
|
SecDebugLog $ENV{DEBUG_LOG}
|
|
SecDebugLogLevel 9
|
|
SecRequestBodyAccess On
|
|
#SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,status:403"
|
|
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny,status:403"
|
|
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,status:403"
|
|
),
|
|
match_log => {
|
|
debug => [ qr/name: a.*variable: 1.*Invalid part header \(header name missing\)/s, 1 ],
|
|
-debug => [ qr/Adding request argument \(BODY\): name "b"/s, 1 ],
|
|
},
|
|
match_response => {
|
|
status => qr/^403$/,
|
|
},
|
|
request => new HTTP::Request(
|
|
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
|
[
|
|
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
|
],
|
|
normalize_raw_request_data(
|
|
q(
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="a"
|
|
|
|
1
|
|
-----------------------------69343412719991675451336310646
|
|
:
|
|
-----------------------------69343412719991675451336310646
|
|
Content-Disposition: form-data; name="b"
|
|
|
|
2
|
|
-----------------------------69343412719991675451336310646--
|
|
),
|
|
),
|
|
),
|
|
},
|