In my previous post I discussed a range of tools that can help automate security testing within the development pipeline. One of those tools was Gauntlt. Gauntlt is one of the more common CI security frameworks out there offering support a for range of commonly used security testing tools, from simple port scans to more intrusive tests such as SQL injections.
The aim of this post is not only to make you aware of Gauntlt but to offer guidance in configuring and implementing Gauntlt within your environment. I’ve even put together the Docker contents to aid this process.
This post will cover:
So what is Gauntlt? In simple terms Gauntlt is an attack framework that enables us to run a range of attacks and parse the output in a CI friendly form, allowing for our CI server to take an action based the response. Whether that’s to block the build, create an issue, notify or proceed will depend on the CI configuration.
Gauntlt natively supports the range of security testing tools. As of the time of writing the following are supported; I’m not going to go into too much detail about each as the focus here is Gauntlt but hopefully the brief descriptions below will suffice.
One key thing to understand is Gauntlt doesn’t provide these tools, it’s just a wrapper that will enable you to bring the tools into the pipeline. Configuring these tools to be friendly with Gauntlt can at times present a challenge. To make things easier I’ve done it for you. The links below will provide the data of a Docker container that’ll work out of the box. This build is actively used so if something does breaks chances are it’ll be fixed soon. Link to built docker image also provided however the github repo will allow much more flexibility – all you need to provide is the attack files. We’ll cover that soon.
Gauntlt Docker Data – https://github.com/garytkainos/Gauntlt-Ubuntu
Gauntlt Docker Image – https://hub.docker.com/r/garyt225/gauntltkainos/
So now we all know what Gauntlt is and the potential benefits let’s move onto the configuration. Again won’t be going into depth when it comes to each individual tool, the installation instructions can be found on each individual site. The key thing for Gauntlt is to ensure it can find the tools, the attack files will detail how it’s picking up the tool location. Best practice is to either amend your PATH variable or create a unique path variable just depending on what suits best. Example below:
export garmr_path=/usr/local/bin/garmr export PATH=$PATH:/gauntlt/arachni/bin
If making use of the Docker container provided all you need is to provide the attack files. The creators of Gauntlt provide plenty of examples and is easy enough to pick up; below is an example attack file along with explanations of key areas.
Before we can start writing our attack files, we need to have a basic under standing of Cucumber and Gherkin syntax. You don’t need to be an expert or have extensive programming experience as Gauntlt has done most of the required configuration.
So a quick crash course on Cucumber / Gherkin – nothing too in-depth but I’ve provided a few links in the useful resources section.
So firstly, what is Cucumber and Gherkin?
Gherkin – a simple plain text structured language
Cucumber – used to interpret and execute the Gherkin code.
Gherkin has several key terms for writing and structuring your feature files. When putting these together from scratch you need two files, one feature file and a step definition.
Key terms for Gherkin are listed in the below table.
Feature file – This will be your plain English, structured in a readable format. i.e.
Feature: Check login works Scenario: Log into website When Username is provided login Then Login to website And Check login status
The above is a very simplified feature file, but hopefully will give you a general idea on how the syntax works. The main question from looking at this is how does Cucumber know what to do with it? That’s where the step definition comes in.
Step definition file will contain hooks for each steps defined in your feature file, the definition file will contain the actual code for performing the scenarios, whether that’s checking something is installed or more complex operations. So when the feature file states “Then Login to website” Cucumber will look for a matching scenario and “Then” statement within the step definitions and execute the code within.
Before going any further, just a small note. The terminology is going to slightly change; the above is just a introduction of Gherkin / Cucumber in its rawest form. Gauntlt incorporates this technology in its own way.
Feature files = Attack Files
Step Definition files = Attack Adapters
Below is an example of a real attack file, it will check that SSLv2 and SSLv3 are disabled. Looking at the below example you’ll see similarities to the generic example above, main difference being we’ve added in a data table, this is used to store reusable values throughout the file. Data tables provide the benefit of simplifying the structure, especially with larger files.
Attack File Feature: Run sslyze against a target Background: Given "sslyze" is installed And the following profile: | name | value | | hostname | www.kainos.com | | port | 443 | Scenario: Ensure no SSLv2 and SSLv3 are disabled When I launch an "sslyze" attack with: """ sslyze --sslv2 --sslv3 <hostname>:<port> """ Then the output should not contain: """ Accepted """
Comments Attack files are written in Gherkin, making it easy to understand and write. There is three main sections to this attack file, with key terms throughout: Feature - A description of that attack Background - Used to store some prerequisites and the data table values. Scenario - this is where the attack will be detail key commands and expected (or not expected) response. In this attack file we have the a standard sslyse command string checking for SSLv2/3 support. You can also see we've added in <hostname> this will be pulled from the profile setting defined in the background session. While not overly useful in this example defining variables within the profile can be extremely beneficial when dealing with large attack file.
The above attack file will have an associated attack adapter (step definition) for each of the terms defined, Gauntlt will store these in two different place.
<Gauntlt_Path>/lib/gauntlt/attack_adapters - Specific hooks for tools <Ruby_Gems_Path>/aruba-0.5.4/lib/aruba/cucumber.rb - Generic reusable hooks ("Output should contain" etc)
Examples of the adapters are below:
This code is provided by Gauntlt so for the most part we don’t need to worry about it but awareness of how it all hangs together can be very beneficial when implementing and maintaining in a live environment.
One final thing I’d like to cover around the operation of these attack files is Tags, these are used to classify a feature file and additionally add some code across multiple files. Tags begins with the @ symbol and can either be used across entire feature file or individual scenario. Gauntlt primarily makes use of these to signify how long an attack will take. By default, we have the following:
No Tag - Each scenario will run for up to 3 seconds @slow - Each scenario will run for up to 30 seconds @reallyslow - Each scenario will run for up to 10 minutes
So that’s a high overview of how the attack files are put together. Next I want to run this attack file and take a brief look of what Gauntlt is doing in the background.
Firstly before running this attack to get a better appreciation of what Gauntlt is doing lets run sslyze without Gauntlt.
So in the attack file the command we specified is “sslyze –sslv2 –sslv3 <hostname>:<port>” Gauntlt will take this command, run it and look for key terms to indicate a pass or failure.
Before creating our attack file we need to understand what output will be presented by the security tool, in this case sslyze.
So just to clarify in this scenario we want to ensure our website does not accept communications over SSLv2 or SSLv3, these are old and highly vulnerable protocols and is generally recommended to keep disabled.
Below you can see the output. One small thing to note, for demonstration purposes I’ve added a few extra switches.
–tlsv1_2 – added to demonstrate expected output when protocol is enabled (SSLv2/3 are disabled)
–hide_rejected_ciphers – purely added into reduce the noise of the output, key information will still be presented.
You can see here that SSLv2 and SSLv3 are rejected, we can also see the output of sslyze when those protocols are rejected. TLSv1.2 is enabled on this site and again we can see the sslyze output when the protocols are accepted. There are multiple ways we can use this output to indicate a pass or failure for this example I took the simple approach of looking for the word “Accepted”. When only checking SSLv2 and SSLv3 the term “Accepted” should not show as it does for TLSv1.2. This is a very simple approach and check, you can of course take things further and check for specific ciphers.
Now when we run Gauntlt with the above attack file, we’ll see a slightly different output than shown in sslyze. We can see the command executed and the results. The Attack file ran sslyze to check for SSLv2/3 and then checked for the term “Accepted” in the output, that term was not found so it was marked as a success, if the term accepted was found it would have failed.
When you initiate Gauntlt by default it will search the system for *.attack files, will then take all of the attack files and run through the provided scenarios. Alternatively you can specify the attack file as such “Gauntlt Nmap.attack”
Gauntlt will work out of the box to cover most requirements, however if you’re wanting to make more extenisive use of Gauntlt there’re various ways you can expand out the from the basic attack. There are multiple ways of doing this, in the example discussed below I’ve modified some of the configuration files within Gauntlt to perform additional testing. This could also be accomplished via using the “generic” attack, using Gherkin / Cucumber in its rawest form. While you can do this I find some benefits in amending Gauntlt’s configuration.
This is my own opinion and preference, you can adapt the attacks in whatever way suits your team or project requirements.
The best example for expanding from the normal, default attacks is probably Arachni, out of the box Gauntlt / Arachni attack scenarios only supports XSS attacks. This can easily be expanded by adding in new attack aliases.The attack aliases files can normally be found here – <Gauntlt_Path>/lib/gauntlt/attack_aliases/
The attack aliase files are written in JSON, containing attack the aliases and the Arachni command string. When creating new aliase for the most part it’s a copy and paste exercise, only things to note are:
So once you add in your custom aliases what will the attack files look like? Below is an example of one that will test for 5 different common security misconfigurations. (This configuration comes included in the Docker Container provided as part of this post.)
@reallyslow Feature: Look for forms with file upload functionality Background: Given "arachni" is installed And the following profile: | name | value | | url | https://www.kainos.com | | depth | 1 | | timeout | 00:09:00 | Scenario: Using the arachni, look for for forms with file upload functionality and verify no issues are found When I launch an "arachni-form-upload" attack Then the output should contain "0 issues were detected." Scenario: Using the arachni, Looks for resources served over HTTP when the HTML code is server over HTTPS. When I launch an "arachni-mixed-resource" attack Then the output should contain "0 issues were detected." Scenario: Using the arachni, Logs cookies that are served over an encrypted channel but without having the secure flag set. When I launch an "arachni-insecure-cookies" attack Then the output should contain "0 issues were detected." Scenario: Using the arachni, look for unallowed HTTP methods When I launch an "arachni-allowed-methods" attack Then the output should contain "0 issues were detected." Scenario: Using the arachni, Checks whether or not the session cookie can be set to an arbitrary value When I launch an "arachni-session-fixation" attack Then the output should contain "0 issues were detected."
Again this is just one way to go about it, there are easier ways such as using the generic attack file, containing the full command and output check. It all comes down to personal preferences and end goals.
Integrating with CI
So now we have a working instance Gauntlt configured whats next? The main purposes of Gauntlt is to enable continuous security testing as part of you developement pipeline. There are multiple ways of doing this, some of which will be dependent on your CI tool of choice, for the most part I’d recommend making use of Docker. This allows the CI to temporarily spin up the attack platform, carryout the testing and get the output. Personally for most project I use Gitlab-CI which has great integration with Docker, making the task even easier. Many of the major CI tools out there tend to offer some sort of Docker support.
Doing over the integration of Gauntlt into Gitlab-CI / TeamCity / Jinkins etc would be a lengthy post in its own so won’t be going into too much detail here. Below are some snippets of config from a Gitlab-CI instance.
Pipeline deployment code (the Gauntlt part)
'gauntlt': stage: security-webvulnscans image: GitLab-Docker-Repoistory/main-site.com/image:latest script: - export SSLYZE_PATH=/usr/local/bin/sslyze - export garmr_path=/usr/local/bin/garmr - export PATH=$PATH:/gauntlt/arachni/bin - gauntlt
The above code will take place after security tests such as static code analysis and deployment to the test environment. The attack files will be pointed to the test environment. Gauntlt will run before committing the code to the live environment. One of the easiest options to for this is to spin up the code in a Docker container, then run the tests against that, if it passes all tests the code to be committed.
Gitlab-CI executing Gauntlt.
So there you have it, a closer look at Gauntlt. In this post we’ve look at how Gauntlt interacts with commonly used security testing, how Gauntlt works under the hood and more importantly how we can use it for continuous security testing. Gauntlt is a framework, it can be implemented in many ways the above approach is just one of many ways you can implement Gauntlt the exect implimentation will depending on project requirements, pre-exisiting environment and personal preference. Hopefully this post has pointed you in the right direction.