monowire is a tool for finding TLS keys in process memory on Linux.
There are several different methods out there for decrypting TLS traffic, including (non-exhaustively)
- using the
SSLKEYLOGFILEenvironment variable; - using a proxy like mitmproxy;
- and using a uprobe-based tool like eCapture.
These are all respectable techniques that can fail in more adversarial scenarios, e.g. against obfuscated binaries.
monowire is an attempt to fix these shortcomings by identifying TLS secrets
for traffic decryption against a larger set of binaries. The tradeoff is that
it's a little less reliable in cases where one of the aforementioned approaches
works. It also requires significantly more computational overhead than these
other approaches.
monowire is a Linux tool for TLS decryption that works by using brute-force
search to find traffic secrets in a process's memory. It consists of a userspace
component and a kernelspace component.
The userspace component (monowire/) drives most of the action. This includes
writing captured packets to disk, dumping process memory, searching for TLS
secrets, and decrypting packets. It also does the handling for all monowire
subcommands.
The kernelspace component consists of a set of eBPF programs (monowire-ebpf/),
and an (optional) kernel module (monowire-module/). The eBPF programs are used
to send data back to the userspace component, including captured packets and
TLS connection information.
The kernel module is an optional but recommended component that allows
monowire to create on-demand process forks. This is a relatively cheap method
for creating memory snapshots that can be searched for key material. When the
kernel module is unavailable, the fallback mechanism for creating memory
snapshots involves moving target processes into a frozen cgroup, which is prone
to latency issues (and may interfere with the operation of the original
process).
The loose process for finding TLS secrets works as follows:
- On startup,
monowire attachloads several eBPF programs for capturing packets and monitoring TLS connections. - When a new TLS connection is established, an eBPF program monitors the connection for the first packet of encrypted application data. It sends an event back to the userspace component when this first packet is encountered.
- When the userspace component sees this event, it makes a best-effort attempt
to create an instantaneous snapshot of process memory at that point in time.
- If
/dev/monowireis available (indicating that the monowire kernel module has been loaded),monowirewill use it to fork the target process so that we can search the fork's memory for key material. - Otherwise,
monowirewill asynchronously move the target process into a frozen cgroup while immediately starting its memory dump (with the hopes of grabbing key material before it's wiped from memory.
- If
monowirethen searches the dumped memory for the client and server traffic secrets.- If found, these secrets will be written as a DSB record to the .pcapng file
containing captured packets from the process. This can then be used to
decrypt the PCAP using
monowire decrypt.
# Capture all TLS connections established by curl
monowire attach -c curl -O output
# Read pcap generaged by monowire and decrypt its contents
monowire decrypt ./output/$pid/$timestamp.pcapng
# Install nightly toolchain and rust-src
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
# Install bpf-linker
cargo +nightly install bpf-linkercargo build
# Build kernel module (optional)
cd monowire-module && makeThis compiles the eBPF programs (via aya-build in monowire/build.rs) and the
userspace binary in a single cargo build invocation.
To produce a fully static, portable binary using musl libc:
# Via Docker (no local musl toolchain needed)
bash scripts/build-static.sh
# Or locally (requires musl-tools installed)
bash scripts/build-static.sh --localThe Docker mode outputs the binary to target/static/monowire. The local mode
outputs to target/x86_64-unknown-linux-musl/release/monowire.
sudo sysctl -w kernel.perf_event_paranoid=-1
FLAGS="-g --call-graph dwarf"
# Memory scanning benchmarks
# * use "fast" for the fast keyscan path
# * use "full" for the full keyscan path
variant="fast"
perf record $FLAGS \
cargo bench --bench keyscan -- --profile-time 10 $variant
# perf archive / perf archive --unpack can be used to export perf
# results and read them on another systemAll components of this project with the exception of ./monowire-module (the
Linux kernel module companion) is licensed under MIT. The ./monowire-module
code is licensed under GPLv3.

