Libreswan is one of the most widely used VPN solutions for IPsec on Linux. But between versions 4.2 and 4.5, a serious bug was discovered—CVE-2022-23094—that could let anyone crash your VPN service remotely just by sending a bad IKEv1 packet. In this post, I’ll break down how this bug works, why it happened, how it can be abused, how to patch it, and give you a real glimpse at the vulnerable code.
What is CVE-2022-23094?
CVE-2022-23094 is a denial of service (DoS) bug affecting Libreswan versions 4.2 up to 4.5. It’s a pure remote attack: no login, no authentication is needed—just a specially crafted IKEv1 packet. If you’re using these versions to secure your servers, this vulnerability makes it possible for someone on the internet to crash your VPN, knocking all users offline instantly.
A summary of the issue
> _Libreswan’s IKEv1 handling code (pluto/ikev1.c) assumes that a valid state object always exists when processing packets. If an attacker sends an IKEv1 message that doesn’t properly trigger creation of this state object, the code tries to use a non-existent pointer, crashing the “pluto” daemon (NULL pointer dereference)._
Understanding the Code Flaw
In simple terms, the flaw comes down to unsafe assumptions about pointers. When a program tries to use a pointer that is NULL (doesn’t point to any valid data), it leads to a crash. The “pluto” daemon in Libreswan is responsible for handling IKE (Internet Key Exchange) traffic, which sets up VPN connections. When it receives messed-up IKEv1 packets, it tries to process them even if no session (state) was created for this packet—causing the NULL pointer dereference.
Let’s look at a simplified code snippet, close to what was reported
// Inside pluto/ikev1.c, handling an inbound IKEv1 packet:
struct state *st = find_state_by_msgid(msgid);
if (st->some_field == expected_value) { // <--- CRASH if st == NULL!
// continue processing...
}
If find_state_by_msgid() returns NULL (no state object for this packet), the code blindly tries to access st->some_field. That’s a NULL pointer dereference, which immediately crashes the whole “pluto” VPN process.
Exploiting the Bug
A remote attacker just has to identify your Libreswan’s VPN port (usually UDP 500 or 450) on your public IP, and then send a malformed IKEv1 packet designed to reach this buggy code path (in particular, with no state object created for it).
Just a single, maliciously constructed IKEv1 packet.
While a single crash may take your VPN offline until restarted, this attack can be endlessly repeated to keep your VPN service down—making it effective for DoS.
How Was the Bug Fixed?
The developers patched this in Libreswan 4.6 (and later). The vulnerability was fixed by checking that the state pointer is not NULL before using it:
struct state *st = find_state_by_msgid(msgid);
if (st != NULL && st->some_field == expected_value) {
// Only enter this block if state exists!
}
This simple check means that if an invalid or unexpected packet comes in, it is just dropped—no crash.
Libreswan 4.2, 4.3, 4.4, or 4.5
- Any system with a public-facing IPsec service, processing IKEv1 packets (common on Linux VPN servers, some routers, many cloud VPN setups)
Both default and many custom Libreswan configs are affected (nothing “special” required)
If you’re using IKEv2 only, some risk still exists—misclassified packets can still hit the IKEv1 handler.
How to Protect Yourself
Update Libreswan!
The fix is included from Libreswan 4.6 onwards. If you’re on any build earlier than 4.6, upgrade immediately. Most distributions (Fedora, RHEL, Debian, Ubuntu) now offer patched packages through their package managers.
- Official release notes for Libreswan 4.6
- Full CVE-2022-23094 security advisory
- Upstream commit fixing the bug (GitHub link)
Workarounds:
If you are unable to instantly upgrade, consider blocking UDP 500/450 from untrusted sources at your firewall until you can patch.
Simple Exploit Example (Python and Scapy)
Here’s a basic (unsophisticated) test for a vulnerable Libreswan server. DO NOT use this for unauthorized access! For test labs only.
from scapy.all import *
# Replace with your VPN server IP
vpn_ip = "192..2.10"
packet = IP(dst=vpn_ip)/UDP(sport=500,dport=500)/Raw(load=b'\x00'*40)
send(packet)
print("Packet sent. If the VPN is vulnerable, it may now crash.")
Sending this malformed packet can trigger the vulnerable path, potentially crashing the daemon if not patched.
Final Thoughts
CVE-2022-23094 is a reminder that deep inside even battle-tested open-source software, little coding shortcuts—like assuming a pointer “must” exist—can have big consequences.
If you’re running IPsec VPNs with Libreswan, please check your version and update to 4.6 or later. Protecting the reliability of your VPN is essential to your users and your business.
For more technical details, check out
- Libreswan Security Announcements
- CVE writeup at MITRE
- Maintainer’s mailing list discussion
Stay safe out there. Patch your VPNs!
*This post is a simplified, exclusive explainer for CVE-2022-23094. All code and examples are for educational purposes only.*
Timeline
Published on: 01/15/2022 02:15:00 UTC
Last modified on: 01/24/2022 13:27:00 UTC