Skip to content

Commit 481660a

Browse files
Add unexpected_responses.js script (#240)
This is another variation on the "do something if we see a surprising response" theme, but is intended to be more flexible: * Response codes are tested against a regular expression rather than a literal value * A sense code is used to indicate if matching the regex is "good" or "bad", so you can either whitelist or blacklist depending on your particular use case * Failures (unexpected responses) generate alerts. The formatting here was tailored for mechanical consumption, but there are suggestions in the comments if you value "pretty" output Signed-off-by: Scott Bailey <scott.bailey@godaddy.com>
1 parent 8d82882 commit 481660a

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88
- active/Cross Site WebSocket Hijacking.js > an active scan for Cross-Site WebSocket Hijacking vulnerability
99
- targeted/cve-2021-22214.js > A targeted script to check for Unauthorised SSRF on GitLab - CVE 2021-22214
1010
- httpsender/full-session-n-csrf-nashorn.js > full session and csrf token management.
11+
- httpfuzzerprocessor/unexpected_responses.js > compare response codes to a (pass/fail) regex and generate alerts
1112

1213
### Changed
1314
- Update links in READMEs.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* This fuzz processor script will raise alerts based on HTTP response codes.
3+
* It expects two special parameters:
4+
* - A regular expression used to match the response code
5+
* - A string that is either "pass" or "fail", indicating whether or not a
6+
* matching response is expected ("pass") or unexpected ("fail").
7+
* Unexpected responses will cause an alert to be raised.
8+
*/
9+
10+
// See https://github.com/zaproxy/community-scripts/tree/main/httpfuzzerprocessor
11+
12+
// See https://github.com/zaproxy/community-scripts/blob/main/httpfuzzerprocessor/showDifferences.js
13+
// for inspiration for differencing logic used to document detected defects.
14+
15+
// This script needs Diff add-on
16+
17+
var DiffTool = Java.type("org.zaproxy.zap.extension.diff.diff_match_patch");
18+
19+
/*
20+
* Declare parameters
21+
*/
22+
function getRequiredParamsNames() {
23+
return ["pattern", "sense"];
24+
}
25+
26+
function getOptionalParamsNames() {
27+
return [];
28+
}
29+
30+
/*
31+
* Processes the fuzzed message (payloads already injected).
32+
*
33+
* Called before forwarding the message to the server.
34+
*
35+
* @param {HttpFuzzerTaskProcessorUtils} utils - A utility object that contains functions that ease common tasks.
36+
* @param {HttpMessage} message - The fuzzed message, that will be forward to the server.
37+
*/
38+
function processMessage(utils, message) {
39+
// Take no action
40+
}
41+
42+
/*
43+
* Processes the fuzz result.
44+
*
45+
* Called after receiving the fuzzed message from the server.
46+
*
47+
* @param {HttpFuzzerTaskProcessorUtils} utils - A utility object that contains functions that ease common tasks.
48+
* @param {HttpFuzzResult} fuzzResult - The result of sending the fuzzed message.
49+
* @return {boolean} Whether the result should be accepted, or discarded and not shown.
50+
*/
51+
function processResult(utils, fuzzResult) {
52+
// All the above 'utils' functions are available plus:
53+
// To raise an alert:
54+
// utils.raiseAlert(risk, confidence, name, description)
55+
// To obtain the fuzzed message, received from the server:
56+
// fuzzResult.getHttpMessage()
57+
58+
// Retrieve (string) parameters and convert to required types
59+
var params = utils.getParameters();
60+
var pattern = new RegExp(params.pattern); // response regex
61+
var sense = params.sense == "pass"; // true if regex is expected response
62+
63+
// Retrieve response code and test it against supplied pattern
64+
var fuzzed = fuzzResult.getHttpMessage();
65+
var actual = fuzzed.getResponseHeader().getStatusCode().toString();
66+
var found = actual.search(pattern) != -1;
67+
var expected = found == sense;
68+
var why = "";
69+
70+
// If unexpected, raise an alert
71+
if (!expected) {
72+
// Convert (inverse) of sense to English
73+
if (sense) { // expected a match but did not get it
74+
why = " did not match ";
75+
} else { // expected no match but got one anyway
76+
why = " matched ";
77+
}
78+
79+
// "The original message"
80+
var original = utils.getOriginalMessage();
81+
82+
// Compare the content of the original and fuzzed requests; this will
83+
// indicate what changed to cause the problem. This is very nice if you
84+
// are sending it somewhere that will render HTML, but looks like noise
85+
// anywhere else.
86+
//var diffHtml = createDiffHtml(
87+
// requestAsString(original),
88+
// requestAsString(fuzzed)
89+
//);
90+
91+
// Generate a text difference of the two files
92+
var diffText = createDiffText(
93+
requestAsString(original),
94+
requestAsString(fuzzed)
95+
);
96+
97+
utils.raiseAlert(
98+
3, // High Risk
99+
2, // Medium Confidence
100+
"Unexpected Fuzzer Response", // name
101+
"The application is failing to handle unexpected input correctly.", // description (long)
102+
null, // what parameter was fuzzed? we have no idea...
103+
diffText, // attack
104+
null, // otherInfo (long)
105+
null, // solution (long)
106+
null, // reference (long)
107+
"The received response " + actual + why + params.pattern + ".", // evidence
108+
684, // CWE-684: Incorrect Provision of Specified Functionality
109+
20 // WASC-20: Improper Input Handling
110+
);
111+
112+
// We don't need any more examples; stop this fuzzer
113+
utils.stopFuzzer();
114+
}
115+
116+
// Always accept the result
117+
return true;
118+
}
119+
120+
function requestAsString(httpMessage) {
121+
var requestHeader = httpMessage.getRequestHeader().toString();
122+
var requestBody = httpMessage.getRequestBody().toString();
123+
return requestHeader + "\r\n" + requestBody;
124+
}
125+
126+
function createDiffHtml(original, fuzzed) {
127+
var diffTool = new DiffTool();
128+
var diffList = diffTool.diff_main(original, fuzzed);
129+
return diffTool.diff_prettyHtml(diffList);
130+
}
131+
132+
function createDiffText(original, fuzzed) {
133+
var diffTool = new DiffTool();
134+
diffTool.Patch_Margin = 16; // bytes of context for patches
135+
var patchList = diffTool.patch_make(original, fuzzed);
136+
return diffTool.patch_toText(patchList);
137+
}

0 commit comments

Comments
 (0)