Distributed version of RIVER. Cardinal can trace multiple testcases at a time and log the resulting traces.
./run.sh [binary-id] [runs] [cores] [benchmark-runs] [(no)rebuild] [(no)genetic]
binary-id = unique identification string of the benchmark binary
runs = number of testcases that are generated by base fuzzers
cores = number of tracer processes that run in parallel
benchmark-runs = number of repetitions for current benchmark
(no)rebuild = if "rebuild", node-river build is updated
(no)genetic = if "genetic", river.genetic component is enabled to enhance testcase quality
Cardinal is a distributed environment that searches for security flaws in multiple binaries at a time. Cardinal testing targets can be either executables or source code. Cardinal tests represent binary stream generated by state-of-art fuzzers. The tests represent input data for testing targets. Once tests are sent to targets as input stream, the execution trace is collected by Cardinal and stored inside a global coverage state corresponding to the target executable.
tracer.node is the Cardinal component that starts the target execution. It sends the test as input to target program and collects the execution trace. The execution is traced using RIVER, a dynamic binary translation system. The trace format is shown below.
mongo.rabbit.bridge component is based on Mongo Oplog. It tracks the Mongo changes in the tests collections and creates a Rabbit message corresponding to the test. The message is inserted in the corresponding Rabbit queue(new test or traced test).
process.manager represents the processes orchestrator. It is the utility that manages Cardinal subcomponents. process.manager starts/stops subcomponents, limits the number of running processes and allow user configuration of Cardinal. 'process.manager/processes.json' shows the configuration for each component process as command line. 'process.manager/resources.json' is the configuration file that allows limitation of component running instances. For example, if configuration file contains: 'tracer.node : 10', then a maximum of 10 process instances of 'tracer.node' are allowed to run simultaneously.
river.genetic is a component that allows ranking input by the basic blocks exercised in the target program. In this manner, only inputs that discover new code or inputs that discover new paths are kept and used for mutations. This component can be disabled from command-line. Cardinal is more efficient when 'river.genetic' is enabled.
The individual traces produced by 'tracer.node' represent the path in binary described by ordered basic blocks followed by target program when individual input is sent at runtime. One program execution shows one path. By gathering these paths together per each executable, Cardinal is able to show a global coverage state showing what basic blocks where exercised, how many times and what are the ancestors (incoming edge). The state aggregator is able to gather the traces from database and grouping these in local and global collections. The global collections per executable represent the current coverage obtained by Cardinal in testing the executables.
The components is a helper for state.aggregator and can be used by command line to clean coverage data by executable id.
Cardinal has a user-friendly interface that allows showing the status of each executable tested with Cardinal. It shows how many tests were traced, how many of them failed (possible vulnerabilities), what resources are used for testing each executable and the global coverage state.