Skip to content

Latest commit

 

History

History
318 lines (257 loc) · 12.8 KB

PAN_GlobalProtect_protocol_doc.md

File metadata and controls

318 lines (257 loc) · 12.8 KB

This is an anonymized log of the authentication, configuration, tunnel data transfer, and logout interactions between a PAN GlobalProtect VPN server and client. The logs below are based on the official Windows client, v3.0.1-10, with some updates from v4.0.5-8.

Client version 4.0 adds IPv6 support and SAML authentication support.

The correct user-agent (User-Agent: PAN Globalprotect) is required for all HTTP interactions with the GlobalProtect VPN. It treats any other user-agent as a web browser, not a VPN client.

Login request

Some of the form fields are required (user and password obviously, ok=Login inexplicably) while others can apparently be omitted.

POST https://gateway.company.com/ssl-vpn/login.esp

Connection:      Keep-Alive
Content-Type:    application/x-www-form-urlencoded
User-Agent:      PAN GlobalProtect
Host:            gateway.company.com

URLEncoded form:

prot:                           https:
server:                         gateway.company.com
inputStr:
jnlpReady:                      jnlpReady
user:                           Myusername
passwd:                         DEADBEEF
computer:                       DEADBEEF01
ok:                             Login
direct:                         yes
clientVer:                      4100
os-version:                     Microsoft Windows Server 2012, 64-bit
preferred-ip:                   12.34.56.78
clientos:                       Windows
clientgpversion:                3.0.1-10
portal-userauthcookie:          empty
portal-prelogonuserauthcookie:  empty
host-id:                        deadbeef-dead-beef-dead-beefdeadbeef

New parameters sent by Windows client v4.0.5-8:

clientgpversion:                4.0.5-8
prelogin-cookie:
ipv6-support:                   yes
client-ip:                      34.56.78.90
client-ipv6:                    .
preferred-ipv6:

The client-ip{,v6} parameters refer to the client's external internet-facing IP address, while preferred-ip{,v6} parameters refer to the expected/desired addresses within the VPN.

Successful login response

This response contains a delicious 32-digit cookie. The second hexadecimal blob is a persistent identifier associated with the combination of user account and gateway (probably the sha1 hash of something, since it's 40 digits long).

In order to handle the getconfig, tunnel-connect, and logon requests properly (described below), the client needs to save some other parts of this response besides the cookie:

  • username: the server may return a slightly modified version of the username provided upon login (e.g. steve.JoNes transformed into the canonical steve.jones)
  • domain name and portal name: the correct values for these are—inexplicably—required to log out of the VPN session successfully ¯\_(ツ)_/¯
  • authentication type is something like LDAP-auth or AUTH-RADIUS_RSA_OTP, and appears to reflect the mechanism by which the user was authenticated
  • preferred IP address is set by some VPN gateways even if it was omitted from the login request; if it is not empty or (null), its value should be used in the subsequent getconfig request
  • 4100 appears to identify the VPN protocol version. I've never seen another value.
<?xml version='1.0' encoding='utf-8'?>
<jnlp>
  <application-desc>
    <argument>(null)</argument>
    <argument>delicious 32 digits hex cookie</argument>
    <argument>another 40 mysterious hexadecimal digits</argument>
    <argument>Gateway-Name</argument>
    <argument>username provided above</argument>
    <argument>authentication type</argument>
    <argument>vsys1</argument>
    <argument>company domain name</argument>
    <argument>(null)</argument>
    <argument/>
    <argument/>
    <argument/>
    <argument>tunnel</argument>
    <argument>-1</argument>
    <argument>4100</argument>
    <argument>preferred IP address as sent in request</argument>
  </application-desc>
</jnlp>

Windows client v4.0.5-8 receives additional input-parroting arguments at the end:

    <argument>portal-userauthcookie as sent in request</argument>
    <argument>prelogon-userauthcookie as sent in request</argument>
    <argument>preferred IPv6 address as sent in request</argument>

getconfig request

Similar to above, some of the parameters are required, others are not. addr1 seems to be the current IPv4 subnet of the client machine, and is apparently optional.

If a client has obtained a valid and unexpired authcookie, it's possible to re-run the getconfig request/response flow. This can be used to reconnect the tunnel after a network outage, without reauthenticating.

POST https://gateway.company.com/ssl-vpn/getconfig.esp

Connection:      Keep-Alive
Content-Type:    application/x-www-form-urlencoded
User-Agent:      PAN GlobalProtect
Host:            gateway.company.com

URLEncoded form

user:              Myusername
addr1:             4.5.6.78/24     (current IPv4 network, I think?)
preferred-ip:      12.34.56.78     (use value from login response)
portal:            Gateway-Name    (use value from login response)
authcookie:        cookie          (32 hex digits from above)
client-type:       1
os-version:        Microsoft Windows Server 2012, 64-bit
app-version:       3.0.1-10
protocol-version:  p1
clientos:          Windows
enc-algo:          aes-256-gcm,aes-128-gcm,aes-128-cbc,
hmac-algo:         sha1,

Windows client v4.0.5-8 adds additional parameters at the end:

app-version:       4.0.5-8
addr1-v6-1:        f00f::/16
addr1-v6-2:        f00f:dead:beef::dead:beef/128
preferred-ipv6:
hmac-algo:         sha1,.

Response #2 (getconfig)

Here's where it gets interesting:

  • Routing information seems almost identical to what Cisco AnyConnect provides, except in XML form
  • IPsec configuration specifies the exist SPI indexes to use, as well as the client-to-server (c2s) and server-to-client (s2c) encryption keys and authentication keys. Note that the upstream and downstream keys and SPIs do not match; this is intentional.
  • SSL tunnel URL (<ssl-tunnel-url>/ssl-tunnel-connect.sslvpn</ssl-tunnel-url>) is the same on all servers I've seen
  • MTU is sent as zero (<mtu>0</mtu>) on all servers I've seen. This seems broken and useless.
<?xml version='1.0' encoding='UTF-8'?>
<response status="success">
  <need-tunnel>yes</need-tunnel>
  <ssl-tunnel-url>/ssl-tunnel-connect.sslvpn</ssl-tunnel-url>
  <portal>Gateway-Name</portal>
  <user>Myusername</user>
  <lifetime>86400</lifetime>
  <timeout>3600</timeout>
  <disconnect-on-idle>3600</disconnect-on-idle>
  <bw-c2s>1000</bw-c2s>
  <bw-s2c>1000</bw-s2c>
  <gw-address>IP address of gateway.company.com in my case</gw-address>
  <ip-address>the preferred IP address from above</ip-address>
  <netmask>255.255.255.255</netmask>
  <dns>
    <member>8.8.8.8</member>
    <member>4.4.4.4</member>
  </dns>
  <wins>
    <member>8.8.8.9</member>
    <member>4.4.4.5</member>
  </wins>
  <default-gateway>gateway for default internal route</default-gateway>
  <mtu>0</mtu>
  <dns-suffix>
    <member>company.com</member>
    <member>company.internal</member>
    <member>stuff.company.com</member>
  </dns-suffix>
  <no-direct-access-to-local-network>no</no-direct-access-to-local-network>
  <access-routes>
    <member>10.0.0.0/8</member>
    <member>192.168.0.0/16</member>
  </access-routes>
  <ipsec>
    <udp-port>4501</udp-port>
    <ipsec-mode>esp-tunnel</ipsec-mode>
    <enc-algo>aes-128-cbc</enc-algo>
    <hmac-algo>sha1</hmac-algo>
    <c2s-spi>0xDEADBEEF</c2s-spi>
    <s2c-spi>0xFEEDBACC</s2c-spi>
    <akey-s2c>
      <bits>160</bits>
      <val>deadbeefdeadbeefdeadbeefdeadbeefdeadbeef</val>
    </akey-s2c>
    <ekey-s2c>
      <bits>128</bits>
      <val>feedbaccfeedbaccfeedbaccfeedbacc</val>
    </ekey-s2c>
    <akey-c2s>
      <bits>160</bits>
      <val>deadbeefdeadbeefdeadbeefdeadbeefdeadbeef</val>
    </akey-c2s>
    <ekey-c2s>
      <bits>128</bits>
      <val>feedbaccfeedbaccfeedbaccfeedbacc</val>
    </ekey-c2s>
  </ipsec>
</response>

Data transfer over the tunnel

In the back-and-forth flows shown below, < means sent by the gateway, > means sent by the client.

ESP-over-UDP

Uses the keying information obtained in response to the getconfig request. In order to initiate the connection, the client sends 3 ICMP request ("ping") packets to the gateway.

  • These packets are ESP-encapsulated

  • These packets are sent from the client's in-VPN IP address to the IP address specified by the <gw-address> from the getconfig response.

    • The destination address is usually the same as the gateway's public internet-facing IP address, but sometimes it is a VPN-internal address ¯\_(ツ)_/¯
  • These ICMP request packets include the following magic payload — though only the first 16 bytes of the payload appear to be necessary to elicit a response from the gateway.

    "monitor\x00\x00pan ha 0123456789:;<=>? !\"#$%&\'()*+,-./\x10\x11\x12\x13\x14\x15\x16\x18"
    "monitor\x00\x00pan ha " (first 16 bytes)
    
  • Once the gateway has responded with a corresponding ICMP reply, the client and server send and receive arbitrary ESP-encapsulated traffic.

  • The client continues to periodically send the same "magic ping" packets as a keepalive.

SSL vpn tunnel

The tunnel starts when the client issues a CONNECT-disguised-as-GET command, to the tunnel URL path specified in the getconfig response. The gateway responds with the ASCII string START_TUNNEL instead of a standard HTTP response code:

> 'GET /ssl-tunnel-connect.sslvpn?user=Myusername&authcookie=deadbeef HTTP/1.1\r\n\r\n'
< 'START_TUNNEL'

Now the client and gateway proceed to communicate by sending encapsulated IPv4 packets back and forth. Here is an example snippet of the IP-over-TLS stream format, as initiated by the client's GET command:

> 'GET /ssl-tunnel-connect.sslvpn?user=Myusername&authcookie=deadbeef HTTP/1.1\r\n\r\n'
< 'START_TUNNEL'
< 1a2b3c4d0800005401000000000000004500005461e400007e11f5520a100f030a12c23d[...]
> 1a2b3c4d08000034010000000000000045000034038f0000011108df0a12c23de00000fc[...]
...

Here is the packet format:

  1. 4 magic bytes: 1a2b3c4d
  2. Next 2 bytes are probably the Ethertype (as uint16_be): 0800 is IPv4
  3. Next 2 bytes are the packet length (as uint16_be) excluding this header, or 0000 for a keepalive packet
  4. Next 8 bytes are always 0100000000000000 for a real IP packet, or 0000000000000000 for a keepalive packet
  5. Remaining bytes are the actual Layer 3 packet (IPv4 packets starting with 45 in the examples above)

The DPD/keepalive packets can be sent by either the client or the server, and the other should immediately respond with an identical packet.

The server will drop the client connection if it doesn't receive anything from the client (after about 120 seconds in my testing) and the client should send the DPD/keepalive if it hasn't received anything from the server in a while. The official client appears to always send keepalive packets every 10 seconds.

ESP and SSL tunnels are mutually exclusive

If/when the SSL tunnel is connected, the ESP tunnel cannot be used any longer. The VPN server appears to invalidate the SPIs/keys that it sent, and will not respond to ESP-over-UDP packets. The only way to re-enable the ESP connection is to disconnect the SSL tunnel, re-run the getconfig request, and start over with new ESP keys sent in the new getconfig response.

This means that a client that prefers to use ESP must not try to connect the SSL tunnel until after an ESP connection has failed. (The official Windows client waits 10 seconds for ICMP reply packets over ESP, before failing over to the SSL tunnel.)

Logout request

The client must send the exact domain, computer name, portal, and OS version from the login request or response… otherwise the logout request will fail and the tunnel can be reconnected using the same authcookie.

POST https://gateway.company.com/ssl-vpn/logout.esp

Accept:          */*
Content-Type:    application/x-www-form-urlencoded
Host:            gateway.company.com

URLEncoded form:

user:        Myusername
portal:      Gateway-Name
authcookie:  as above
domain:      company domain name
computer:    DEADBEEF01
os-version:  Microsoft Windows Server 2012, 64-bit

Successful logout response

<?xml version='1.0' encoding='UTF-8'?>
<response status="success">
  <portal>Gateway-Name</portal>
  <domain>company domain name</domain>
  <user>Myusername</user>
  <computer>DEADBEEF01</computer>

  <!-- newer servers include these, older ones don't: -->
  <saml-session-index></saml-session-index>
  <saml-name-id></saml-name-id>
</response>