Functions

SecApps Cohesion can be extended with user-supplied functions written in JavaScript. These functions can be used to change requests, use custom business logic, provide extra logging and much more.

Function Usage

To define a function, simply create a file with a module export. You can use the following template:

module.exports = function (request) {
    // TODO: add code here

    return request
}

To execute, we need to use a function command option, such as the "--target-func". For example:

$ cohesion fuzzer --target-func=/path/to/auth.js 01.request

If the function is within the current directory, it can be referenced by name too. For example:

$ cohesion fuzzer --target-func=auth 01.request

This command will load the function from file "auth.js".

This mechanism also allows us to explicitly specify the name of the function if it is not the module export. For example:

exports.func = function (request) {
    // TODO: add code here

    return request
}

Then the command is:

$ cohesion fuzzer --target-func=auth.func 01.request

Functions cannot be configured via command line options but configuration is possible with environment variables. For example:

$ VAR1=a VAR2=b cohesion fuzzer --target-func=auth.func 01.request

The authentication function now can reference both VAR1 and VAR2 variables in the following way:

exports.func = function (request) {
    const var1 = process.env.VAR1
    const var2 = process.env.VAR2

    // TODO: add code here

    return request
}

Target Functions

The target function is executed once for each loaded target (file or URL). This type of function is useful when some dynamic parameters need to be supplied to the request at runtime, such as dates, exchange rates, and authentication tokens. Requests can be generated dynamically too.

For example, the following function supplies an authorisation token:

const url = require('url')
const https = require('https')

module.exports = (request) => {
    return new Promise((resolve, reject) => {
        const options = url.parse('http://auth/token')

        const req = https.request(options, (res) => {
            const chunks = []

            res.on('error', reject)

            res.on('data', (data) => {
                chunks.push(data)
            })

            res.on('end', () => {
                const { token } = JSON.parse(Buffer.concat(chunks).toString())

                if (!request.headers) {
                    request.headers = {}
                }

                request.headers['Authorization'] = `Bearer ${token}`

                resolve(request)
            })
        })

        req.on('error', reject)
    })
}

Let's use the function:

$ cohesion fuzzer --target-func=auth.func 01.request

The file "01.request" contains the following request:

POST http://target/path HTTP/1.1
Host: target
Content-Type: application/json

{
    "param": "value"
}

Once the function is executed, the request will be changed to the following:

POST http://target/path HTTP/1.1
Host: target
Content-Type: application/json
Authorization: Bearer token

{
    "param": "value"
}

With this function, we can be certain that the fuzzer will always have correct credentials for fuzzing.