Skip to content

Commit b353997

Browse files
authored
Merge pull request kaakaww#24 from kaakaww/auth-script-examples
Auth script examples
2 parents ab0e918 + be02b5c commit b353997

File tree

15 files changed

+594
-33
lines changed

15 files changed

+594
-33
lines changed

db/vulny.mv.db

4 KB
Binary file not shown.
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
2+
/** TEMPLATE BEGIN **/
3+
/** Use this boilerplate code in all auth scripts.
4+
* NOTE: This script requires hawkscan version 2.6.0 or higher to support the getHawkConf() function.
5+
* **/
6+
7+
/** Import Java classes required for many authentication functions **/
8+
const URLEncoder = Java.type("java.net.URLEncoder");
9+
const URI = Java.type("org.apache.commons.httpclient.URI");
10+
const LogManager = Java.type("org.apache.log4j.LogManager");
11+
12+
const ScriptVars = Java.type("org.zaproxy.zap.extension.script.ScriptVars");
13+
const AuthenticationHelper = Java.type("org.zaproxy.zap.authentication.AuthenticationHelper");
14+
const ExtensionAntiCSRF = Java.type("org.zaproxy.zap.extension.anticsrf.ExtensionAntiCSRF");
15+
const Control = Java.type("org.parosproxy.paros.control.Control");
16+
17+
const HttpHeader = Java.type("org.parosproxy.paros.network.HttpHeader");
18+
const HttpRequestHeader = Java.type("org.parosproxy.paros.network.HttpRequestHeader");
19+
20+
/** Create logger and helper init functions **/
21+
const logger = LogManager.getLogger("custom-form-auth");
22+
let loggingEnabled = false;
23+
24+
// log if enabled
25+
const log = (str) => {
26+
if (loggingEnabled) {
27+
logger.info(str)
28+
}
29+
}
30+
31+
// initialize logging based on parameters from hawk config
32+
const initLogging = (paramsValues) => {
33+
const loggingParam = paramsValues.get("logging");
34+
if (loggingParam != null && loggingParam === "true") {
35+
loggingEnabled = true;
36+
}
37+
}
38+
39+
/** Reference to the configured hawkscan conf file as a Javascript Object **/
40+
const getHawkConf = () => {
41+
return JSON.parse(ScriptVars.getGlobalVar("hawkConf"));
42+
}
43+
const hawkConf = getHawkConf();
44+
45+
/** Helper functions **/
46+
// build a URL from supplied params and hawkscan conf's app.host
47+
const paramUrl = (paramsValues, paramName) => {
48+
return `${hawkConf["app"]["host"]}${paramsValues.get(paramName)}`
49+
}
50+
51+
// build a form-urlencoded string from a Javascript Object
52+
const buildForm = (obj) => {
53+
let str = "";
54+
let i = 0;
55+
for (const key in obj) {
56+
if (i > 0) {
57+
str += "&";
58+
}
59+
str += `${urlEncode(key)}=${urlEncode(obj[key])}`;
60+
i++;
61+
}
62+
return str;
63+
}
64+
65+
// Url encode a string
66+
const urlEncode = (str) => {
67+
return URLEncoder.encode(str, "UTF-8");
68+
}
69+
70+
// List of credential names from the configured hawkscan conf
71+
const credentialNames = () => {
72+
let names = [];
73+
for (const name in hawkConf["app"]["authentication"]["script"]["credentials"]) {
74+
names.push(name);
75+
}
76+
return names;
77+
}
78+
79+
// Add all credentials to the form Object
80+
const addCredentials = (formObj, credentials) => {
81+
credentialNames().forEach((name) => {
82+
formObj[name] = credentials.getParam(name);
83+
});
84+
}
85+
86+
/** Reference to the ExtensionCsrf AddOn for csrf parsing utilities **/
87+
const extCsrf = Control.getSingleton()
88+
.getExtensionLoader()
89+
.getExtension(ExtensionAntiCSRF.class);
90+
91+
/**
92+
* Make a GET request like a browser would following redirects and accumulating cookies into the "jar"
93+
* The returned object will contain and array of HttpMessage's in chronological order of each redirect.
94+
* The HttpMessage contains the requestHeaders, requestBody, responseHeader, and responseBody.
95+
* **/
96+
const getRequestBrowserLike = (helper, url, jar) => {
97+
if (jar == null) {
98+
jar = {cookies: {}, messages: []};
99+
}
100+
101+
let requestUri = new URI(url, false);
102+
let requestHeader = new HttpRequestHeader(HttpRequestHeader.GET, requestUri, HttpHeader.HTTP11);
103+
104+
let msg = helper.prepareMessage();
105+
msg.setRequestHeader(requestHeader);
106+
107+
// Make the HTTP request
108+
helper.sendAndReceive(msg);
109+
110+
log(`req/resp: ${logMsg(msg)}`)
111+
msg.responseHeader.getHttpCookies().forEach((cookie) => {
112+
if (cookie.name in jar.cookies) {
113+
jar.cookies[cookie.name].push(cookie);
114+
} else {
115+
jar.cookies[cookie.name] = [cookie];
116+
}
117+
});
118+
119+
jar.messages.push(msg);
120+
const locationHdr = msg.responseHeader.getHeader("Location");
121+
if (locationHdr != null) {
122+
return getRequestBrowserLike(helper, locationHdr, jar);
123+
} else {
124+
return jar;
125+
}
126+
127+
}
128+
129+
const jsonMsg = (msg) => {
130+
return {
131+
requestHeader: msg.requestHeader.toString(),
132+
requestBody: msg.requestBody.toString(),
133+
responseHeader: msg.responseHeader.toString(),
134+
responseBody: msg.responseBody.toString()
135+
}
136+
}
137+
138+
const logMsg = (msg) => {
139+
return `${msg.requestHeader}\r\n\r\n${msg.requestBody}\r\n---\r\n${msg.responseHeader}\r\n\r\n${msg.responseBody}`;
140+
}
141+
142+
/** TEMPLATE END **/
143+
144+
function authenticate(helper, paramsValues, credentials) {
145+
initLogging(paramsValues);
146+
log("Authenticating with custom script...");
147+
148+
// Login form page url
149+
let url = paramUrl(paramsValues, "loginPagePath");
150+
151+
// Make request to login form page following redirects and accumulating cookies
152+
let jar = getRequestBrowserLike(helper, url);
153+
154+
/* Enable for demo
155+
log("jar response headers")
156+
jar.messages.forEach((jarMsg) => {
157+
log(`${jarMsg.responseHeader.toString()}`)
158+
});*/
159+
160+
// The last message in the jar should contain our login form
161+
let msg = jar.messages[jar.messages.length - 1];
162+
163+
// Add login form page response to the auth message history to aid cookie session tracking
164+
AuthenticationHelper.addAuthMessageToHistory(msg);
165+
166+
// Add special extra csrf like token
167+
extCsrf.addAntiCsrfTokenName(paramsValues.get("csrfExtra"));
168+
169+
// Extract acsrf tokens from the response
170+
const acsrfTokens = extCsrf.getTokensFromResponse(msg);
171+
172+
// Accumulate the tokens and credentials for the form post on an Object.
173+
let formObj = {};
174+
log(`csrf tokens count: ${acsrfTokens.size()}`);
175+
acsrfTokens.forEach((token) => {
176+
formObj[token.name] = token.value;
177+
log(`adding csrf token ${token.name} = ${token.value}`);
178+
});
179+
addCredentials(formObj, credentials);
180+
formObj["remember"] = paramsValues.get("remember");
181+
182+
// Build the request body from the form Object
183+
let requestBody = "";
184+
const formType = paramsValues.get("formType");
185+
log(`formObj: ${JSON.stringify(formObj)}`)
186+
// Encode as JSON or form
187+
if (formType != null && formType === "JSON") {
188+
requestBody = JSON.stringify(formObj);
189+
} else {
190+
requestBody = buildForm(formObj);
191+
}
192+
193+
log(`POST: ${requestBody}`);
194+
195+
// Prepare the request to the login form
196+
url = paramUrl(paramsValues, "loginPage");
197+
requestUri = new URI(url, false);
198+
requestHeader = new HttpRequestHeader(HttpRequestHeader.POST, requestUri, HttpHeader.HTTP11)
199+
msg = helper.prepareMessage();
200+
msg.setRequestHeader(requestHeader);
201+
msg.setRequestBody(requestBody);
202+
203+
// Set the contentLength header from the length of the encoded request body
204+
requestHeader.contentLength = msg.requestBody.length();
205+
206+
// Make the HTTP POST request to the login form
207+
helper.sendAndReceive(msg);
208+
209+
log(`req/resp: ${logMsg(msg)}`)
210+
211+
/**
212+
* Return response message from the authentication form post.
213+
* The response header and body will be evaluated against the app.authentication.testPath
214+
* as well as the app.loggedIn/OutIndicators. If the response is determined to be
215+
* valid the response will also be passed to the session mgmt method
216+
* for evaluation.
217+
*/
218+
return msg;
219+
}
220+
221+
/**
222+
* The list of required parameters, the script will fail if these are not present.
223+
* They are available on the paramsValues map in the authenticate() function
224+
* @returns {string[]}
225+
*/
226+
function getRequiredParamsNames() {
227+
return ["loginPagePath", "loginPage", "remember"];
228+
}
229+
230+
/**
231+
* The list of credential parameters.
232+
* They are available on the credentials map in the authenticate() function
233+
* These parameters MUSt match the names in app.authentication.script.credentials.
234+
* @returns {string[]}
235+
*/
236+
function getCredentialsParamsNames() {
237+
return ["username", "password"];
238+
}
239+
240+
/**
241+
* The list of optional parameters/
242+
* They are available on the paramsValues map in the authenticate() function.
243+
* A parameter MUST be included here if passed in the app.authentication.script.parameters map
244+
* or it will not be available on the paramsValues map.
245+
* @returns {string[]}
246+
*/
247+
function getOptionalParamsNames() {
248+
return ["logging", "formType", "csrfExtra"];
249+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import org.apache.log4j.LogManager
2+
import org.parosproxy.paros.network.HttpMessage
3+
import org.zaproxy.zap.extension.script.HttpSenderScriptHelper
4+
import org.zaproxy.zap.extension.script.ScriptVars
5+
6+
val logger = LogManager.getLogger("sender1")
7+
8+
// modify a request before it's sent to the web application
9+
fun sendingRequest(msg: HttpMessage, initiator: Int, helper: HttpSenderScriptHelper) {
10+
// logger.info("custom-sender script $initiator")
11+
msg.requestHeader.setHeader("X-ZAP-Initiator", "$initiator")
12+
}
13+
14+
// modify the response from the web application before sending to the client
15+
fun responseReceived(msg: HttpMessage, initiator: Int, helper: HttpSenderScriptHelper) {
16+
msg.responseHeader.setHeader("X-ZAP-Initiator", "$initiator")
17+
}

openapi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"openapi":"3.0.1","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"https://localhost:9000","description":"Generated server url"}],"paths":{"/api/jwt/items/search/":{"get":{"tags":["jwt-item-controller"],"operationId":"searchAll","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/items/search/{text}":{"get":{"tags":["jwt-item-controller"],"operationId":"search","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/auth/signin":{"post":{"tags":["jwt-auth-controller"],"operationId":"signin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticationRequest"}}}},"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/token/items/search/":{"get":{"tags":["token-item-controller"],"operationId":"search_1","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/token/items/search/{text}":{"get":{"tags":["token-item-controller"],"operationId":"search_2","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/basic/items/search/":{"get":{"tags":["basic-auth-item-controller"],"operationId":"search_3","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/basic/items/search/{text}":{"get":{"tags":["basic-auth-item-controller"],"operationId":"search_4","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"AuthenticationRequest":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}}}}}}
1+
{"openapi":"3.0.1","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"https://localhost:9000","description":"Generated server url"}],"paths":{"/api/jwt/auth/signin":{"post":{"tags":["jwt-auth-controller"],"operationId":"signin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticationRequest"}}}},"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/users/search/{text}":{"get":{"tags":["jwt-user-controller"],"operationId":"search","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/users/search/":{"get":{"tags":["jwt-user-controller"],"operationId":"searchAll","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/items/search":{"post":{"tags":["jwt-item-controller"],"operationId":"search_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Search"}}}},"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/items/search/{text}":{"get":{"tags":["jwt-item-controller"],"operationId":"search_2","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/jwt/items/search/":{"get":{"tags":["jwt-item-controller"],"operationId":"searchAll_1","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/basic/items/search/":{"get":{"tags":["basic-auth-item-controller"],"operationId":"search_3","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/basic/items/search/{text}":{"get":{"tags":["basic-auth-item-controller"],"operationId":"search_4","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/token/items/search/":{"get":{"tags":["token-item-controller"],"operationId":"search_5","responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/token/items/search/{text}":{"get":{"tags":["token-item-controller"],"operationId":"search_6","parameters":[{"name":"text","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"default response","content":{"*/*":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"AuthenticationRequest":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}}},"Search":{"type":"object","properties":{"searchText":{"type":"string"}}}}}}

0 commit comments

Comments
 (0)