How to Make Your Own Undetectable VPN

We take privacy very seriously at Hive. We are developing a social network which helps maintain the privacy, security and freedom that has made the internet a great place to communicate across the world. Often, strong encryption techniques are not enough to protect you from surveillance from governments or adversaries. For this reason, it is often necessary to make use of proactive obfuscation techniques, which help disguise the true intent of what you are doing. You can read more about this in the book ‘Obfuscation: A User’s Guide for Privacy and Protest’, which you can buy here. I recommend it to anybody who is even vaguely interested in preserving their freedoms online.

This tutorial was born out of my need to access a remote server from behind a restrictive firewall, but the applications of this method could be far more important. For instance, people in China – who have their internet access restricted by the Great Firewall – could use this technique to hide their outgoing internet connections from the government. Of course, it is possible that you could use this method to gain access to restricted sites at work or school but we don’t advocate this since it may jeopardise your job or education, and the security of your employer (nobody wants that). This method has been tested by me but I cannot guarantee that it will work in every scenario.

The way this method works is by encrypting typical VPN traffic (which is usually detected using Deep Packet Analysis), and sending it over port 443 (which is usually unblocked by firewalls for HTTPS). In case you were unaware, a VPN is used to encrypt traffic between a server and a client, usually to access blocked content, or hide traffic from snoopers.

Prerequisites:

  • A remote server running Linux (I recommend a VPS/Dedicated Server, but you can use almost any device)
  • SSH access to the remote server + internet access

Method:

In this method, I am making the following assumptions:

  1. You are able to access your remote server through SSH, or can access it locally.
  2. Access to your server’s IP address/URL is not blocked
  3. Port 443 (for SSL) is not blocked by your firewall (uncommon)

If any of the above are not true, you may have difficulty completing this tutorial but there are ways around them which are beyond the scope of this tutorial. You should also be familiar with standard security practices, which are also beyond the scope of this tutorial.

Installing and Setting Up OpenVPN

First of all, it is necessary to install OpenVPN on your remote server. We will also install easy-rsa, which is necessary for generating RSA key pairs for encrypting the VPN traffic. The method for this is different depending on the distribution of Linux that you are using, but the following snippet will work on Debian-based operating systems (such as Ubuntu):

apt-get update
apt-get install openvpn easy-rsa

Next, we will unzip the sample OpenVPN config file to our OpenVPN directory:

gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf

Then, we need to open the newly created config for editing. The following snippet uses nano (which is easiest), but you can you use vim or any other text editor.

nano /etc/openvpn/server.conf

Now that the config file is open in your preferred text editor, you will need to make the following change:

;proto tcp
proto udp

This needs to be changed in order to use the TCP protocol rather than UDP (since stunnel, which we will use later, uses TCP)

proto tcp
;proto udp

Now you must edit the line:

dh dh1024.pem

And replace it with:

dh dh2048.pem

This will configure OpenVPN to use a 2048-bit encryption key, as opposed to a weaker 1024-bit encryption key. Next, you will need to edit the line:

;push "redirect-gateway def1 bypass-dhcp"

And replace it with the following:

push "redirect-gateway def1 bypass-dhcp"

As you can see, I have removed the semi-colon from the start of the line, in order to uncomment it. You will have to so the same to another two lines, which relate to the DNS servers used by VPN clients. The lines are:

;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.222.222"

After that, you should uncomment the lines pertaining to the user and user group that OpenVPN is ran as. Since OpenVPN is web-facing, we want it to be restricted in how it can change our server. In order to limit this, we will uncomment the following lines (remove the semi-colons):

;user nobody
;group nogroup

Now that OpenVPN is successfully configured and secured, we can save our changes and exit our text editor (Ctrl+X in nano)

Correct Packet Forwarding

We need to configure the server to forward packets, rather than just dropping them when they reach the server. To do so, we must run the following command:

echo 1 > /proc/sys/net/ipv4/ip_forward

In order to make this change permanent, we must edit the system control file at:

nano /etc/sysctl.conf

All you must do is edit the following line:

#net.ipv4.ip_forward=1

to:

net.ipv4.ip_forward=1

Which will make this change persist, even when you reboot your server.

Generating and installing encryption keys

It is now time to set up a Certificate Authority, to issue certificates to both the server and the client. This authority will be used when generating certificates for any client that wants to connect to your server. You can start this process by copying the easy-rsa binaries to the openvpn directory using the following command:

cp -r /usr/share/easy-rsa/ /etc/openvpn

Then, we must create the directory which will be used to store the keys generated by easy-rsa in the next steps:

mkdir /etc/openvpn/easy-rsa/keys

After that, it is useful to set up easy-rsa’s variables file in order to set some defaults when generating new certificates. To do so, use the command:

nano /etc/openvpn/easy-rsa/vars

Then, edit the lines directly below the line that reads:

# Don't leave any of these fields blank.

Next, we will generate the key that we referenced earlier in the openvpn config file. We do this by running:

openssl dhparam -out /etc/openvpn/dh2048.pem

Now, we must change the working directory to that used by easy-rsa, by running:

cd /etc/openvpn/easy-rsa

After that run the following command to initialise the Public Key Infrastructure, including the leading dot and space:

. ./vars

Then run the following command to remove any potential example keys that easy-rsa has included:

./clean-all

We must now run a command which will establish our certificate authority, using the variables from earlier (you can just press [enter] to confirm these variables):

./build-ca

Generating the server’s key and certificate

In order to generate a key for the clients to encrypt traffic sent to the server, we must run the following command:

./build-key-server server

Just press [enter] when prompted for challenge or company name. Then, answer yes (y) to the prompts to sign the certificate and to commit.

Finally in the key generation, we must move the generated certificates and key to the openvpn directory. To do so, run the following command:

cp /etc/openvpn/easy-rsa/keys/{server.crt,server.key,ca.crt} /etc/openvpn

Now the certificates are in place, you can continue to the next step, which is running the OpenVPN server.

Running OpenVPN

In order to start the OpenVPN service, you must run:

service openvpn start

Now, assuming you have completed all of the steps successfully, you will have a functioning OpenVPN server.

Generating client keys and certificates

You will need to generate a unique key pair and certificate for each client that uses the server. In order to do so, complete the following tasks for the number of devices you wish to connect. (Where {client-name} is the name of the client)

./build-key {client-name}

As before, confirm all of the defaults by pressing enter. Then when prompted, type ‘y’ in order to confirm the signing and committing of the generated keys.

Next, we will want to create a configuration file for the client, which they will use along with their keys to connect to the server. In order to do this, run the following command, which will copy the sample file to the keys directory:

cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/easy-rsa/keys/client.ovpn

Transferring keys to the client

The final stage in setting up OpenVPN is to transfer the keys and the default config files to the client. This can be done in a number of ways, the most common of which is to use SFTP. This is easy to do, and just involves using Filezilla or similar to connect using SSH and download the following files:

/etc/openvpn/easy-rsa/keys/{client-name}.crt
/etc/openvpn/easy-rsa/keys/{client-name}.key
/etc/openvpn/easy-rsa/keys/client.ovpn
/etc/openvpn/ca.crt

Combining the config and the keys

Next, you must edit the files you have downloaded to the client. Doing this means that we have one file which contains the configuration and the keys for the client. To do so, open the file client.ovpn in your text editor of choice. The first change to make is to change the following:

remote my-server-1 1194

You must change the my-server-1 to the IP address of URL of your remote server. Then, you must comment out the following three lines:

ca ca.crt
cert client.crt
key client.key

In order to merge the configuration with the keys, you must paste the contents of the key files into the following XML tags at the end of the config file:

<ca>
[Contents of ca.crt]
</ca>

<cert>
[Contents of {client-name}.crt]
</cert>

<key>
[Contents of {client-name}.key]
</key>

Testing the VPN config

Depending on your platform, there are different methods for connecting to your newly configured OpenVPN server. The following is the method for Windows:

  1. Install OpenVPN
  2. Transfer client.ovpn to C:/Program Files/OpenVPN/config
  3. Right click the OpenVPN taskbar icon and click ‘start’

If your VPN has successfully connected, then you can move on to the next stage, which will cover how to obfuscate your VPN traffic to make it look like normal SSL traffic.

Setting up STunnel to Obfuscate Traffic

While having a VPN running remotely is fine, it is sometimes necessary to take further steps in order to hide traffic from adversaries. STunnel does this by disguising your VPN (or other service) traffic as normal SSL traffic. By combining this with the use of port 443, there is no feasible method of differentiating this traffic from typical SSL traffic.

First of all, you will need to install stunnel. You can do this on Debian-based systems by running:

apt-get install stunnel

Then, we must generate another certificate which will be used to encrypt the traffic from client to server:

openssl req -new -x509 -days 3650 -nodes -out /etc/stunnel/stunnel.pem -keyout /etc/stunnel/stunnel.pem

This certificate will be valid for 10 years after you issue it, which is insecure in the encryption world, but it is convenient. I recommend that you use a shorter timeframe if you are worried about this being compromised.

Next, you must determine which IP address OpenVPN is listening on. This is usually 0.0.0.0, but you can verify by running:

netstat -nlp|grep openvpn

After that, you must create a config file at /etc/stunnel/stunnel.conf, containing the following text (replacing 0.0.0.0 if necessary):

cert = /etc/stunnel/stunnel.pem
pid = /var/run/stunnel.pid
output = /var/log/stunnel
[openvpn]
accept=443
connect=0.0.0.0:1194

This will have stunnel listen on port 443 for SSL traffic, which it will decrypt with the certificate and direct to openvpn on port 1194.

Next,we simply have to make stunnel run on config. Stunnel doesn’t have an included init script, so we will add a line to crontab. To do so, simply enter the comand:

crontab -e

Then, add the following line into the crontab:

@reboot stunnel /etc/stunnel/stunnel.conf

Set up the stunnel client

Setting up the stunnel client was difficult for me, since it isn’t very clear on Windows. But the following is the steps that I followed, it will differ on Linux and Mac.

  1. Open Start->Stunnel->Edit stunnel.conf
  2. Add the following (where serverip is the remote server IP):
    [openvpn]
    client = yes
    accept = 127.0.0.1:443
    connect = serverip:443
  3. Adjust my OpenVPN config at C:/Program Files/OpenVPN/config/client.ovpn to change the server IP address to 127.0.0.1:443

Now, if you followed my somewhat incoherent instructions, you should have a fully encrypted and obfuscated VPN running on port 443. I hope you have had success with this tutorial, but I know that some of it may not be applicable to your specific Operating System. If this is the case, it may be necessary to consult the user guides of the applicable software. One possible pitfall would be that it may raise suspicion if all of your traffic is being tunnelled through one IP and port, so bear that in mind when using this method.

Further Development

I have a lot of aspirations to changes to this configuration, so I will list them below:

  • Use a port multiplexer to be able to handle both normal HTTPS traffic and VPN traffic on port 443. This is difficult, because stunnel needs to be ran before the multiplexer (such as SSLH) can process the packets.
  • Implement client-side authentication, in order to ensure the connecting client is authorised to use this service. This will reduce the chance of somebody just randomly attempting to stunnel VPN traffic through the server, which would reveal that it is indeed a VPN server.

I hope you enjoyed this article. If so, I implore you to subscribe to the Hive mailing list, where you can keep up to date with articles like these direct from the blog.

 

Adam Galloway
Adam Galloway
Programmer and Project Supervisor. Lover of tea and witticisms, the typical British stereotype. Adores cryptography, privacy and human rights.

Comments are closed.