Faraday
Faraday is a platform to facilitate security assessments, by providing a dashboard interfacing the results of many cybersecurity tools.
- Documentation (βͺ)
- Open-source (4.2k β) with a paid-plan
- Supported tools (nmap, metasploit, ping, ZAP, W3af, Nessus...)
Supported tools are plugins in Python. It's quite easy to write your own. The plugin development section is a good start.
After installing faraday, you can access it at http://localhost:5985/
.
Terminology π
- A workspace π is a separate dashboard usually associated with one security assessment.
- A host π§ is a device, such as a computer, that was detected, and may contain vulnerabilities.
- A host may have services π running such as HTTPS/443.
- A host may have vulnerabilities 𧨠which are either created manually or imported from a file or a command.
See also: Faraday CLI.
Install and configure Faraday
You can install faraday using Docker Compose:
$ mkdir faraday && cd faraday
$ wget https://raw.githubusercontent.com/infobyte/faraday/master/docker-compose.yaml -O docker-compose.yml
$ docker compose up -d
[...]
Admin user created with username: faraday password: password
To access faraday-*
binaries, connect to the docker:
$ docker exec -it $(docker compose ps -q app) /bin/bash
To shut down all services, use:
$ docker compose stop
Run as a service
When running as a service, faraday will always be running, and you won't have to start/stop/restart it.
Assuming you did the previous commands, do:
$ docker compose down
$ docker swarm init
$ docker stack deploy -c docker-compose.yml faraday
β‘οΈ You should use docker secrets
instead of plaintext passwords inside the docker-compose.yml
.
Configuration
By default, configuration files and logs are stored inside ~/.faraday
.
Plugins development
Faraday will look for plugins inside its default plugin folder, and inside the Custom Plugin Folder (CPF).
You first need to change its value, which is stored inside the database. You only have to do it once.
$ faraday-manage settings -a update reports --data '{"custom_plugins_folder": "/home/faraday/.faraday/faraday_plugins/"}'
β‘οΈ Use faraday-manage settings -a show reports
to check its value.
β‘οΈ The command assumes that ~/.faraday/faraday_plugins
will be used to store your custom plugins (same folder on host and docker).
Basics
Each plugin has its own folder with an empty __init__.py
and a plugin.py
file. To develop on the host, you need to install:
$ pip install faraday-plugins
There are two types of plugins, while one plugin can have both:
-
command
: a plugin parsing a command output -
file
: a plugin parsing a file report
Plugins can only create vulnerabilities. A new vulnerability is created after each import, unless there is already a vulnerability that is the exact same (e.g., all attributes have the same value).
π There is one exception: if a vulnerability was marked as "closed," it becomes "re-opened" if re-imported in a scan.
By default, for file report plugins, the name and type of file determine which plugin will parse it. Only .xml
, .txt
, and .zip
extensions are (currently) allowed. To by-pass this, rename your report file to match this regex: .*_faraday_plugin_name.*
as it's the first element used to determines which plugin is loaded.
Basic templates
Here are some empty templates to get started:
plugin.py
: file plugin template
from faraday_plugins.plugins.plugin import PluginBase
class XXXClass(PluginBase):
def __init__(self, *arg, **kwargs):
super().__init__(*arg, **kwargs)
self.id = "xxx"
self.name = "xxx"
self.plugin_version = "0.0.1"
self.version = "0.0.1"
# output is a string with all lines of the files
# you need to parse them
def parseOutputString(self, output):
# read the code of others plugins to
# write your parser
pass
def createPlugin(*args, **kwargs):
return XXXClass(*args, **kwargs)
test.py
: template to test your parser
While there are tools to easily test your plugin, to test your parser, you may use this sample script:
# assuming we are in a plugin's folder
from pathlib import Path
# ./plugin.py contains "XXXClass"
from plugin import XXXClass
with Path('my_test_file.txt').open(**{"mode": "rb"}) as f:
plugin = XXXClass()
plugin.parseOutputString(f.read())
Faraday commands
Inside your script, using the data you got from parsing a file or a command, you'll call them methods:
# create a host, e.g., a target having vulnerabilities
host_id = createAndAddHost(...)
# create a host, and add a service to it (ex: HTTP/80)
service_id = createAndAddServiceToHost(...)
# add a vulnerability to...
vuln_id = createAndAddVulnToHost(...) # a host
vuln_id = createAndAddVulnToService(...) # a service
vuln_id = createAndAddVulnWebToService(...) # a web service
Faraday API
Faraday API is documented in their OpenAPI specification, along inside the API Server Page, but some routes are missing.
You can access the OpenAPI page for a local installation at http://example.com:5985/api-definitions
or User > Faraday API
.
Assuming the following Python script:
from requests import Session
username=''
password=''
server_address=''
workspace_name=''
headers={'Content-Type': 'application/json'}
print('Authentication to server {0}'.format(server_address))
session = Session()
- Login
response = session.post(server_address + '/_api/login', json={'email': username, 'password': password})
# status_code == 200
- Get all vulnerabilities in a workspace
response = session.get(server_address + f'/_api/v3/ws/{workspace_name}/vulns', headers=headers)
result = response.json()
# status_code == 200
- Delete a vulnerability by ID
vuln_id = ''
response = session.delete(server_address + f'/_api/v3/ws/{workspace_name}/vulns/{vuln_id}')
# status_code == 204
- Update a vulnerability
vuln_value = {} # fetch the vulnerability first
response = session.put(server_address + f'/_api/v3/ws/{workspace_name}/vulns/{vuln_id}', json=vuln_value)
# status_code == 200
- Upload a report
response = session.get(server_address + f'/_api/session', headers=headers)
token = response.json()['csrf_token']
# status_code == 200
files = {'file': open('xxx','rb')}
values = {'csrf_token': token}
response = session.post(server_address + f'/_api/v3/ws/{workspace_name}/upload_report', files=files, data=values)
# status_code == 200
π» To-do π»
Stuff that I found, but never read/used yet.
- internal API URL