Introduction

The PAC application enables users to write and upload their own custom attack scripts to the platform. This level of customization allows for the development and deployment of unique business logic attacks across an entire suite of enterprise applications with ease. These attacks should be compliant with one of the scanners PAC supports.

Common Vulnerabilities and Exposures (CVE)


Custom attacks are categorised under the CVE section of the PAC configuratin file.

This documentation provides the complete steps about how to use the custom scripts in PAC.

Prancer PAC also supports running of custom Bash shell scripts as part of custom codified attacks.

Setup the Git Repository

Custom attacks in the Prancer platform will need to be linked to a Git repository in a particular location. There are two files that are needed in your Git repository; the codified attack script and the metadata YAML configuration file. To better show this, we will go over an example script below.

Codified Attack File

http_sender_attack.js

  • This example script will check every response made during a penetration test and generate an alert for every response which satus code is equal to 400 or more, up to 599.
// A script which will raise alerts based on HTTP Response codes
// By default it will raise 'Info' level alerts for Client Errors (4xx) (apart from 404s) and 'Low' Level alerts for Server Errors (5xx)
// But it can be easily changed.

var control, model
if (!control) control = Java.type("org.parosproxy.paros.control.Control").getSingleton()
if (!model) model = Java.type("org.parosproxy.paros.model.Model").getSingleton()

var Pattern = Java.type("java.util.regex.Pattern")

pluginid = 100000   // https://github.com/zaproxy/zaproxy/blob/main/docs/scanners.md

function sendingRequest(msg, initiator, helper) {
    // Nothing to do
}

function logger() {
    print('[' + this['zap.script.name'] + '] ' + arguments[0]);
}

var control
if (!control) control = Java.type("org.parosproxy.paros.control.Control").getSingleton()

function responseReceived(msg, initiator, helper) {
    var code = msg.getResponseHeader().getStatusCode()
    var extensionAlert = control.getExtensionLoader().getExtension(org.zaproxy.zap.extension.alert.ExtensionAlert.NAME)
    if (extensionAlert != null) {
        var code = msg.getResponseHeader().getStatusCode()
        if (code < 400 || code >= 600) {
            // Do nothing
        } else {
            var risk = 0    // Info
            var title = "A Client Error response code was returned by the server"
            if (code >= 500) {
                // Server error
                risk = 1    // Low
                title = "A Server Error response code was returned by the server"
            }
            // CONFIDENCE_HIGH = 3 (we can be pretty sure we're right)
            var alert = new org.parosproxy.paros.core.scanner.Alert(pluginid, risk, 3, title)
            var ref = msg.getHistoryRef()
            if (ref != null && org.parosproxy.paros.model.HistoryReference.getTemporaryTypes().contains(
                        java.lang.Integer.valueOf(ref.getHistoryType()))) {
                // Dont use temporary types as they will get deleted
                ref = null
            }
            if (ref == null) {
                // map the initiator
                var type
                switch (initiator) {
                    case 1: // PROXY_INITIATOR
                        type = 1 // Proxied 
                        break
                    case 2: // ACTIVE_SCANNER_INITIATOR
                        type = 3 // Scanner 
                        break
                    case 3: // SPIDER_INITIATOR
                        type = 2 // Spider 
                        break
                    case 4: // FUZZER_INITIATOR
                        type = 8 // Fuzzer 
                        break
                    case 5: // AUTHENTICATION_INITIATOR
                        type = 15 // User 
                        break
                    case 6: // MANUAL_REQUEST_INITIATOR
                        type = 15 // User 
                        break
                    case 8: // BEAN_SHELL_INITIATOR
                        type = 15 // User 
                        break
                    case 9: // ACCESS_CONTROL_SCANNER_INITIATOR
                        type = 13 // Access control 
                        break
                    default:
                        type = 15 // User - fallback
                        break
                }
                ref = new org.parosproxy.paros.model.HistoryReference(model.getSession(), type, msg)
            }
            alert.setMessage(msg)
            alert.setUri(msg.getRequestHeader().getURI().toString())
            alert.setDescription("A response code of " + code + " was returned by the server.\n" +
                "This may indicate that the application is failing to handle unexpected input correctly.\n" +
                "Raised by the 'Alert on HTTP Response Code Error' script");
            // Use a regex to extract the evidence from the response header
            var regex = new RegExp("^HTTP.*" + code)
            alert.setEvidence(msg.getResponseHeader().toString().match(regex))
            alert.setCweId(388) // CWE CATEGORY: Error Handling
            alert.setWascId(20) // WASC  Improper Input Handling
            extensionAlert.alertFound(alert , ref)
        }
    }
}

Metadata File

metadata.yaml

  • The metadata file contains the configuration details required for Prancer's PAC to run the attack. An example of the metdata.yaml file for the http_sender script is shown below.
Name: Alert On Http Response Code Errors
Type: httpsender
Engine: Oracle Nashorn
Description: A HTTP Sender Script which will raise alerts based on HTTP Response code
Charset: UTF-8
  • Save both the http_sender_attack.js and the metadata.yaml file in your specified Git repository. For example, we've saved the files inside of the Alert_on_HTTP_Response_Code_Errors directory:
Git repository
.
|___ Alert_on_HTTP_Response_Code_Errors
│    │   http_sender_attack.js
│    │   metadata.yaml

run-hello.sh

Here is a run-hello.sh Bash shell script which raises an alert. The condition can be added as per user requirements.

#!/bin/bash

# Source the prancer-lib shell script to call all pr-* library functions.
source shlib/prancer-lib.sh

# generate a hello alert, pass the target like: "https://brokencrystals.com/"
output=`pr_hello_world_alert "$1"`

# Check the output
if [ $? -ne 0 ];  then
  echo "Failed to generate alert!...."
else
  echo "$output"
fi

exit 0

For documentation on custom bash scripts refer to [../PAC/custom-bash-script.md]

metadata.yaml

Metadata file contains the configurations and details which are required for Prancer PAC to read.

Name: BashHello
Technology: standalone
Type: active
Engine: bash
Description: Run bash script to generate alert.
Charset: UTF-8
tags:
  Type: Blackbox, Web  

Save both run-hello.sh and metadata.yaml files under BashHello at particular location in git. For example, we saved files inside the BashHello in root folder of the repository.

Git repository
.
|___ BashHello
│    │   run-hello.sh
│    │   metadata.yaml

Store the Secrets in Key Vault

Prancer requires the secure storage of an authentication token or key to connect and clone the Git repository. To generate a Git access token from the Git console, please refer to the official documentation.

First, ensure the following permissions are provided when generating the token:

repo: Full control of private repositories
read: user Read ALL user profile data

With this newly generated token, you can now create a new entry in the Key Vault. In our example, the Key Name is the value of httpAccessToken and Key Value is the generated access token.

../img/pac/attacks/CVE_vault_upload.png

Create and Upload a Git Connector File


A Git Connector file will be used to connect our Git repository to the Prancer platform. This connector will be in JSON format and the information provided in the file enables Prancer to run custom attacks from your repository. An example of the Git Connector file:

azure_custom_script_connector.json

{
    "branchName": "main",
    "companyName": "prancer",
    "fileType": "structure",
    "gitProvider": "https://github.com/prancer-io/prancer-pac-sample.git",
    "httpsAccessToken": "secret-git-key",
    "private": true,
    "type": "filesystem"
}

Breakdown of the fields in the JSON connector file:

Field Value Description
container container name The container name should be match with the value of Collection property defined in PAC config file.
name connector name Any name of the connector which will use to define in PAC config file
gitProvider clone URL The URL for clone the git repository.
branchName branch name Git branch name where the zap scripts are available
httpsAccessToken secret key Any secret key which will be used to store the git token in the key vault

Once the Git Connector file has been created, upload the file by using the drag and drop feature or selecting the 'click here' option on the desired collection.

../img/pac/attacks/CVE_upload_file.png

Create a PAC Application from the PAC Wizard

  • Use the PAC Wizard to create a PAC configuration file.
  • Existing PAC config files can also be edited to include the new custom attack. Exisitng PAC files can be found in Inventory Mangement or visible under the assigned collection.

Once created, you will be presented with the PAC config file editor and your file should look similiar to the example shown below:

Collection: azure_remote_test
ConnectionName: azure_remote_test_connector
CloudType: azure
ApplicatioName: Azure Remote Application
RiskLevel: safe
Compliance:
- CSA-CCM
- HIPAA
- ISO 27001
- SOC 2
- HITRUST
- NIST 800
ApplicationType: APIScan
Schedule: onetime
Target: http://prancersampleapp01.eastus2.cloudapp.azure.com:8888
# You can use postman collection as code for running attack inside the prancer.
# Connector defines the name of the git connector available in the collection.
# Postman remote files should include a path which has postman collection file and
# for postman env remote files, if you have environment variable file you can put
# the path inside the postmanEnvRemote file so prancer will go and extract the env
# variables and their values and merged it with postman collection.
APIScan:
  Type: OpenAPI
  DirectionProvider: git
  Direction: http://prancersampleapp01.eastus2.cloudapp.azure.com:8888/v2/swagger.json
  PostmanRemoteFile: remote_postman/postman_collection.json
  PostmanEnvRemoteFile: remote_postman/postman_environment.json
  Connector: azure_postman_connector
Scanner:
  Cloud:
    Platform:
      Azure:
        ContainerInstance:
          AfterRun: delete
          NewContainerInstance:
            External:
              SubscriptionId: 12345678-1234-5678-abcd-1234abcd4567
              ResourceGp: testgroup
              Region: eastus2
              ContainerGroupName: prancer-scanner-group
              ContainerName: prancer-pentest-instance
              ResourceName: prancer-instances-1
AuthenticationMethod: noAuthentication
AddOns:
- accessControl
- ascanrulesBeta
- sqliplugin
- directorylistv2_3
- portscan
- pscanrulesBeta
- websocket
- fuzzdb
- fuzzdboffensive
- fuzz
- graphql
- openapi

Update the PAC Config file:

  • Once your PAC config file has been created, it's time to add your Custom Attack to the application.
  • Open the Inventory Management section of Prancer and click PAC Configuration on the application you'd like to add your attack to.

../img/pac/attacks/CVE_PAC_configure.png

  • Add the CVE field in the PAC configuration file.

Example template:

CVE:
- Path:
    Include:
    - .*\.js
    - abc.java
    - BashHello
    Exclude:
    - .*\.py
  Connector: azure_custom_script_connector
Field Value Description
Connector connector name the container name which you specified in Git connector.
Path Include and Exclude paths Contains list of include and exclude paths
Path.Include list of path Contains list of script paths ( Regex ) which need to include in processing
Path.Exclude list of path Contains list of paths ( Regex ) which will be excluded while load the scripts.

Complete PAC File

Collection: azure_remote_test
ConnectionName: azure_remote_test_connector
CloudType: azure
ApplicatioName: Azure Remote Application
RiskLevel: safe
Compliance:
- CSA-CCM
- HIPAA
- ISO 27001
- SOC 2
- HITRUST
- NIST 800
ApplicationType: APIScan
Schedule: onetime
Target: http://prancersampleapp01.eastus2.cloudapp.azure.com:8888
# You can use postman collection as code for running attack inside the prancer.
# Connector defines the name of the git connector available in the collection.
# Postman remote files should include a path which has postman collection file and
# for postman env remote files, if you have environment variable file you can put
# the path inside the postmanEnvRemote file so prancer will go and extract the env
# variables and their values and merged it with postman collection.
APIScan:
  Type: OpenAPI
  DirectionProvider: git
  Direction: http://prancersampleapp01.eastus2.cloudapp.azure.com:8888/v2/swagger.json
  PostmanRemoteFile: remote_postman/postman_collection.json
  PostmanEnvRemoteFile: remote_postman/postman_environment.json
  Connector: azure_postman_connector
CVE:
- Path:
    Include:
    - .*\.js
    - abc.java
    - BashHello
    Exclude:
    - .*\.py
  Connector: azure_custom_script_connector
Scanner:
  Cloud:
    Platform:
      Azure:
        ContainerInstance:
          AfterRun: delete
          NewContainerInstance:
            External:
              SubscriptionId: 12345678-1234-5678-abcd-1234abcd4567
              ResourceGp: testgroup
              Region: eastus2
              ContainerGroupName: prancer-scanner-group
              ContainerName: prancer-pentest-instance
              ResourceName: prancer-instances-1
AuthenticationMethod: noAuthentication
AddOns:
- accessControl
- ascanrulesBeta
- sqliplugin
- directorylistv2_3
- portscan
- pscanrulesBeta
- websocket
- fuzzdb
- fuzzdboffensive
- fuzz
- graphql
- openapi

Run the Pentest:

Now that everything is set up and the custom attack has been added to the PAC file, we can begin testing. Click the Start button on your PAC file to begin running the pentest.

../img/pac/attacks/CVE_run_pentest.png

  • The amount of time needed to complete a test will vary depending on the size of your environment. The current status will be listed towards the bottom of the PAC file.
  • You can check on the results of the test at any point by clicking on the See Latest Results option towards the bottom of the PAC file.

../img/pac/attacks/CVE_see_results.png

  • Clicking this option will bring you to the Application Security Findings page.
  • Note, if multiple scans have been run using the same PAC file, the results will need to be filtered to narrow down the

../img/pac/attacks/CVE_pentest_result.png

../img/pac/attacks/CVE_pentest_result_bash.png

Run the Pentest using CLI:

Check how to run the Pentest using CLI