Memory forensics plugins for extracting IPsec Security Association (SA) and Security Policy (SP) data from Linux kernel memory images.
These plugins enable the extraction of cryptographic key material and configuration metadata from the Linux kernel's XFRM subsystem (s. XFRM Intro), which implements the IPsec protocol suite. The extracted data facilitates retrospective decryption of captured network traffic and provides forensic visibility into encrypted communication channels.
The plugins address several forensic use cases:
| Extracted Data | Forensic Application |
|---|---|
| ESP encryption keys (AES, 3DES, ChaCha20) | Decryption of ESP-encrypted IPsec packets |
| Authentication keys (HMAC-SHA256, HMAC-SHA1) | Verification of packet integrity and detection of tampering |
| Security Parameter Index (SPI) | Correlation of memory-resident keys with captured network traffic |
| Source/Destination addresses | Identification of VPN tunnel endpoints |
| Security policies with selectors | Reconstruction of traffic routing decisions |
| Tunnel/Transport mode configuration | Determination of encapsulation methodology |
| Lifetime counters (bytes/packets) | Quantification of SA usage and activity periods |
| Network namespace identifiers | Attribution of VPN configurations to containers or namespaces |
- Volatility 3 Framework (version 2.10.0 or later)
- Python 3.8 or later
- Linux memory dump in supported format (LiME, ELF core, etc.)
- ISF symbol file for the target kernel (for symbol-dependent plugins)
Copy the plugin files directly to the Volatility 3 plugins directory:
# Navigate to Volatility 3 installation
cd /path/to/volatility3
# Copy plugin files
cp -r /path/to/XFRM-Inspector/src/linux/xfrm.py \
volatility3/framework/plugins/linux/
cp -r /path/to/XFRM-Inspector/src/linux/xfrm_nosymbols.py \
volatility3/framework/plugins/linux/Specify the plugin directory at runtime using the -p flag:
python3 vol.py \
-p /path/to/XFRM-Inspector/src \
-f memory.dump \
linux.xfrm.XfrmStateNote: When using an external plugin path, ensure the directory structure does not conflict with built-in Volatility packages. If import errors occur, use Method 1 instead.
Extracts Security Association Database (SAD) entries containing cryptographic keys and SA metadata.
Output Formats:
- Tabular format (default)
ip xfrm statecompatible format (--ip-style)- Wireshark ESP SA format (
--wireshark) - JSON format (
--json-output)
Extracts Security Policy Database (SPD) entries defining traffic selectors and policy rules.
Output Formats:
- Tabular format (default)
ip xfrm policycompatible format (--ip-style)
Unified plugin providing combined SAD and SPD output per network namespace, analogous to executing ip xfrm state followed by ip xfrm policy.
Key Features:
- By default, only shows namespaces containing XFRM states or policies (reduces noise)
- Displays process names using each namespace (e.g.,
charon[13070]) for easier identification - Provides a summary of how many namespaces have XFRM content
- Use
--show-allto include empty namespaces
Symbol-independent plugin utilizing physical memory scanning for environments lacking debug symbols. Still experimental.
- Linux memory image (LiME, /proc/kcore, or equivalent)
- ISF symbol file generated via dwarf2json or obtained from Volatility symbol repositories
- Linux memory image (LiME format recommended)
- Supported kernel versions: 5.x, 6.x (ARM64, x86_64)
python3 vol.py -p /path/to/volatility_plugins \
-s /path/to/symbols \
-f memory.dump \
linux.xfrm.XfrmStatecp -r linux/ /path/to/volatility3/volatility3/framework/plugins/# Tabular output
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmState
# Output matching 'ip xfrm state' format
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmState --ip-style
# Wireshark ESP decryption format
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmState --wireshark > esp_keys.txt
# JSON output for programmatic processing
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmState --json-output > states.json
# Filter by network namespace
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmState --netns-inum 4026532324# Tabular output
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmPolicy
# Output matching 'ip xfrm policy' format
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmPolicy --ip-style# Default: only shows namespaces with XFRM content, includes process info
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmShow
# Show all namespaces including empty ones
python3 vol.py -p /path/to/plugins -s /path/to/symbols \
-f memory.dump linux.xfrm.XfrmShow --show-allpython3 vol.py -p /path/to/plugins \
-f memory.dump linux.xfrm_nosymbols.XfrmStateNoSymbols| Option | Applicable Plugins | Description |
|---|---|---|
--ip-style |
XfrmState, XfrmPolicy | Output format compatible with iproute2 utilities |
--wireshark |
XfrmState | Wireshark ESP SA import format |
--json-output |
XfrmState | JSON format for automation |
--verbose |
XfrmState | Include lifetime counters and timestamps |
--netns-inum N |
All | Filter by network namespace inode number |
--show-expired |
XfrmState | Include expired Security Associations |
--show-all |
XfrmShow | Show all namespaces including empty ones (default: only with content) |
Offset NetNS Proto SPI Src Dst Mode EncAlgo EncKey AuthAlgo AuthKey
0xffff0000fc5c9040 4026532324 ESP 0x30d8d4c4 10.0.0.1 10.0.0.2 tunnel cbc(aes) 851b63... hmac(sha256) e06e68...
Offset NetNS Dir Priority Src Dst Templates
0xffff0000c4b6a000 4026532324 in 367231 10.0.0.2/32 10.0.0.1/32 1
src 10.0.0.1 dst 10.0.0.2
proto esp spi 0xbee395c6 reqid 1 mode tunnel
replay-window 0 flag af-unspec
auth-trunc hmac(sha256) 0x8b6b946640cbacac... 128
enc cbc(aes) 0x76b4fd85af668aaa...
anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
src 10.0.0.2/32 dst 10.0.0.1/32
dir in priority 367231
tmpl src 10.0.0.2 dst 10.0.0.1
proto esp reqid 1 mode tunnel
Showing 2 of 9 namespaces with XFRM content (use --show-all to see all)
=== Network Namespace: 4026532505 (charon[13070], tcpdump[13717]) ===
src 10.0.0.1 dst 10.0.0.2
proto esp spi 0xc8d22bd1 reqid 1 mode tunnel
replay-window 0 flag af-unspec
auth-trunc hmac(sha256) 0x24b88656be2a856a... 128
enc cbc(aes) 0xddd9bea883ce8355...
anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
src 10.0.0.2/32 dst 10.0.0.1/32
dir in priority 367231
tmpl src 10.0.0.2 dst 10.0.0.1
proto esp reqid 1 mode tunnel
Note: The process names in parentheses (e.g., charon[13070]) identify which applications are using each network namespace, facilitating correlation with VPN configurations or container boundaries.
"esp","10.0.0.1","10.0.0.2","0xbee395c6","AES-CBC [RFC3602]","0x76b4fd85...","HMAC-SHA-256-128 [RFC4868]","0x8b6b9466..."
{
"plugin": "linux.xfrm.XfrmState",
"timestamp": "2025-12-20T14:08:32.903356",
"states": [
{
"offset": "0xffff0000fd9b8d00",
"netns_inum": 4026532324,
"protocol": "ESP",
"spi": "0xbee395c6",
"src_addr": "10.0.0.1",
"dst_addr": "10.0.0.2",
"mode": "tunnel",
"reqid": 1,
"encryption": {
"algorithm": "cbc(aes)",
"key_len_bits": 256,
"key_hex": "76b4fd85af668aaad336bb168128636e..."
},
"authentication": {
"algorithm": "hmac(sha256)",
"key_len_bits": 256,
"key_hex": "8b6b946640cbacac8719cb8c334fb0c2..."
}
}
]
}To decrypt captured IPsec traffic using extracted keys:
- Generate keys in Wireshark format:
--wireshark > esp_keys.txt - In Wireshark, navigate to Edit, Preferences, Protocols, ESP
- Select Edit adjacent to ESP SAs
- Import the generated file or enter entries manually
dwarf2json linux --elf /path/to/vmlinux > linux-$(uname -r).jsonvolatility3/symbols/linux-6.8.0-generic-arm64.json
| Architecture | Symbol-Dependent | Symbol-Independent |
|---|---|---|
| x86_64 | Supported | Supported |
| ARM64 (AArch64) | Supported | Supported |
| x86 (32-bit) | Supported | Limited |
| Kernel Identifier | Wireshark Designation | Reference |
|---|---|---|
| cbc(aes) | AES-CBC | RFC 3602 |
| rfc4106(gcm(aes)) | AES-GCM | RFC 4106 |
| cbc(des3_ede) | 3DES-CBC | RFC 2451 |
| ctr(aes) | AES-CTR | RFC 3686 |
| rfc7539(chacha20,poly1305) | CHACHA20-POLY1305 | RFC 7634 |
| Kernel Identifier | Wireshark Designation | Reference |
|---|---|---|
| hmac(sha256) | HMAC-SHA-256-128 | RFC 4868 |
| hmac(sha1) | HMAC-SHA-1-96 | RFC 2404 |
| hmac(sha384) | HMAC-SHA-384-192 | RFC 4868 |
| hmac(sha512) | HMAC-SHA-512-256 | RFC 4868 |
| xcbc(aes) | AES-XCBC-MAC-96 | RFC 3566 |
struct xfrm_state {
possible_net_t xs_net; // Network namespace reference
struct hlist_node bydst; // Hash linkage by destination
struct hlist_node byspi; // Hash linkage by SPI
struct xfrm_id id; // SPI, protocol, destination
struct xfrm_selector sel; // Traffic selector
struct xfrm_lifetime_cfg lft; // Lifetime configuration
struct xfrm_lifetime_cur curlft; // Current usage counters
struct xfrm_algo *ealg; // Encryption algorithm
struct xfrm_algo_auth *aalg; // Authentication algorithm
struct xfrm_algo_aead *aead; // AEAD algorithm
// Additional fields omitted
};The upstream definition of the original structure is in the Linux kernel source (include/net/xfrm.h, Linux v5.10.46), starting at line 149. See: [xfrm.h @ v5.10.46 (L149)][xfrm-h].
struct xfrm_policy {
possible_net_t xs_net; // Network namespace reference
struct hlist_node bydst; // Hash linkage
struct xfrm_selector sel; // Traffic selector
u32 priority; // Policy priority
u8 type; // Policy type
u8 dir; // Direction (in/out/fwd)
struct xfrm_tmpl xfrm_vec[]; // Template array
int xfrm_nr; // Template count
// Additional fields omitted
};The XfrmStateNoSymbols plugin employs the following methodology:
- Physical memory scanning for algorithm name patterns (e.g., "cbc(aes)", "hmac(sha256)")
- Structure validation at each pattern match location
- Key material extraction from validated xfrm_algo structures
- Reverse pointer traversal to locate parent xfrm_state structures
- Deduplication of extracted keys
Limitations:
- Extended execution time due to full memory scan requirements
- Reduced metadata availability for keys in vmalloc regions
- Potential inclusion of residual keys from freed memory
- Verify symbol file compatibility with kernel version
- Remove network namespace filter to search all namespaces
- Confirm IPsec tunnels were active at time of memory acquisition
- Enable verbose logging with
-vor-vvflags
Regenerate symbol file using dwarf2json with a vmlinux binary containing DWARF debug information.
- Volatility 3 Framework: https://volatility3.readthedocs.io/
- dwarf2json: https://github.com/volatilityfoundation/dwarf2json
- Wireshark ESP Decryption: https://wiki.wireshark.org/ESP
- RFC 4301: Security Architecture for the Internet Protocol
- Linux Kernel Source: include/net/xfrm.h: [xfrm-h]: https://elixir.bootlin.com/linux/v5.10.46/source/include/net/xfrm.h#L149