OpenBSD Journal

Tunnelling out of corporate networks (Part 1)

Contributed by sean on from the slacker-of-the-year dept.

Mark Uemura (mtu@) writes in:

Tunneling out of corporate networks (Part 1)

I have always been intrigued with encrypted network tunnels, be it ipsec(4) or ssh(1). Yet, I don't think that anything beats SSH VPN tunneling on OpenBSD for a quick, elegant and stealth-like solution without the IPsec headaches.

Read on to find out more about SSH VPN tunnels:

Articles 1 2 3 4 5

After discussing tunnels with Ryan McBride (mcbride@) and its implications for security and/or policy violations, he made a comment that he has yet to see a network that he was not able to tunnel out of. There are various tools in ports to do just that, assuming that you are not using IPsec or SSH. However, before I get into corporate policy violations and back-channel malware tunnels, I should back up in time to give some perspective and my experiences with VPNs.

At C2K6, I was working with Hans-Joerg Hoexer (hshoexer@) on IPsec failover VPNs using sasyncd(8). I also had the pleasure of sitting pretty close to Reyk Floeter (reyk@). He was the first person to introduce me to VPN tunnels using SSH. Reyk had a SIP phone that he was carrying around to call home with a SSH VPN using the tun interface. He developed this SSH VPN functionality with bits of code from Markus Friedl (markus@) and merged it into OpenSSH at the end of 2005. Since then, we have had the ability to create SSH based layer 2 or layer 3 VPN tunnels all handled at layer 7 :-).

It wasn't until last year that I started experimenting with this in earnest. Normally, I use SSH port forwarding with authpf(8) and key/passphrase authentication for most things and IPsec with authpf where port forwarding is not practical. Generally, with OpenSSH VPNs, you don't have to worry about Maximum Transition Unit (MTU) issues or firewalls getting in the way of the VPN. For the record, I'm not a fan of PKI so I have never gone down the ssl(8) VPN path.

SSH VPNs do their magic at the application layer (layer 7) without the headaches and baggage that come with traditional IPsec VPNs. Now, I can use OpenSSH to do what IPsec used to do for me in the past. IPsec on OpenBSD is really simple to set up but became more problematic with other Operating Systems. Yes, you need to work through this and familiarize yourself with IPsec implementations for each OS but it seems more complicated than it needs to be. OpenBSD has really simplified the setup and configuration of IPsec VPNs.

Unfortunately, in the real world, you often come across firewalls that block ESP/AH or ISAKMP/ISAKMP-NAT-T. Moreover, packet fragmentation caused by MTU issues were always a concern. If you didn't get the MTU just right, the user would run into fragmentation issues making the VPN really slow resulting in a negative end user experience. Lowering the MTU is really important in order to avoid this issue but in doing so, you inevitably reduce the maximum throughput of non-IPsec traffic. However, too many networks block icmp(4) or TCP MTU discovery which at times can cause "speed issues" with the road warriors you need to support. Well, with pf and scrub you can compensate for this but when you are dealing with Windows, changing the MTU is an all or nothing dilemma.

To the point, with SSH VPNs, you've got one of the most trusted of SSH implementations, OpenSSH, and all the security goodness that comes with it. Here's a simple config set borrowed from ssh(1):


How to use OpenSSH-based virtual private networks
-------------------------------------------------

(1) Server: Enable support for SSH tunneling (/etc/ssh/sshd_config):

	PermitTunnel yes

send the hangup signal (SIGHUP) to reload the new sshd_config

(2) Server: Restrict client and assign the tunnel (/root/.ssh/authorized_keys)

	tunnel="1",command="sh /etc/netstart tun1" ssh-dss ... my_id_dsa

(3) Server: /etc/hostname.tun1

	inet 192.168.5.2 255.255.255.252 192.168.5.1
	!/sbin/route add -inet zzz.yyy.xxx.0/24 192.168.5.1

(4) Client: Configure the local network tunnel interface (/etc/hostname.tun1)

set up the layer 3 tunnel on the client:

	inet 192.168.5.1 255.255.255.252 192.168.5.2
	!/sbin/route add -inet aaa.bbb.ccc.0/24 192.168.5.2

(5) Client: Configure the OpenSSH client (in /root/.ssh/config):

	Host AAA.BBB.CCC.DDD
        	Tunnel yes
        	TunnelDevice 1:any
        	PermitLocalCommand yes
        	LocalCommand sh /etc/netstart tun1

The following network plan illustrates the previous layer 2 configuration.

zzz.yyy.xxx.0/24                                  aaa.bbb.ccc.0/24
----------------                                  ----------------
    |                                                     |
    |                                                     |
zzz.yyy.xxx.www                                    AAA.BBB.CCC.DDD
+--------+               (          )                +--------+
| Client |--------------(  Internet  )---------------| Server |
+--------+               (          )                +--------+
    : 192.168.5.1                             192.168.5.2 :
    :.....................................................:
           Forwarded ssh connection (Layer 3 tunnel)

--- real connection
... "virtual connection"

AAA.BBB.CCC.DDD   "Server public IP address"
aaa.bbb.ccc.0/24  "Private network behind above public IP address"

zzz.yyy.xxx.www   "Client private IP address"
zzz.yyy.xxx.0/24  "Private network behind above private IP address"

(6) Client: Connect to the server and establish the tunnel

	# ssh AAA.BBB.CCC.DDD

when successful, you should see the following interface created on
the server:

tun1: flags=51 mtu 1500
        groups: tun
        inet 192.168.5.2 --> 192.168.5.1 netmask 0xfffffffc

(7) Client and Server: pf needs to be configured to allow and perhaps
hide networks on either side via NAT.  Essentially both the client and
the server have become VPN peers. The Client above is not directly 
connected to the Internet.  It is on a private network behind some
Internet router. Imagine the client inside some corporate network.

I went a little crazy to see how far I could take this. When forced to use Windows, I would configure VMWare and install OpenBSD as a guest and then create the SSH VPN. I could then pass traffic to and from Windows through the tunnel using OpenBSD and OpenSSH as the conduit. I've done similar things with Mac OS X but David Gwynne (dlg@) informed me that there are more elegant hacks that can be done when using a Mac. Obviously, running OpenBSD in VMWare just to create a VPN to tunnel out of some restricted network seems a little much and dangerous for many reasons but it is not too difficult to do. Alternatively, you can create the SSH VPN tunnel on a different machine running OpenBSD and turn it into a router for other machines to enjoy the tunnel too.

Now the benefits are that you don't have to worry about firewalls as most networks don't proxy SSL connections. Configuring your SSH server to listen on port 443 and/or port 53 eliminates firewall issues most of the time. Since we are using OpenSSH for this VPN, we also don't have to worry about fragmentation issues :-). Thanks Reyk!

The above discussion is background info for another article that I have in the pipeline. In the meantime, I would be very curious and happy to hear what others have to say about their experience with SSH VPN tunnels using the tun interface. I am also interested in what packages and efforts you go through to break out of supposedly secure proxied networks.

Mark T. Uemura

What a tease! Thanks Mark for explaining this underused feature of ssh and we're anxiously waiting for the second part!

(Comments are closed)


Comments
  1. By Dan Shechter G (danshtr) danshtr@gmail.com on

    Very interesting read. Thanks!

    Are these papers are relevant to OpenSSH TCP tunneling implementation?

    http://www-imase.ist.osaka-u.ac.jp/paper/Honda05_ITCom_ppt.pdf

    http://sites.inka.de/~W1011/devel/tcp-tcp.html

    http://www.cs.cmu.edu/~rajesh/papers/tunnel1-3.PDF

    Maybe the internet today is better then when these papers where written.

    Comments
    1. By Anonymous Coward (Anon) on

      > http://sites.inka.de/~W1011/devel/tcp-tcp.html

      > Maybe the internet today is better then when these papers where written.

      "At that time it had to run over an optical link which suffered frequent packet loss, sometimes 10-20% over an extended period of time."

      "the internet" wasn't that bad when that was written. This article talks about a connection with seriously bad packet loss. They're right, TCP in TCP tunnels will totally suck with this sort of connection. Even plain ordinary TCP won't cope well with that (it takes any packet loss to indicate congestion and throttles right back).

      Over a more typical connection, then or now, it's nowhere near that bad. In most circumstances it's totally usable. When it doesn't work you might do better with ipsec. And when ipsec doesn't work you might do better with this.

  2. By jirib (jirib) jirib@mailinator.com on

    not exactly related to OpenBSD but I have to use commercial socks 5 server with SSL extension (see http://ss5.sourceforge.net/draft-ietf-aft-socks-ssl-00.txt), but there is not opensource socks client which supports it :(

    does ATTclient run under OpenBSD? any experience? it does exist for linux.

  3. By Ed Ahlsen-Girard (girard) girarde@alum.rpi.edu on

    Slick!

  4. By Wild K.H. (lynxxx) kh.wild@wicom.li on Karl-Heinz

    >> I've done similar things with Mac OS X but David Gwynne (dlg@) informed me that there are more elegant hacks that can be done when using a Mac.

    I would be very interested in more detail informations about this topic.
    Are there any?

  5. By Guy (guy) guybsd@gmail.com on

    As you point out, you can put your SSH service on port 443 or 53.

    To make it more certain that you can access your SSH server from a corporate network, you can multiplex port 80 for both SSH and HTTP on your outside server.

    The concept is simple (tool: 'portknock')
    - run a webserver on port 80
    - have a process watch for access to a certain page on the webserver
    - when the page is accessed, have the process add the source address to a pf table
    - preconfigure a rule in pf for all access from the source address to port 80 of the server to be redirected to port 22
    - now, access to port 80 from the source address will provide an SSH service (but web service for everyone else)
    - quickly expiring the port forward rule will make the service revert back to a webserver, even for the designated source address, but the state will remain for the existing SSH session

    Comments
    1. By Richard D. (bsdude) on

      > As you point out, you can put your SSH service on port 443 or 53.
      >
      > To make it more certain that you can access your SSH server from a corporate network, you can multiplex port 80 for both SSH and HTTP on your outside server.
      >
      > The concept is simple (tool: 'portknock')
      > - run a webserver on port 80
      > - have a process watch for access to a certain page on the webserver
      > - when the page is accessed, have the process add the source address to a pf table
      > - preconfigure a rule in pf for all access from the source address to port 80 of the server to be redirected to port 22
      > - now, access to port 80 from the source address will provide an SSH service (but web service for everyone else)
      > - quickly expiring the port forward rule will make the service revert back to a webserver, even for the designated source address, but the state will remain for the existing SSH session

      Awesome stuff, thank you!

      Would be great if you wrote a small undeadly article for this too, how you do it, etc. *hint hint* =)

    2. By Alex (levity) on

      Fascinating article. Please forgive me for being slightly off topic with my question but was certain that if anybody knew the answer it would be the author of this story or maybe one of the readers.

      I've been using nc(1) for approximately six months to send all my new ssh sessions through a SOCKS proxy on my loopback interface using ProxyCommand in .ssh/config:


      Host *
      ProxyCommand nc -x127.0.0.1:9999 %h %p


      Could anybody tell me if I could substitute dante (socksify) or socat with nc(1) for sending other applications through SOCKS proxy, if yes could you please give some syntax examples for sending lynx traffic through? Really appreciate any feedback.

    3. By Guy (guy) on

      That should have said, "tool: 'pageknock

      > The concept is simple (tool: 'portknock')

  6. By Anonymous Coward (DoctorPhish) on

    My employer and I have been having an (unintentional) arms race in regards to tunneling out.
    The setup consists of a windows box with cygwin connecting to an OpenBSD firewall.
    At first, it was relatively simple. I just needed to get past the NTLM authenticated proxy, which was easy with NTLMAPS.
    The proxy also didn't allow encrypted traffic over any port but 443, so using pf to redirect the port 443 from said employer's public IP made the setup work.
    Then, they upgraded the proxy, and it started rejected non-ssl traffic over port 443.
    This took a bit more thinking, but using nc to SSL encrypt the SSH traffic, and using stunnel to listen on the other end made the whole thing work.
    Of course, my boss knows that I'm doing this, and have actually used it to save the day; allowing the accountants access to legitimate business websites that the corporate proxy unintentionally mangled (ie. anything not using standard ports). It took them a year to get it working with the corporate proxy.
    I wouldn't suggest poking through corporate firewalls without permission, as the consequences of being caught would likely be severe

    Comments
    1. By Anonymous Coward (Anon) on

      > This took a bit more thinking, but using nc to SSL encrypt the SSH traffic, and using stunnel to listen on the other end made the whole thing work.

      I think you can do that with relayd too, now.

  7. By Jeff Quast (dingo) af.dingo@gmail.com on

    I have yet to see a vpn I couldn't tunnel out of either, but they are beginning to make it hard. The most obnoxious one I ran into a few years ago was a web proxy appliance that required NTLM (windows) authentication. Lucky for me, there was a python-based program that was able to tunnel a single tcp connection through it, and after a few edits, i was able to coerce it to work and get out with ssh.

  8. By Brynet (Brynet) on

    IP over ICMP = http://github.com/jakkarth/icmptx/tree/master
    TCP over ICMP = http://www.cs.uit.no/~daniels/PingTunnel/
    IP over DNS = http://code.kryo.se/iodine/

  9. By Jul_bsd (jul_bsd) jul_bsd@yahoo.fr on

    Super stuff !!!

    any way to allow this for non-root user ?
    Most of the time i block root user in sshd. and i hope most admin do the same.

    So, something like this would be great (server side)

    Match user xxx
    PermitTunnel yes
    ForceCommand "sh /etc/netstart tun1"

    or maybe we can manually connect to the server and call netstart with sudo ?

    but the problem is the same on client side.
    maybe a "LocalCommand sudo sh /etc/netstart tun1" could work
    and after there is portability problem with Windows/putty ...

    Anyway, thanks a lot for this tuto

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]