Cipherfix is a framework for finding and mitigating ciphertext side-channel leakage. It combines dynamic binary instrumentation and dynamic taint analysis to analyze the target binaries and pinpoint potentially vulnerable code parts. Then, it uses static binary intrumentation to produce binaries hardened against ciphertext side-channels.
Note: This is a proof-of-concept implementation. We currently do not support the entire x86 instruction set and make some assumptions about the structure of the analyzed binaries, so it is possible that the analysis and/or instrumentation fail on certain systems or configurations.
In the following, we describe how to set up Cipherfix and its dependencies, and how to use it to harden a binary against ciphertext side-channel leakage.
If you just want to reproduce the analyzed targets from the Cipherfix paper, feel free to skip to the Running the example targets section.
The static instrumentation application and the evaluation tool are based on .NET 6.0, so the .NET 6.0 SDK is required for compiling.
The analysis tools all rely on Intel Pin 3.26. We assume that there is a PIN_ROOT
environment variable that points to Pin's base directory. This can be done per session with export PIN_ROOT=/path/to/pin
.
All framework modules can be compiled at once by running ./build-all.sh
.
As a running example, we use a binary that computes an EdDSA signature using the WolfSSL library:
.../examples
wolfssl/
eddsa/
app
To run the taint and structure analysis run
./analyze.sh <working directory> <library path> <interesting images> <main binary> [<application arguments>]
Arguments:
- Working directory: Path to directory containg the application binary, e.g.
$(pwd)/examples/wolfssl/eddsa
. - Library path: Path to needed shared libraries (for LD_LIBRARY_PATH), e.g.,
$CF_WOLFSSL_DIR/lib
. - Interesting images: List of image IDs which should be taken into consideration during analysis, e.g.,
"1;4;5;6"
.
Whenever Pin instruments a binary (application or shared library), it assigns an image Id. Usually, ID 1 refers to the application itself, ID 2 and 3 refer to vDSO and the dynamic linker (which have to be ignored), and subsequent IDs to libc and the application's other dependencies (e.g. ID 4 forlibwolfssl.so.34
). The IDs can be determined by looking at the first few lines of the generated$(pwd)/examples/wolfssl/eddsa/structure.out
file (specify only image ID"1"
initially and then re-run). - Main binary: Name of the application binary, e.g.
app
. - Application arguments (optional): Arguments for the application itself, e.g.
10 perf
(run 10 iterations, do not output intermediate results).
The taint analysis may print a number of warnings and a few errors about unknown instructions. Usually, those instructions are rather obscure and can be ignored, as they do not touch secrets and thus don't need masking.
This will produce four files:
$(pwd)/examples/wolfssl/structure.out
: Results of the structure analysis. This file needs to be manually modified before static instrumentation (see below).$(pwd)/examples/wolfssl/static-vars.out
: Static variables, needed for taint tracking.$(pwd)/examples/wolfssl/taint.out
: Taint tracking results.$(pwd)/examples/wolfssl/taint.out.memtrace
: Memory trace for evaluation. Only needed for leakage analysis of the instrumented binaries.
To statically instrument the application and its dependencies run
./instrument.sh <working directory> <mode> [<flags>]
Arguments:
- Working directory: Path to directory containing the application binary and the analysis results, e.g.
$(pwd)/examples/wolfssl/eddsa
. - Mode: Instrumentation mode (
base
,fast
orenhanced
). - Flags (optional): Instrumentation flags to specify the PRNG used for mask generation and various evaluation/debugging flags. If no flags are specified, the
rdrand
PRNG is used.
Relevant flags:
aesrng
: AES-based PRNG.xsprng
: XorShift128+ PRNG.evalmarker
: Include evaluation markers (needed to align traces of original and instrumented binaries)
Flags can be concatenated with -
, e.g. aesrng-evalmarker
.
On the first run, the instrumentation tool will most likely immediately exit and produce a list of heap allocation function candidates and call stacks. The following steps are difficult to automate reliably, and thus need to be done manually. For an example, see Running the example targets below.
-
Open
structure.out
in a text editor (or useecho
-based concatenation, see example linked above). -
Check the outputs of the static instrumentation run to identify heap (re)allocation functions and append them at the end. Those are both the entries that belong to
malloc
-style functions in the.plt
-sections of the binaries and the actual allocation functions from libc (malloc
,calloc
,realloc
). Allocations start withMm
(malloc
) orMc
(calloc
), whereas reallocations start withMr
, followed by the address that is output by the instrumentation tool.The instrumentation tool automatically tries to fetch the symbol name associated with a given offset; if this fails, the symbol name may be extracted via
objdump -d --start-address 0x<offset> --stop-address 0x<offset+1> /path/to/binary
Re-running the instrumentation tool should now produce instrumented binaries in a new <working directory>/instr-<mode>[-<flags>]
directory, e.g.
.../examples/wolfssl/eddsa/
app
instr-base/
app.instr
libc.so.6.instr
libm.so.6.instr
libwolfssl.so.34.instr
The instrumented application binary is named <main binary>.instr
and takes the same arguments as the original binary.
In the example, the instrumented binary can be run with
cd $(pwd)/examples/wolfssl/eddsa/instr-base/
chmod +x app.instr
./app.instr 10
We offer a tool to check whether there are remaining ciphertext leakages after static instrumentation.
To run the leakage analysis, first re-instrument the binary with the evalmarker
flag.
This will insert special marker instructions into the instrumented binary, that allow the memory trace comparison tool to align single memory writes from the original binary with memory write sequences from the instrumented binary.
The instrumented sequences then start with a begin offset
and end with an end offset
marker.
Then execute the following command:
./evaluate.sh <working directory> <instr directory> <interesting offsets> <main binary> [<application arguments>]
Arguments:
- Working directory: Path to directory containg the application binary, e.g.
$(pwd)/examples/wolfssl/eddsa
. - Instr directory: Path to generated instrumentation directory, e.g.,
$(pwd)/examples/wolfssl/eddsa/instr-base-evalmarker
. - Interesting offsets: List of instruction offsets in the instrumented binaries that should be checked against their vulnerable counterparts in the original binary.
Format:<image ID 1>.<begin offset 1>.<end offset 1>;<image ID 2>.<begin offset 2>.<end offset 2>;...
- Main binary: Name of the application binary, e.g.
app
. - Application arguments (optional): Arguments for the application itself, e.g.
3 perf
.
The resulting <working directory>/eval-results.txt
file then contains a list of memory locations and information about observed block values (ciphertexts). Ideally, each location only has "unique" block values, else there are collisions and thus leakage.
If the comparison tool aborts early (i.e., before processing at least 98% of all memory accesses), the instrumented trace may need some manual tweaking (the tool outputs the line number of the first detected misalignment).
In the following, we describe the steps needed to fully reproduce two different examples: MbedTLS AES (multiple rounds), and WolfSSL EdDSA (one signature).
The directory contains the test targets from the Cipherfix paper. To aid reproducibility, we offer two preconfigured Docker images:
- uzl-its/cipherfix-examples: Contains all necessary dependencies and precompiled library binaries.
- uzl-its/cipherfix-examples-full: Contains all necessary dependencies, precompiled library binaries, precompiled target binaries, and the precompiled Cipherfix framework. The image is generated by calling
/cipherfix/setup.sh
from theuzl-its/cipherfix-examples
image.
Thus, a Docker installation and an x86 CPU (preferably AMD Zen 3) are sufficient. Both Docker images were built on an AMD Zen 3 system.
To analyze, instrument and run the examples, execute the following steps:
-
Pull and start the supplied Docker container:
docker run -it ghcr.io/uzl-its/cipherfix-examples-full:latest
-
To analyze example
<name>
(eithermbedtls-aes
orwolfssl-eddsa
), run./analyze-<name>.sh
-
To instrument example
<name>
, run./instrument-<name>.sh
On the first run, this will produce a number of candidates for heap allocation functions, which can not be determined automatically and thus must be appended to
./cipherfix/examples/<library>/<target>/structure.out
manually (<library>/<target>
is eithermbedtls/aes-multiround
orwolfssl/eddsa
). Each entry consists of a function address and a type prefix (Mm
formalloc
,Mc
forcalloc
,Mr
forrealloc
).Appending can be done, for example, by running
echo -e "Mm ...\nMm ...\nMc ..." >> ./cipherfix/examples/<library>/<target>/structure.out
. Alternatively,nano
is installed in the container.Allocation functions for
mbedtls-aes
:Mm
:malloc@plt
inapp
(usually+83a0
)Mm
:malloc
inlibc.so.6
(usually+22310
)Mc
:mbedtls_calloc
inapp
(usually+a120
)
For example:
Mm 0000562c6c1ce3a0 Mm 00007fd169d9a310 Mc 0000562c6c1d0120
Appended with
echo -e "Mm 0000562c6c1ce3a0\nMm 00007fd169d9a310\nMc 0000562c6c1d0120" >> cipherfix/examples/mbedtls/aes-multiround/structure.out
Allocation functions for
wolfssl-eddsa
:Mm
:malloc@plt
at low address inapp
(usually+1200
)Mm
:malloc
inlibc.so.6
(usually+22310
)
For example:
Mm 0000559aad7e7200 Mm 00007f39aee6d310
Appended with
echo -e "Mm 0000562c6c1ce3a0\nMm 00007fd169d9a310" >> cipherfix/examples/wolfssl/eddsa/structure.out
After entering all allocation functions, re-run the instrumentation.
-
Finally, the original and instrumented programs for example
<name>
can be run with./run-<name>.sh
The command should print the computed ciphertexts/signatures and the required execution time of both programs, respectively.
It is possible to extend or replace the taint tracking and preprocessing modules by adding own tools that produce suitable trace files.
For building or using single modules, please use the provided build.sh
and run.sh
scripts in the respective subdirectories, or replace them by your own.
The existing modules are
structure-analysis
: Pintool to find all basic blocks and track the register and flag usage per instruction (preprocessing for static instrumentation); resulting trace file is needed forstatic-instrumentation
.static-variables
: Pintool to detect all static variables in the image memory itself; resulting trace file is needed fortaint-tracking
.taint-tracking
: Pintool for tracking secrets (and all instructions touching them) and precisely determining stack frames and heap allocations; needs the results ofstatic-variables
and produces the needed trace file forstatic-instrumentation
.static-instrumentation
: C# static instrumentation tool to harden the binary against the ciphertext side-channel; takes as input the results fromstructure-analysis
andtaint-tracking
.memwrite-tracer
: Pintool to collect traces of memory writes and their contents for the hardened binary; resulting memory trace file is needed forevaluation
.evaluation
: C# leakage evaluation tool to compare and evaluate memory write traces of the uninstrumented and the hardened binary; takes as input the memory trace fromtaint-tracking
, map/ignore files fromstatic-instrumentation
and the memory trace frommemwrite-tracer
.
To customize a module, please keep in mind that the static variable detection has to be executed before the taint tracking and that the dynamic analysis (static variables, taint tracking, structure analysis) has to be run before the static instrumentation takes place.
For an extended description of the framework, please refer to our paper:
- Jan Wichelmann, Anna Pätschke, Luca Wilke, and Thomas Eisenbarth. 2023. Cipherfix: Mitigating Ciphertext Side-Channel Attacks in Software. In 32nd USENIX Security Symposium (USENIX Security 2023). [paper and presentation]
For more background and a description of ciphertext side-channel attacks see
- Mengyuan Li, Luca Wilke, Jan Wichelmann, Thomas Eisenbarth, Radu Teodorescu and Yinqian Zhang. 2022. A Systematic Look at Ciphertext Side Channels on AMD SEV-SNP. In 2022 IEEE Symposium on Security and Privacy (S&P '22). [DOI]
Contributions are appreciated! Feel free to submit issues and pull requests.
The project is licensed under the MIT license. For further information refer to the LICENSE file.