Create a SOCKS proxy on a Linux server with SSH to bypass content filters

Mattias Geniar, Thursday, January 19, 2017 - last modified: Thursday, February 16, 2017

Are you on a network with limited access? Is someone filtering your internet traffic, limiting your abilities? Well, if you have SSH access to any server, you can probably set up your own SOCKS5 proxy and tunnel all your traffic over SSH.

From that point on, what you do on your laptop/computer is sent encrypted to the SOCKS5 proxy (your SSH server) and that server sends the traffic to the outside.

It's an SSH tunnel on steroids through which you can easily pass HTTP and HTTPs traffic.

And it isn't even that hard. This guide is for Linux/Mac OSX users that have direct access to a terminal, but the same logic applies to PuTTy on Windows too.

Set up SOCKS5 SSH tunnel

You set up a SOCKS 5 tunnel in 2 essential steps. The first one is to build an SSH tunnel to a remote server.

Once that's set up, you can configure your browser to connect to the local TCP port that the SSH client has exposed, which will then transport the data through the remote SSH server.

It boils down to a few key actions;

  1. You open an SSH connection to a remote server. As you open that connection, your SSH client will also open a local TCP port, available only to your computer. In this example, I'll use local TCP port :1337.
  2. You configure your browser (Chrome/Firefox/...) to use that local proxy instead of directly going out on the internet.
  3. The remote SSH server accepts your SSH connection and will act as the outgoing proxy/vpn for that SOCKS5 connection.

To start such a connection, run the following command in your terminal.

$ ssh -D 1337 -q -C -N user@ma.ttias.be

What that command does is;

  1. -D 1337: open a SOCKS proxy on local port :1337. If that port is taken, try a different port number. If you want to open multiple SOCKS proxies to multiple endpoints, choose a different port for each one.
  2. -C: compress data in the tunnel, save bandwidth
  3. -q: quiet mode, don't output anything locally
  4. -N: do not execute remote commands, useful for just forwarding ports
  5. user@ma.ttias.be: the remote SSH server you have access to

Once you run that, ssh will stay in the foreground until you CTRL+C it to cancel it. If you prefer to keep it running in the background, add -f to fork it to a background command:

$ ssh -D 1337 -q -C -N -f user@ma.ttias.be

Now you have an SSH tunnel between your computer and the remote host, in this example ma.ttias.be.

Use SOCKS proxy in Chrome/Firefox

Next up: tell your browser to use that proxy. This is something that should be done per application as it isn't a system-wide proxy.

In Chrome, go to the chrome://settings/ screen and click through to Advanced Settings. Find the Proxy Settings.

In Firefox, go to Preferences > Advanced > Network and find the Connection settings. Change them as such:

From now on, your browser will connect to localhost:1337, which is picked up by the SSH tunnel to the remote server, which then connects to your HTTP or HTTPs sites.

Encrypted Traffic

This has some advantages and some caveats. For instance, most of your traffic is now encrypted.

What you send between the browser and the local SOCKS proxy is encrypted if you visit an HTTPs site, it's plain text if you visit an HTTP site.

What your SSH client sends between your computer and the remote server is always encrypted.

What your remote server does to connect to the requested website may be encrypted (if it's an HTTPS site) or may be plain text, in case of plain HTTP.

Some parts of your SOCKS proxy are encrypted, some others are not.

Bypassing firewall limitations

If you're somewhere with limited access, you might not be allowed to open an SSH connection to a remote server. You only need to get an SSH connection going, and you're good to go.

So as an alternative, run your SSH server port on additional ports, like :80, :443 or :53: web and DNS traffic is usually allowed out of networks. Your best bet is :443, as it's already an encrypted protocol and less chance of deep packet inspection middleware from blocking your connection because it doesn't follow the expected protocol.

The chances of :53 working are also rather slim, as most DNS is UDP based and TCP is only use in either zone transfers or rare DNS occasions.

Testing SOCKS5 proxy

Visit any "what is my IP" website and refresh the page before and after your SOCKS proxy configuration.

If all went well, your IP should change to that of your remote SSH server, as that's now the outgoing IP for your web browsing.

If your SSH tunnel is down, crashed or wasn't started yet, your browser will kindly tell you that the SOCKS proxy is not responding.

If that's the case, restart the ssh command, try a different port or check your local firewall settings.



Hi! My name is Mattias Geniar. I'm a Support Manager at Nucleus Hosting in Belgium, a general web geek, public speaker and podcaster. Currently working on DNS Spy. Follow me on Twitter as @mattiasgeniar.

I respect your privacy and you won't get spam. Ever.
Just a weekly newsletter about Linux and open source.

SysCast podcast

In the SysCast podcast I talk about Linux & open source projects, interview sysadmins or developers and discuss web-related technologies. A show by and for geeks!

cron.weekly newsletter

A weekly newsletter - delivered every Sunday - for Linux sysadmins and open source users. It helps keeps you informed about open source projects, Linux guides & tutorials and the latest news.

Share this post

Did you like this post? Will you help me share it on social media? Thanks!

Comments

Wouter D'Haeseleer Saturday, January 21, 2017 at 12:11

I think it’s also worth pointing out that you are also able to do this on an already established SSH session,
Just hit the SSH escape sequence and force your SSH connection to accept command line arguments:

~C

So hit ENTER then ~ and then capital C

Now just add the port forward like on the CLI

-D 1234

for example

Reply


Serge van Ginderachter Saturday, January 21, 2017 at 17:58

Except when one already multiplexes one’s SSH connections by default.

“`
serge ~ ~C escape not available to multiplexed sessions
“`

Reply


Mattias Geniar Saturday, January 21, 2017 at 20:31

I think it’s also worth pointing out that you are also able to do this on an already established SSH session

Ooh, that’s a nice trick – didn’t know that. Thanks!

Reply


shyam jos Sunday, January 22, 2017 at 10:23

will this work if ssl/ssh packet inspection enabled in firewall ?

Reply


manu Sunday, January 22, 2017 at 14:03

oneliner to connect through the SOCKS proxy:

on linux:

$ google-chrome -proxy-server="socks5://127.0.0.1:8080" --host-resolver-rule="MAP * 0.0.0.0, EXCLUDE 127.0.0.1:8080"

on mac:

$ open -a /Applications/Google Chrome.app --args --proxy-server="socks5://127.0.0.1:8080" --host-resolver-rule="MAP * 0.0.0.0, EXCLUDE 127.0.0.1:8080"

Reply


Mattias Geniar Monday, January 23, 2017 at 10:49

will this work if ssl/ssh packet inspection enabled in firewall ?

Yes, you’re using the SSH protocol to encapsulate all your packets. It’s not a “hack” on SSH, it’s a built-in feature, so it should pass through any DPI firewalls.

Reply


Wouter D'Haeseleer Tuesday, January 24, 2017 at 16:01

I do have to point out that most DPI firewalls are able to see that you are not sending SSL traffic over port 443 but SSH

In fact even a basic proxy is able to detect this kind of beakout.
(Because SSH starts with exchanging the version as clear text traffic)

To also hide the fact that you are using SSH to tunnel one could create a OpenVPN tunnel over port 443.
SInce openVPN uses the same Negotiation as HTTPS it would be impractical to to dectect this traffic as non HTTPS traffic.

That said a PaloAlto is still able to fingerprint SSL based traffic and filter HTTPS from other SSL stuff.

Reply


Leave a Reply

Your email address will not be published. Required fields are marked *