How to bypass a firewall using a VPS on AWS
Tags: vpn, linux, cloud, openvpn
Published: 2020-09-20 07:00:30

When you browse at school or work you probably have experienced some problems browsing in certain websites or using certain applications. Is a common practice to block some kind of pages on internet at work or school environment also they block another kind of traffic such as torrents, adult-content or they just permit web traffic, you school or work don't want you to browse sites they haven't approved.

# Types of firewall blocking

There are certain levels of firewall blocking, the most simple is based on blocking certain kind of web-pages. The other type of firewall blocking is based on protocols, they just allow certain kind of traffic such as web traffic, ssh, dns, etc. Almost every school or work place have both kind of firewall blocking, but there is more sophisticated blocking levels, in this article we only focus on this type of firewall blocking.

# Who wants to bypass a firewall?

There are some many types of users who wants to bypass a firewall for different reasons, this reasons could be:

- Wants to browse in certain kind of web pages
- Wants to use specific application that are blocked such a torrent
- Needs to access a school or work environment behind a firewall

There are different methods to bypass a firewall according to their usage. For the first kind of user who only wants to browse in blocked websites, the method could be a VPN or proxy. For the second kind of user who wants to use specific non web application, the method could be a VPN. The last kind of user wants to expose some service running behind firewall such a ssh server running at school or workplace, the method for this user could be ssh port forwarding or VPN with port forwarding on server-side.

# Disclaimer
**This tutorial was made for informational and educational purposes only. I cannot be held responsible for any misuse of the given information. If you plan to use the information for illegal purposes, please leave this tutorial now.**

# Before begin
In this tutorial we are gonna setup a VPN server, Proxy server and SSH server to bypass a firewall, normally some services are't blocked by the firewall such http, https, ssh and DNS it means that we can setup any service on these ports for example:
- Squid proxy on port 80/tcp
- SSH server on port 22/tcp
- OpenVPN on port 443/tcp
- Wireguard VPN on port 53/udp

Each of these services have advantages and disadvantages and serves a specific purpose for example you can use ssh tunnel as sock proxy, forward ports through ssh tunnel using ssh port forwarding this is useful but in some application and mobile devices this method is not enough. Using a proxy y very useful if you only want to browse in blocked web pages. A vpn is the best solution to navigate without restrictions, it works on desktop and mobile devices, you can forward traffic from internet to client or make available a private subnet connecting client to client through VPS server using a gateway device such raspberry pi. In this tutorial I setup 2 vpns, wireguard and openvpn, in my personal opinion wireguard is better than openvpn but wireguard does't work with tcp protocol, that's why i set wireguard at 53/udp and openvpn at 443/tcp one advantage of openvpn is his protocol that utilizes SSL/TLS for key exchange so in a packet analysis will appears like https traffic.

# Configure VPS on AWS

For all services we need a virtual private server (VPS), this vps could be setup on any public cloud provider, in my case i chose aws because they offer one year of free trial on aws EC2.

The first step is create an account in aws, create a VPS, configure a key pair and security group. I choose ubuntu 20.04 with the following configuration. 

![aws-ec2](https://dev-to-uploads.s3.amazonaws.com/i/byyh62byl7n7ts4k56wn.png)

In order to avoid a change os ip when the VPS restart i recommend to associate a static ip address, this can be set in *elastic ip* option as shown in the following image

![elastic-ip](https://dev-to-uploads.s3.amazonaws.com/i/6eozhvhb411be9ukrf7y.png)

## Access to VPS

We need to download the key pair created steps earlier and move to `~/.ssh` directory
```sh
$ mv ~/Downloads/aws.pem ~/.ssh/
``` 
Change file permissions to be only readable for user owner
```sh
$ chmod 400 ~/.ssh/aws.pem
``` 
Access to remote VPS
```sh
$ ssh -i ~/.ssh/aws.pem ubuntu@<public_ip_address>
```
Update the system
```sh
$ apt-get update && apt-get upgrade -y
```

## Install needed packages
```sh
$ apt-get install wireguard squid fail2ban qrencode apache2-utils -y
```

## Configure fail2ban
fail2ban is a tool that helps to prevent automated brute force attacks in services exposed to internet.

Add sshd jail in `/etc/fail2ban/jail.d/sshd-jail.conf`
```
[sshd]
enabled   = true
maxretry  = 3
findtime  = 1d
bantime   = 4w
ignoreip  = 127.0.0.1/8
```
Reload fail2ban service
```sh
$ systemctl restart fail2ban
```
Check sshd jail
```sh
$ fail2ban-client status sshd
```

## Configure SSH server
In order to setup a ssh port forwarding we need to configure some options in `/etc/ssh/sshd_config` to allow TCP Forwarding and Gateway Ports
```
AllowTcpForwarding yes
GatewayPorts yes
```
Reload the ssh server
```sh
$ systemctl restart sshd
```
Now you can setup port forwarding through ssh tunnels, check [this](https://link.medium.com/NBkzEmAf29) tutorial to create a systemd service with ssh tunnel.

## Configure squid proxy on 80/tcp

Squid is a http proxy, it can be configured on port 80 to bypass firewall.
Configure squid proxy to listen in port 80 and basic user authentication.

Create user and password 
```sh 
$ htpasswd -c /etc/squid/passwd client1
```

Generate config file, first create a backup of original file
```sh
$ mv /etc/squid/squid.conf /etc/squid/squid.conf.bk
```

Generate squid config file in `/etc/squid/squid.conf`
```sh
$ cat <<EOF > /etc/squid/squid.conf
acl localnet src 0.0.0.1-0.255.255.255  # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8             # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10          # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16         # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12          # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16         # RFC 1918 local private network (LAN)
acl localnet src fc00::/7               # RFC 4193 local private network range
acl localnet src fe80::/10              # RFC 4291 link-local (directly plugged) machines

acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT

auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwd
auth_param basic children 5
auth_param basic realm Squid Basic Authentication
auth_param basic credentialsttl 2 hours
acl auth_users proxy_auth REQUIRED
http_access allow auth_users

http_access deny !Safe_ports

http_access deny CONNECT !SSL_ports

http_access allow localhost manager
http_access deny manager

include /etc/squid/conf.d/*

http_access allow localhost

http_access deny all

http_port 80

coredump_dir /var/spool/squid

refresh_pattern ^ftp:           1440    20%     10080
refresh_pattern ^gopher:        1440    0%      1440
refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
refresh_pattern \/(Packages|Sources)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims
refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims
refresh_pattern \/InRelease$ 0 0% 0 refresh-ims
refresh_pattern \/(Translation-.*)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims
refresh_pattern .               0       20%     4320
EOF
```

Restart squid service
```sh
$ systemctl restart squid
```
Now you can configure a proxy in your browser, system or phone.

## Configure Wireguard at 53/udp

Wireguard is modern VPN protocol that works on kernel-side, unfortunately only works on **UDP** ports and most of firewalls blocks outgoing udp connections except in some services such a DNS on 53/UDP so we'll configure wireguard to listen in 53/UDP.

First of all, we need to enable ip forwarding
```sh
$ sysctl -w net.ipv4.ip_forward=1
```

Make changes permanent uncomment this line `net.ipv4.ip_forward=1` in `/etc/syctl.conf`
```sh
$ sed -i '/net.ipv4.ip_forward/s/^#//g' /etc/sysctl.conf
```

Most of systemd based distros uses ***systemd-resolve*** to resolve dns queries, this is a problem if we want to setup wireguard to listen on 53/udp, so we need to disable systemd-resolve, first of all check what process is listen on port 53/UDP.
```sh
$ ss -ulpn4
```
As we can see in the following image, the process who listen on port 53/UDP is *systemd-resolve*
![systemd-resolve](https://dev-to-uploads.s3.amazonaws.com/i/m3oxaz9s56i0rkvd6o0g.png)

Disable systemd-resolve
```sh
$ systemctl disable --now systemd-resolved
```

Set static dns server adding this lines on `/etc/resolv.conf`
```
nameserver 1.1.1.1
nameserver 1.0.0.1
```

Now you can check again who is using port 53/udp with this command
```sh
$ ss -ulpn4
```
A this point we need to generate a config file for wireguard server.
Before create a config file check what is you default interface in my case is eth0, modify wireguard config file according to your interface name
```sh
$ ip -o -4 route show to default | cut -d ' ' -f 5
``` 

Create wireguard config file at `/etc/wireguard/wgserver.conf`
```
[Interface]
Address = 10.20.0.1/24
ListenPort = 53
PrivateKey = <your_private_key>
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
SaveConfig = true
```

Generate wireguard private key and put in `/etc/wireguard/wgserver.conf`
```sh
$ sed -i "s/<your_private_key>/$(wg genkey)/" /etc/wireguard/wgserver.conf
```

Enable wireguard server
```sh
$ sudo systemctl enable --now wg-quick@wgserver
```

Generate client template at `~/wgclients/template.conf`
```
[Interface]
PrivateKey = <private_key>
Address = 10.20.0.xxx/32

[Peer]
PublicKey = <server_public_key>
Endpoint = <public_ip_address>:53
AllowedIPs = 0.0.0.0/0, ::/0
```

Get server public key, replace this in `<server_public_key>` in `~/wgclients/template.conf` file
```sh
$ wg show wgserver | awk '/public key:/{print $3}'
```
Set server public ip address in `~/wgclients/template.conf`
```sh
$ sed -i "s/<public_ip_address>/$(curl -s ifconfig.me/ip)/" ~/wgclients/template.conf
```

Generate client and copy template
```sh
$ mkdir -p ~/wgcliets/client1
$ cp ~/wgclients/template.conf ~/wgcliets/client1/client1.conf
``` 

Generate client keys
```sh
$ cd ~/wgclients/client1
$ wg genkey | tee private-key | wg pubkey > public-key
```

Copy private key and paste in `~/wgclients/client1.conf` file and set ip address. Add client public key in `/etc/wireguard/wgserver.conf` and tunnel ip address
```
[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.20.0.10/32
```

Reload config on-the-fly
```sh
$ su -c "wg addconf wgserver <(wg-quick strip wgserver)"
```

To check wireguard connection, download wireguard android app in PlayStore. Generate QR code from client config file and import in wireguard app.
```sh
$ qrencode -t ansiutf8 < ~/wgclients/client1/client1.conf
```
Now you can check connection typing `ifconfig.me` at mobile web browser it will appears the server public ip address

## Configure OpenVPN at 443/tcp

OpenvPN is a vpn that uses a custom security protocol that utilizes SSL/TLS for key exchange so it could be set in HTTPS port since every web site uses SSL/TSL the firewall cannot block that port.

Install OpenVPN with automated script
```sh
$ git clone https://github.com/Nyr/openvpn-install.git
$ cd openvpn-install
$ bash openvpn-install.sh
```

Configure using the following parameters:
- Use IPV4 address in eth0 in my case 172.31.14.144
- Put public ipv4 address
- Protocol: TCP
- Port: 443
- DNS: 1.1.1.1

Configurations is showed in the following image

![openvpn](https://dev-to-uploads.s3.amazonaws.com/i/vqlhyth12l7rew3cdqd2.png)

The client config file will be placed on `/root` directory, copy to home
```sh
$ mkdir ~/ovpnclients
$ mv /root/client1.ovpn /home/ubuntu/ovpnclients/
$ chown ubuntu:ubuntu ~/ovpnclients/client1.ovpn
```
Download config file to your pc and transfer to android app
```sh
$ scp -i ~/.ssh/aws.pem ubuntu@<public_ip_address>:~/ovpnclients/client1.ovpn ~/ovpnclients
```

Import file in android app and connect, type `ifconfig.me` it will appears the server public ip address.

# Conclusion
These methods will work in almost all scenarios, please use them at your own risk because these methods can open a security breach in your work environment.