Bypass Any Firewall
This page is based heavily on the excellent SSH over HTTPS how-to that Dag Wieers wrote a couple of years ago. I felt the need to write it as since that article proxytunnel has had number of improvements and Dag's article has remained static. I originally had this as a private page for my friends to be referred to when they asked me how to set up their own tunnels but have decided it might as well be made available to everyone. If you have arrived at this page but were just trying to find a trivial web proxy for you to use then see if my simple Google-hosted proxy will suffice.
Tunnel SSH Over HTTP(S)
The purpose of this how-to is to show how a completely undetectable hole may be punched through a firewalled enviroment's web proxy to allow someone within it to access any website, any protocol and any port whilst looking like nothing more than casually browsing a single harmless-looking site even if full packet-inspection is employed. Traditionally such tunnelling is performed simply by connecting to an external SSH server that you control and have configured to listen on a port that the firewall allows access to (normally either 80 or 443). However the method described here, whilst more involved, has a number of benefits over this more basic approach which I feel greatly justifies its use:
- The standard method of connecting to an SSH server running on a port that happens to be open is easily detectable and blockable.
- This method works even when a full layer-7 firewall is used (application layer, your firewall not only checks your target hosts and ports, but also the type of traffic).
- This method allows you to continue to run a real site on your public port 80/443 and not have to give one up for your SSH server to listen on.
- This method allows your SSH server to be run on any port number or even remain completely hidden and inaccessible behind your firewall.
- The one Apache instance required allows you to connect to any number of target hosts and ports.
- The use of authentication at the Apache level makes the detection of the SSH server virtually impossible even if someone should guess what is being done.
- The optional use of SSL makes the traffic completely indistinguishable from real HTTPS traffic, even if full packet-sniffing were to be used.
The technique described here is useful whenever
a private and securely-encrypted connection to a web-based service is
required** and not just for bypassing local access restrictions. In many
cases such encryption can be performed by other methods but having this
'ultimate' setup at your disposal and knowing how to use it as a matter
of course means that you will always be able to secure your
comms and keep your internet-based activities private no matter what
type of environment or regime you should find yourself in.
Pre-Requisites:
In order to set up your server you need the following outside of the firewall:
- An internet connected server (e.g. your home server/PC or a hosted VPS).
- An Apache instance (preferably with SSL) on this host with mod_proxy installed and enabled (normally standard).
- An SSH server (on this host or elsewhere).
You don't need anything fancy for this, I have configured complete set-ups on standard home PCs (Windows and Linux) and even on hardware as small as a modified Linksys NSLU2.
To connect to your server (proxy) from within your firewall you will need:
- The proxytunnel utility (v1.9 or above).
- An SSH client (PuTTY v0.58 or above, OpenSSH etc).
If you're using this config to discretely browse the internet then you also need a browser on which you can change the proxy settings. I recommend using a separate install to your normal browser in order to keep your browsing history private, if you're running in a standard Windows environment Firefox Portable is ideal. If you are using other tools such as a personal email client etc. then again I suggest using a portable version wherever possible.
Server Configuration:
The server configuration is in three parts:
- Making your server publicly available by a fully-qualified domain name (FQDN) with standard HTTP/HTTPS ports (80/443) served by your Apache instance.
- Configuring Apache with a virtual host that allows its use as a proxy server (forward proxy).
- Configuring the SSH server to allow port-forwarding (this is normally standard).
1. Hostname / General Connectivity
You need to be able to connect to your server by a fully-qualified hostname. If you don't own your own domain or have a fixed IP address, then sign-up with a service such as DynDNS.com and register a dynamic hostname. All traffic that is tunnelled through your external server will appear to be traffic to this hostname and so you might want to give it a sensible, professional feel (not myhax0rproxy.dyndns.org). If you already have a domain name and wish to use this or one of it's sub-domains on a dynamic IP address then I recommend using EditDNS.net (or their free version) - these provide a simple way of updating your DNS CNAME records with your public IP address as it changes. Follow the instructions that your chosen provider supplies and configure their client on your server to keep your hostname updated with your changing IP address.
If you have a fixed IP address then obviously just create an address record for the sub-domain that you are planning on using to it.
If you have a firewall in place then you need to make sure you have allowed web traffic through it to the server on which Apache is running (ports 80 and 443).
2. Apache Config
Your Apache instance needs the proxy modules installed and enabled (a2enmod proxy proxy_connect proxy_http). It should also ideally be set-up for SSL - i.e. the ssl module installed and enabled (a2enmod ssl), certificates generated, listening on port 443 for HTTPS traffic etc.). In many cases the use of SSL won't be necessary but its use will make the tunnelled traffic completely indistinguishable from normal HTTPS access to your site. It's worth the effort unless you find the whole Apache with SSL thing too confusing in which case don't let it hold you back - plain old HTTP will work and is fine for most purposes.
Within your Apache configuration you need to include a virtual host configuration for your domain name (e.g. /etc/apache2/sites-available/www.example.com) that allows you to connect to your SSH server via this site (i.e act as a forward proxy). The necessary AllowConnect and ProxyMatch config is over and above any other site configuration. As all of your tunnelled traffic will look like standard web access of this site, I recommend that you do have browseable a web site also defined in your virtual host config.
Below is a sample virtual host
definition (assumes your FQDN is www.example.com). The text in bold
is that which is needed for the
purposes of your tunnelling (I will show two ways of controlling access
to the connection - one by user/password and one by client location).
The rest of the config is that needed for a
'normal' site and can be whatever you like. The text in italics is that which will normally be your general site content (DocumentRoot etc.) but I am just redisplaying www.ibm.com in this example.
NameVirtualHost *
<VirtualHost *>
# Site administration data
ServerAdmin webmaster@example.com
ServerName www.example.com
ServerSignature Off
# Site log settings
HostnameLookups Off
LogLevel Warn
CustomLog logs/access.log common
ErrorLog logs/error.log
# Enable SSL (apply if required once non-SSL connection has been tested)
#SSLEngine on
#SSLCertificateFile /etc/ssl/certs/ssl-cert-example.pem
#SSLCertificateKeyFile /etc/ssl/private/ssl-cert-example.key
# THIS IS THE CONFIG NEEDED FOR OUR TUNNELLING
# Allow proxy connect (forward-proxy) to servers only on port 22 (SSH)
ProxyRequests On
AllowConnect 22
# Deny all proxying by default...
<Proxy *>
Order deny,allow
Deny from all
</Proxy>
# This directive defines which <x>.example.com servers can be connected to.
# Access is controlled here via standard Apache user authentication.
<ProxyMatch (machine1|machine2|machine3)\.example\.com>
Order deny,allow
Allow from all
# You may remove the below 4 lines if you do not want to authenticate
# prior to allowing the proxy connection to be made. Either this or
# source host/IP restriction should be used. This is preferred.
AuthType Basic
AuthUserFile
/usr/local/etc/httpd/user
AuthName "www.example.com domain login"
Require valid-user
</ProxyMatch>
# We can allow access to other servers just by adding multiple directives.
# Access is controlled here based on source host/IP instead of user auth.
<ProxyMatch machine4\.someotherdomain\.com>
Order deny,allow
# The next 3 lines restrict proxy access to this host by source host
# or IP address. If you do not want this they may be replaced by an
# 'Allow from all' entry. I strongly recommend using just user auth
# (previous example) in all cases and ignore source based controls.
Deny from all
Allow from bigcorp.com
Allow from myuni.edu
Allow from 81.34.122.21
</ProxyMatch>
##
If you are sure your access controls are adequate, you can just use a
## single <ProxyMatch *> directive to allow SSH connection to ANY host.
## This is by far my preferred approach.
## <ProxyMatch *>
## Order deny,allow
## Allow from
all
##
AuthType Basic
## AuthUserFile
/usr/local/etc/httpd/user
##
AuthName "www.example.com domain login"
## Require valid-user
## </ProxyMatch>
#
END OF TUNNELLING CONFIG
# THIS BLOCK IS IN LIEU OF SETTING UP A REAL SITE ON THE VIRTUAL HOST
# (DOCUMENTROOT DEFINITION ETC.)
# IN THIS CASE, WWW.EXAMPLE.COM WILL MIMIC WWW.IBM.COM WHENEVER BROWSED.
ProxyPass / http://www.ibm.com/
ProxyPassReverse / http://www.ibm.com/
# Allow www.IBM.com to be redisplayed as this site contents by anyone
<Proxy http://www.ibm.com/>
Order deny,allow
Allow from all
</Proxy>
</VirtualHost>
In the interest of clarity for those unfamiliar with Apache this example config assumes that you're just using standard HTTP proxying. If you want to use full-blown HTTPS wrapping, then add in the appropriate SSL entries as usual*** to make your proxy connection identical to HTTPS browsing of the site. If you don't know what these SSL settings are, you're probably best keeping it as is.
Your Apache instance must be publicly available to the internet at large for this to work. Check that you have any firewall/routers etc. configured to allow this (ports 80 and 443).
3. SSH Server Config
Over and above having a valid logon defined, the only SSH server configuration required is that SSH port-forwarding must be allowed. This should be enabled by default in a standard OpenSSH or Dropbear installation.
As you will probably need to check log files and reconfigure/restart the web server during testing it is wise to at least initially have your SSH server publically available - make sure any firewalls you have in place allow this. Seeing as the server will be exposed to the internet at large during this time I recommend that you perform the usual SSH hardening tasks such as forbidding root logons, using authenticated keys and disabling plain passwords. Again, if this is all too confusing then don't let it hold you back as it's not absolutely necessary and the direct connection of your SSH server to the internet is purely optional in any case.
In normal operation the tunnelled SSH connections will be made directly from the Apache virtual host itself and so there is no need for the SSH server to be available to any host other than that. Once the setup is working it is therefore upto you to decide whether the SSH server should remain available outside of its network or be secured - it must always be accessable from the Apache virtual host, however, so make sure any firewalls you have in place continue to allow this.
Client Configuration:
The client configuration is in three parts:
- Determining the proxytunnel command that you need to connect to your target SSH server via the intermediary web proxies (local and external).
- Configuring your SSH client to connect via proxytunnel and to open a dynamic tunnel.
- Configuring your browser (and any other applications such as mail clients etc.) to send all traffic via your tunnel.
In the text below, we will use www.example.com to refer to the Apache virtual host defined in the Apache config shown above.
1. Proxytunnel Syntax
Depending on your network topology, proxytunnel will need different flags to connect (-e, -E, -X, -P, -R etc.). When determining what is needed I recommend running it on its own from within a console and using the -v flag to provide verbose output. In all cases it will need at least your local proxy (-p), your Apache virtual host site name (-r) and your SSH server name and port as in your ProxyMatch and AllowConnect statements (-d). If you're using authentication on your Apache virtual host then you will also need to use -R and probably -P or -N if your local proxy also requires logon credentials.
Your proxytunnel command can be said to be working when it returns an SSH server logon prompt on its invocation. At this time, replace any -v flag used with -q (quiet mode) and check it still works – there should be no output other than the SSH prompt returned at this time. Once this is the case then you have your basic proxytunnel command, e.g.:
proxytunnel -q -p my.local.proxy:8080 -P localproxyuserid:localproxypass -r www.example.com:80 -R extapacheuserid:extapachepass -d machine1.example.com:22 -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)\nHost: www.example.com\nContent-Length: 0\nPragma: no-cache"
The above example may be broken down as:
-q don't display any output (only add this flag once you're happy the command works)
-p my.local.proxy:8080 connect via local HTTP proxy on host my.local.proxy, port 8080
-P localproxyuserid:localproxypass use the userid 'localproxyuserid' and password 'localproxypass' to authenticate on local proxy
-r www.example.com:80 connect to the HTTP proxy running on the external Apache virtual host, port 80
-R extapacheuserid:extapachepass use the userid 'extapacheuserid' and password 'extapachepass' to authenticate on the external proxy
-d machine1.example.com:22 ultimately connect to port 22 on server machine1.example.com. This host must resolve from your Apache server.
The -H argument specifies the headers that proxytunnel sends and makes the proxytunnel connection look like a standard web browser. You can see what should go in here within your organisation by running a packet sniffer whilst accessing a site via your normal browser and just mimic what you see it sending out on its first connection. Again, if this is beyond you, just omit it or copy what I have used as it'll be good enough in most cases. It should be included if you want the proxytunnel connection to exactly mimic just browsing your website.
If you decide to use SSL then the remote proxy argument (-r) should specify your Apache virtual host on port 443 instead of 80 and you will need to add one of the encryption flags (-e , -E, -X etc.). An unencrypted command line is useful to use in any case during testing, especially if you have trouble working out which of the encryption options you need to supply to get SSL wrapped traffic working for your topology. Once you have the unencrypted working, then you can move onto including SSL.
It is this proxytunnel command used in conjunction with your Apache configuration that wraps your SSH connection and makes all of its traffic appear to be HTTP/HTTPS traffic to any intermediary firewall. Once we know that this command works, we just need to tell our SSH clients to connect to our SSH servers with it instead of going directly.
2. Client Configuration
If you are using OpenSSH as your client then within your ~/.ssh/config file you need to include config that tells ssh to use the proxytunnel command when trying to connect to any SSH servers for which you have ProxyMatch directives for in your virtual host config:
Host *.example.com *.someotherdomain.com
ProxyCommand
proxytunnel -q -p my.local.proxy:8080 -P
localproxyuserid:localproxypass -r www.example.com:80 -R
extapacheuserid:extapachepass -d %h:%p -H "User-Agent: Mozilla/4.0
(compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)\nHost:
www.example.com\nContent-Length: 0\nPragma: no-cache"
DynamicForward 1080
ServerAliveInterval 60
To connect to your server and open your tunnel, just run:
[user@firewalled-desktop ~]$ ssh machine1.example.com
enter password: ********
[user@machine1 ~] $
Once you have authenticated and have a
shell on your external host, the DynamicForward on port 1080 defined
in your ~/.ssh/config file should be available to you for use as a
SOCKS proxy. The ServerAliveInterval will prevent the connection from
closing with inactivity.
If you are using PuTTY (my preferred client when in a Windows environment) then you need to specify proxytunnel as a 'local proxy command' (available as of v0.58). From within menu item Connection -> Proxy, select the Local proxy type and then type the following in the field 'Telnet command, or local proxy command' (you must use the full path to proxytunnel if it is not in your path or held in the PuTTY folder):
proxytunnel -q -p my.local.proxy:8080 -P localproxyuserid:localproxypass -r www.example.com:80 -R extapacheuserid:extapachepass -d %host:%port -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)\nHost: www.example.com\nContent-Length: 0\nPragma: no-cache"
[ You may replace some of the hard-coded values above with the internal variables that PuTTY allows (e.g. %user, %pass for your proxy userid and password if they have been entered into the associated PuTTY GUI fields). Also notice that unlike OpenSSH, PuTTY uses the variables %host and %port instead of %h and %p to resolve to the target server name and port when determining the proxy command to be executed. ]
The Dynamic port forward should be created under the menu item Connection -> SSH -> Tunnels. Add a port forward of type 'Dynamic' with source port 1080.
Again, once you have successfully logged onto your SSH server, your dynamic port forward should be available for use as a SOCKS proxy. Save the working session for further use.
3. Configuring Browser To Use Tunnel
The dynamic tunnel created by your SSH client allows you to socksify any TCP connection and direct it over the SSH tunnel to get outside of your local environment. Most browsers (and many other applications) allow you to socksify their own stack by simply configuring a SOCKS proxy. To use this feature simply define your browser's proxy as of type SOCKS and on localhost:1080 and all data will be sent via the SSH tunnel.
If you are wanting completely discrete browsing then in Firefox you can also set network.proxy.socks_remote_dns to True. This ensures all DNS lookups are also tunnelled so you do not leak details of the sites that you are visiting by requesting DNS lookups on your local name servers.
If you wish to run other applications over this tunnel then just change their network settings such that they also operate over the SOCKS proxy on localhost:1080. If your application does not have an option for running via a proxy natively then you may find you can run it via a library such as tsocks or a tool like proxifier or FreeCap to provide such functionality.
Additional Information
This
isn't meant to be a discourse on SSH tunnelling in general but rather
just how to use proxytunnel and Apache to extend 'normal' SSH tunnelling
to networks where it would otherwise be unavailable. Many more examples
of how to use your tunnel may be found by searching the internet for 'ssh tunnelling' or 'ssh port forwarding'.
Here are a few other articles that may be of interest:
- Muppet's original paper on proxytunnel. A great article giving its history and lots of thoughts on its possible uses.
- Dag's original article on tunnelling SSH over HTTP(S). The basis for this page, based on older proxytunnel features and syntax.
- Russel Stuart's HTTTP-proxy-tunnel. A proxytunnel alternative. Can bounce through more proxies and has in-built port forwarding.
- A use of SSH tunnelling for SAP Basis Consultants. A clever use of SSH tunnelling for remote SAP system access.
* Confession - this technique doesn't actually 'get through firewalls' per se, there has to be a web proxy that you can get to the outside world through which allows 'HTTP CONNECT' in order for this to work (so one that allows you to access https sites...). Even then, you might
be thwarted by some proxies if they are ultra-conservative and ban all
sites by default, allowing access only to those on a white-list. In this
case, you can try using the Apache config shown in italics to have your virtual host redisplay
the contents of a site which is of use within your environment and then
request that it be added to the white list. It's safe to say that once
you can browse to your website from behind your firewall, there is nothing to stop this technique working.
** This
technique obviously only secures the comms between your local client
and your external server. Should you want security/anonymity further
down the line (i.e. from your ISP or local territory) then you should
consider running an application such as Tor on your server and ultimately forward your traffic through this.
For further anonymity consider where your DNS requests are being
resolved - you may want to change to external name servers such as Google or OpenDNS if you are not using Tor.
*** Older versions of Apache had a bug (29744) which caused the mod_proxy CONNECT
to fail when used in conjunction with SSL. Although this may now been
resolved, if you do not wish to update an existing instance that has
this bug, you may get around the problem by using the standalone tool stunnel (it appears that versions v4.48+ cannot be used) to provide the SSL wrapping of Apache.
posted on 2013-01-31 13:34 Richard.FreeBSD 阅读(423) 评论(0) 收藏 举报
浙公网安备 33010602011771号