]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Add new documentation on how to observe/MITM VPN clients
authorDaniel Lenski <dlenski@gmail.com>
Sat, 22 Jan 2022 23:36:20 +0000 (15:36 -0800)
committerDaniel Lenski <dlenski@gmail.com>
Sun, 23 Jan 2022 18:53:08 +0000 (10:53 -0800)
Put this in a new subsection of "Contributing".  This is based on
https://gitlab.com/openconnect/openconnect/-/issues/246#note_811153868, and
other recent requests for help MITM'ing VPN clients.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
www/Makefile.am
www/contribute.xml
www/html.py
www/menu2-contribute.xml [new file with mode: 0644]
www/mitm.xml [new file with mode: 0644]

index 2d1c6d995f544a9c5d7aa94d2079a078f3af6b63..ca4f4f26fb459720ae3818911475325f0c729faa 100644 (file)
@@ -7,9 +7,10 @@ FTR_PAGES = csd.html charset.html token.html pkcs11.html tpm.html features.html
 START_PAGES = building.html connecting.html manual.html vpnc-script.html
 INDEX_PAGES = changelog.html download.html index.html packages.html platforms.html licence.html
 PROTO_PAGES = protocols.html anyconnect.html array.html fortinet.html f5.html globalprotect.html juniper.html pulse.html
-TOPLEVEL_PAGES = contribute.html mail.html
+CONTR_PAGES = contribute.html mitm.html
+TOPLEVEL_PAGES = mail.html
 
-ALL_PAGES = $(FTR_PAGES) $(START_PAGES) $(INDEX_PAGES) $(TOPLEVEL_PAGES) $(PROTO_PAGES)
+ALL_PAGES = $(FTR_PAGES) $(START_PAGES) $(INDEX_PAGES) $(TOPLEVEL_PAGES) $(PROTO_PAGES) $(CONTR_PAGES)
 
 html_DATA = $(ALL_PAGES)
 
@@ -23,6 +24,7 @@ $(ALL_PAGES): menu1.xml $(srcdir)/inc/*.tmpl
 $(FTR_PAGES): menu2-features.xml
 $(START_PAGES): menu2-started.xml
 $(PROTO_PAGES): menu2-protocols.xml
+$(CONTR_PAGES): menu2-contribute.xml
 $(MAIN_PAGES): menu2.xml
 
 manual.html: openconnect.8.inc
index f4e72d4053b79c4dc5ed1844a1f578c82b31a352..c9153b4bdd0dd1d50842e46d67b33e3553c3083a 100644 (file)
@@ -2,7 +2,9 @@
        <INCLUDE file="inc/header.tmpl" />
 
        <VAR match="VAR_SEL_CONTRIBUTE" replace="selected" />
+       <VAR match="VAR_SEL_CONTRIB_MAIN" replace="selected" />
        <PARSE file="menu1.xml" />
+       <PARSE file="menu2-contribute.xml" />
 
        <INCLUDE file="inc/content.tmpl" />
 
@@ -106,15 +108,17 @@ some help with testing these would be particularly welcome:</p>
 </ul>
 
 
+<a name="new-protocols"/>
 <h2>New Protocols</h2>
 
 <p>There are some other protocols which would be good to add to OpenConnect. Getting a new
 protocol to the point where it basically works to send and receive traffic is only a
 few hours of work, and can be very rewarding.</p>
 
-<p>For some protocols we already know how they work on the wire and it's mostly
-just a matter of typing. For others we might have to observe the existing clients
-to learn how they work.</p>
+<p>For some protocols we already know how they work on the wire and it's mostly just
+a matter of writing the code. For others we might have to <a href="mitm.html">observe
+the existing clients</a> to learn how they work.</p>
+
 <p>These would be great projects for someone to take on as a learning exercise, or
 perhaps even Google Summer of Code projects.</p>
 
index 9278e016920c6022315f23d7e199c3f53d48fd10..8c71d988e2f2d9ce07ea12b4bedd1461e23e26b6 100755 (executable)
@@ -44,6 +44,9 @@ fdout = sys.stdout
 def replaceVars(line):
     cnt = 0
     while cnt < len(replace):
+       # FIXME: this will match partial variable names, e.g. if XYZ and XYZ_ABC
+       # are both in the replacement list, and XYZ appears first, it will
+       # match and (partially) replace occurrences of XYZ_ABC.
         if line.find(replace[cnt]) >= 0:
             line = line.replace(replace[cnt], replace[cnt+1])
         cnt += 2
diff --git a/www/menu2-contribute.xml b/www/menu2-contribute.xml
new file mode 100644 (file)
index 0000000..c953672
--- /dev/null
@@ -0,0 +1,6 @@
+<PAGE>
+       <STARTMENU level="2"/>
+       <MENU topic="Contributing" link="contribute.html" mode="VAR_SEL_CONTRIB_MAIN" />
+       <MENU topic="Observing VPN clients" link="mitm.html" mode="VAR_SEL_CONTRIB_MITM" />
+       <ENDMENU />
+</PAGE>
diff --git a/www/mitm.xml b/www/mitm.xml
new file mode 100644 (file)
index 0000000..4f64ff9
--- /dev/null
@@ -0,0 +1,219 @@
+<PAGE>
+       <INCLUDE file="inc/header.tmpl" />
+
+       <VAR match="VAR_SEL_CONTRIBUTE" replace="selected" />
+       <VAR match="VAR_SEL_CONTRIB_MITM" replace="selected" />
+       <PARSE file="menu1.xml" />
+       <PARSE file="menu2-contribute.xml" />
+
+       <INCLUDE file="inc/content.tmpl" />
+
+<h1>Observing VPN clients</h1>
+
+<p>Most of the VPN <a href="protocols.html">protocols supported by
+OpenConnect</a> are proprietary, undocumented, and in many cases
+overly-complex, perhaps intentionally obfuscated.</p>
+
+<p>In order to add support for <a
+href="contribute.html#new-protocols">new protocols</a>, and sometimes
+even to improve or update support for existing ones, it is often
+necessary to observe existing clients and servers in order to
+understand how they work.</p>
+
+<h2>Observing TLS/SSL connections</h2>
+
+<p>Modern VPN protocols almost always support a UDP-based transport
+for tunneled packets, e.g. DTLS for the Cisco AnyConnect protocol, or
+ESP for the GlobalProtect protocol. This is because <a
+href="http://sites.inka.de/~W1011/devel/tcp-tcp.html">TCP over TCP is
+very suboptimal</a> in terms of performance. However, most VPN
+protocols also support TLS/SSL for connection initiation and as a
+fallback, due to its universal availability even in highly filtered or
+firewalled network environments. <b>It is typically more
+straightforward and productive to start out by observing the TLS/SSL
+side of a new VPN protocol, and saving the UDP-based transport for
+later</b> (See <a
+href="http://lists.infradead.org/pipermail/openconnect-devel/2016-October/004015.html">this
+discussion thread</a> from the <a href="mail.html">mailing list</a>
+during the initial work on the <a
+href="globalprotect.html">GlobalProtect protocol</a>.)</p>
+
+<p>The content of a TLS/SSL connection is end-to-end encrypted and
+authenticated, and the session keys are normally kept only in memory
+by the applications using these connections. Therefore, special
+techniques are needed to decrypt traffic and observe the plaintext
+bytes-on-the-wire of any TLS-based communications protocol.</p>
+
+<p>There are more-or-less 3 possible techniques for decrypting
+TLS-based communications and observing the plaintext. The first two
+shown here are quite simply, but not universally usable; the
+third is more complex but should be applicable to any TLS-based
+VPN protocol.</p>
+
+<h3>(1) Using SSLKEYLOGFILE</h3>
+
+<p>If your VPN client is based on a standard TLS library and does not
+disable this mechanism, it is likely the most straightforward way to
+decrypt TLS traffic.</p>
+
+<p>Most <a
+href="https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations">TLS
+libraries</a> (including OpenSSL, GnuTLS, and LibNSS) support an
+environment variable called <tt>SSLKEYLOGFILE</tt>, which will cause
+applications using those libraries to write "premaster secrets" for
+their TLS/DTLS sessions to a file.  This makes it straightforward to
+automatically decrypt the traffic using the Wireshark network protocol
+analyzer. Basically, you should run the VPN client that you're
+observing with this environment variable set, run Wireshark on the
+same computer, and configure Wireshark to use the resulting log file;
+see <a href="https://wiki.wireshark.org/TLS#tls-decryption">Wireshark's
+TLS decryption documentation for details.</a></p>
+
+<p>Note that some proprietary VPN clients disable the
+<tt>SSLKEYLOGFILE</tt> mechanism to prevent decryption of their
+traffic, but many developers overlook this especially in early
+releases of their client software.</p>
+
+<h3>(2) Using server's RSA private key</h3>
+
+<p>If you have access to the RSA private key of a VPN <i>server</i>
+supporting the protocol you're observing (likely because you
+administer such a VPN), and can use RSA key exchange, then you can
+provide this RSA private key to Wireshark and automatically decrypt
+TLS traffic to and from <i>this server</i> using Wireshark; again, see
+<a href="https://wiki.wireshark.org/TLS#tls-decryption">Wireshark's
+TLS decryption documentation for details and limitations.</a></p>
+
+<p>This works because the RSA key exchange supported by TLS (re)uses
+the server's private key for encryption of the ephemeral session keys,
+unlike Diffie-Helman or Elliptic Curve Diffie-Helman exchanges which
+do not. (<a href="https://security.stackexchange.com/a/35521">More
+detailed explanation on StackExchange.</a>)</p>
+
+<p>This lack of <a href="https://en.wikipedia.org/wiki/Forward_secrecy">forward
+secrecy</a> of session keys is indeed why RSA key exchange has been
+deprecated in TLS 1.2 and <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security#Key_exchange_or_key_agreement">removed
+in TLS 1.3</a>. However, most VPN servers and clients continue to
+support TLS 1.2 or older with RSA key exchange for backwards
+compatibility, so this is still a viable option for decrypting traffic
+as of 2022.</p>
+
+<h3>(3) MITM</h3>
+
+<p>If you cannot use either of the above mechanisms, then you will
+need to use the <a
+href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">MITM
+technique</a> to decrypt traffic to/from the VPN client you are
+observing.</p>
+
+<p>The basic idea is to convince the two peers of the TLS connection
+(VPN client and server) that they are communicating directly with each
+other via an end-to-end encrypted TLS session, when in fact each of
+them is in fact communicating with an intermediary (the
+"man-in-the-middle").  The intermediary creates two <i>separate</i>
+TLS sessions: one between the real client and the intermediary, and
+one between the intermediary and the real server. The intermediary can
+inspect and modify traffic before relaying it between the the peers,
+who continue to believe that they are communicating directly with each
+other.</p>
+
+<p>In order to MITM-capture the traffic from a typical proprietary VPN
+client:</p>
+
+<ol>
+  <li>Use <a href="https://mitmproxy.org">mitmproxy</a>, running on
+  Linux. (There are other similar tools available, but the rest of
+  this document will assume you are running <tt>mitmproxy</tt> on
+  Linux.)</li>
+
+  <li>Set up a virtual machine and install the required operating and
+  VPN client. (It is possible to do this using a physical system as
+  well, but this will make transparent routing more complex.) We
+  recommend:
+  <ul>
+    <li>Linux host OS with <a href="https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine">KVM/QEMU</a>
+    as a hypervisor</li>
+    <li>Guest/VM configured for <a href="https://en.wikibooks.org/wiki/QEMU/Networking#User_mode_networking">user
+    mode networking</a></li>
+    <li>Assuming the guest is running Microsoft Windows as its OS, install <a href="https://access.redhat.com/articles/2488201">RedHat's
+    paravirtualized I/O drivers</a> to improve performance.</li>
+  </ul></li>
+
+  <li><p>Run <tt>mitmproxy</tt> on the host system, and route traffic
+  from the VM through it <i>transparently</i>, that is without setting
+  an explicit proxy.</p><p>With KVM/QEMU and user-mode networking, this
+  consists of setting the guest system's IPv4 gateway to
+  <tt>10.0.2.2</tt> and setting up <tt>iptables</tt> rules on the
+  Linux host to redirect traffic. (Described in more detail in
+  <a href="https://docs.mitmproxy.org/stable/howto-transparent-vms">mitmproxy's
+  guide to transparently proxying virtual machines</a>).</p></li>
+
+  <li><p><b>Browse to the URL <a
+  href="https://mitm.it">https://mitm.it</a> on the VM</b>; this is a
+  special domain intercepted by <tt>mitmproxy</tt> itself.</p><p>The
+  web page shown will help you verify that (a) the VM's traffic is
+  really passing through MITMproxy and (b) the VM's operating system
+  trusts <tt>mitmproxy</tt>'s certificates.</p></li>
+
+  <li>Run the VPN client on the VM, and capture and study its traffic
+  using <tt>mitmproxy</tt> (or <tt>mitmdump</tt>) on the host.</li>
+
+  <li><p>The client and/or server may employ various mechanisms to detect
+  MITM and shut down the MITM'ed connection. <b>Trick,
+  bludgeon, or confuse the client and server into ignoring this</b>;
+  see below for specific examples.</p><p>This usually works by
+  sending a copy or hash/fingerprint of the server's TLS certificate
+  as part of the in-band protocol data, and checking for differences
+  from the certificate exchanged in the TLS handshake. </p></li>
+
+  <li>Repeat these steps iteratively to understand how the VPN
+  client's interaction with the VPN server works.</li>
+</ol>
+
+<p>In cases where your VPN client/server detect MITM'ed connections
+and stop communicating (6), it's typically necessary to write a script
+which will detect and rewrite in-band protocol data containing the
+server's TLS certificate (or a hash/fingerprint of it). This requires
+a recent version of <tt>mitmproxy</tt> containing <a
+href="https://github.com/mitmproxy/mitmproxy/pull/1935">pull request
+#1935</a> which was contributed by OpenConnect developers for this
+purpose.</p>
+
+<p>An example of such a script may be useful:
+<a href="https://gitlab.com/dlenski/pangp-hacks/-/blob/master/gp_ssl_log.py">gp_ssl_log.py</a>.
+This script works with <tt>mitmproxy</tt> or <tt>mitmdump</tt> to modify
+traffic to/from with a GlobalProtect server; specifically it <a
+href="https://gitlab.com/dlenski/pangp-hacks/-/blob/master/gp_ssl_log.py#L63-68">mangles
+the <tt>&lt;root-ca&gt;</tt> XML tag</a> sent by GlobalProtect portal
+servers, which GlobalProtect's official client software uses to verify
+that certificates of servers it connects to. It can be used with
+<tt>mitmdump</tt> as follows:</p>
+
+<pre>
+  ./mitmdump -vvv --tcp $YOUR_GP_SERVER_IP -s /path/to/gp_ssl_log.py --ssl-version-server all --insecure
+</pre>
+
+<h2>Documenting VPN protocols</h2>
+
+<p>Sometimes it's most satisfying and productive to simply start
+coding up support for a new protocol or feature in OpenConnect
+itself. However, if you don't understand the structure of the
+OpenConnect codebase well, this may make it difficult to explain and
+discuss the code with more experienced developers.</p>
+
+<p>Often it is very useful to take a step back and explain how the VPN
+protocol works in more human-readable terms before implementing it in
+OpenConnect's codebase.  Preparing a document that intersperses prose
+explanations with captured traffic can aid in communication.  See
+<a href="https://github.com/dlenski/openconnect/blob/master/PAN_GlobalProtect_protocol_doc.md">PAN_GlobalProtect_protocol_doc.md</a>,
+(prepared during the implementation of the GlobalProtect protocol in
+OpenConnect, and subsequently updated) for a complete example.</p>
+
+<h2>Ask for help</h2>
+
+<p>Ask on the <a href="mail.html">mailing list</a> for help with new
+protocol implementations, or show us your code via Merge Requests
+on GitLab.</p>
+
+<INCLUDE file="inc/footer.tmpl" />
+</PAGE>