Fortigate - Recover IPSec VPN PSK
During a work related project I needed a method for extracting the Pre-shared key of a VPN tunnel in plain-text from a Fortigate firewall. However, this isn’t straightforward as you can’t view the configured PSK in the web interface.
Even if you have a look at the VPN configuration on the CLI the Fortigate displays the PSK only in an encrypted form. This can be seen in the following excerpt where the ENC keyword indicates that the value is encrypted.
Fortigate-VM # show vpn ipsec phase1-interface
config vpn ipsec phase1-interface
edit "Vladilena"
set interface "port1"
set peertype any
set net-device disable
set proposal aes128-sha256 aes256-sha256
set comments "Test VPN Tunnel"
set wizard-type static-fortigate
set remote-gw 192.168.178.54
# PSK is only displayed as an encrypted value
set psksecret ENC KQdvafObUI...
next
end
However, it is possible to retrieve the plain-text key over the REST API of the firewall. First login to the Fortigate
with the following curl
command. Make sure to adjust the IP address as well as the user credentials to your system.
$ curl -k -X POST "https://172.21.130.109/logincheck" \
-d "username=admin&secretkey=12345" -c cookies.txt
If the login is successful curl
should output something like this:
<script language="javascript">
document.location="/prompt?viewOnly&redir=%2F";
</script>
Additionally a ccsrftoken
as well as an APSCOOKIE
value should have been saved to the specified cookies file.
One the login is done you can access the VPN configuration of the device over the following API entry point:
https://x.x.x.x/api/v2/cmdb/vpn.ipsec/phase1-interface?plain-text-password=1
.
The plain-text-password=1
parameter makes sure that the firewall responds with the plain-text password instead
of an encrypted value.
The JSON response from the Fortigate is rather lengthy as it contains the full VPN configuration including default
values. It’s therefore advised to filter the result with tools such as jq
or grep
. The relevant field that
contains the PSK of the VPN tunnel is called psksecret
.
I only had one single VPN tunnel configured on my device, hence I used jq
to extract the information.
This can be seen in the following example:
$ curl -s -k -b cookies.txt \
"https://172.21.130.109/api/v2/cmdb/vpn.ipsec/phase1-interface?plain-text-password=1" \
| jq -r ".results[0] .psksecret"
DummySecretKey86
The result DummySecretKey86
is the plain-text PSK that was configured during tunnel creation.
If you operate your system in Multi-VDOM mode and need to extract the VPN configuration of a specific VDOM
add the URL parameter vdom=VDOM-NAME
to the GET request.
Alternatively it’s possible to send the API requests with one of many programming languages.
The following piece of Python code uses the requests
library to achieve the same goal as the previous curl
commands.
import requests
session = requests.Session()
credentials = {"username":"admin", "secretkey":"12345"}
session.post(
url="https://172.25.86.20/logincheck",
data=credentials,
verify=False,
)
result = session.get(
url="https://172.25.86.20/api/v2/cmdb/vpn.ipsec/phase1-interface?plain-text-password=1",
verify=False
)
print(result.json()["results"][0]["psksecret"])
Using the plain-text-password=1
API parameter also works for other configurations. For example
it’s possible to retrieve configured RADIUS passwords this way. However it’s not possible to obtain
passwords of local users as the firewall only stores a hash value instead of the plain-text password.