Overview
HawkScan's usernamePassword configuration includes a FORM type option which submits credentials via form-encoded POST to the target application.
Configuring form authentication may also involve:
an Anti-CSRF token (as app.AntiCsrfParam) associated with the login form submission
additional query parameters (usernamePassword.otherParams) to be included in the POST URL
Procedure
Step 1: Determine whether an Anti-CSRF parameter is in place
Login forms often include an Anti Cross Site Request Forgery (ACSRF) parameter to safeguard against intruders making form submissions in place of the intended client.
A common method for CSRF protection is a synchronizer token -- a unique known only to you and the server that corresponds to a unique session or render of the page. The server uses this value to verify that you (the client) are the person who submitted this form (not an intruder). If a ASCRF token is in place, you'll need the scanner to obtain and submit its value alongside your login credentials.
To find this value, use your browser's developer tools (e.g., right click-->Inspect in Chrome) and find the hidden parameter on the login form.
For instance, in the javaspringvulny application, the ACSRF parameter is input type="hidden" name="_csrf" value="e8fb0107-cc4c-42dd-bf1b-3d548a3629f6
:
<form action="/login" method="post"><input type="hidden" name="_csrf" value="e8fb0107-cc4c-42dd-bf1b-3d548a3629f6">
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" name="username" id="username" aria-describedby="usernameHelp" placeholder="Enter Username" autocomplete="off" style=[...]">
<small id="usernameHelp" class="form-text text-muted">The username of your search account.</small>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" name="password" placeholder="Password" autocomplete="off" style=[...]>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Note that the value for the _csrf
parameter is unique to your session.
Note the name of this value -- you'll be configuring it in app.antiCsrfParam
(in addition to the usernamePassword
configuration).
Step 2: Determine the login fields
Also in the form HTML above are the input type
fields which correspond to the credential types that you'll configure in usernamePassword.usernameField
and usernamePassword.passwordField
. Note these values in your login form HTML.
In the above example, these fields are username (name="username"
) and password (name="password"
).
Step 3: Validate which AuthZ mechanism is in place
Cookies are a common means of authorization (AuthZ) in a form login context, though other means are possible as well (notably, tokens).
With developer tools on, log into your application and note the authorization values in the network traffic between the browser and the application.
In the case of javaspringvulny, the AuthZ mechanism is the JSESSIONID cookie that can be seen in the Set-Cookie
header in the response to a successful login:
Note the name of the cookie(s) returned -- you'll configure these later.
Step 4: Determine a test path
Identify a path in the application that can only be accessed while authenticated.
Then, determine how to identify a successful request (for instance, the application returns an HTTP 200 OK status code when receiving a GET to the page which includes the AuthZ mechanism).
In javaspringvulny's case, the /search
page requires authentication, and will return a 200 OK if authenticated (or a 302 redirect to the /login
page if not authenticated).
You'll configure either the success
or fail
field with a regex value that matches what you're looking for in a response from the application.
Step 5: Configure the scanner
Now that you've obtained the various login components, it's time to configure them in stackhawk.yml
.
Here's how they all slot into the form auth configuration for javaspringvulny:
app:
applicationId: ${APP_ID:dacc7d3e-babc-47d2-b040-ab117ab04526}
env: ${APP_ENV:dev}
host: ${APP_HOST:https://localhost:9000}
antiCsrfParam: "_csrf"
authentication:
loggedInIndicator: "\\QSign Out\\E"
loggedOutIndicator: ".*Location:.*/login.*"
usernamePassword:
type: FORM
loginPath: /login
loginPagePath: /login
usernameField: username
passwordField: password
scanUsername: ${USERNAME}
scanPassword: ${PASSWORD}
cookieAuthorization:
cookieNames:
- "JSESSIONID"
testPath:
path: /search
success: "HTTP.*200.*"
When the scanner is run with the above configuration, the follow occurs in sequence:
Visit the
/login
page with a GET and obtain the_csrf
token value (from the loginPagePath config)Perform a form-encoded POST to the
/login
page containing:_csrf=(value obtained from the initial loginPagePath GET)
username=(username value passed to the scanner as the environment variable USERNAME)
password=(password value passed to the scanner as the environment variable PASSWORD)
Visit the
/search
page using the default method (GET); send the JSESSIONID cookie value in the Cookie header (Cookie: JSESSIONID=<value>
)if an HTTP 200 (OK) message is found in the login response headers or body, proceed with the scan
if no string in the response headers or body matches the success value, terminate the scan with an authentication error
Proceed with scanning the application
monitor the state of JSESSIONID throughout
if
loggedInIndicator
/loggedOutIndicator
indicate that the scanner is logged out, re-authenticate with the application then proceed with the scan
Note: See Environment Variable Runtime Overrides for details on injecting credentials or other configuration values at runtime.
Auth Request Structure
Relevant request headers:
The login request will include this header:
content-type: application/x-www-form-urlencoded
Request body examples:
The POST body will be comprised of the values you've configured. For instance:
No AntiCsrfParam / no additional params:
<username_field>=<password>&<password_field>=<pasword>
AntiCsrfParam configured / no additional params:
<csrf_token_name>=<csrf_token_value>&<username_field>=<username>&<password_field>=<password>
AntiCsrfParam configured / additional params configured:
(additional param config):
otherParams:
- name: "remember_me"
val: "true"
Resulting POST body:
<csrf_token_name>=<csrf_token_value>&<username_field>=<username>&<password_field>=<password>&remember_me=true
Additional Information
Form Auth Demo:
Scanning the javaspringvulny application using form-encoded authentication:
Authenticated Scanning Primer
For a general overview on the concepts mentioned above, see Getting Started Guide: Authenticated Scanning.
Different Form Types
Not all login forms generate form-encoded POST's. For instance, your login form(s) may utilize JSON payload (content-type: application/json
) instead. In the application/json scenario, you may be able to either:
utilize
type: JSON
in usernamePassword.type (see Authenticating HawkScan to applications using JSON POST)utilize a custom authentication script (see Authenticating HawkScan to applications using custom JSON payloads)