Sunday, 30 April 2017


I did a previous article in 2015 about this very subject, and explained how to build your VPN server on a Virtual Private Server (VPS). It was based on OpenBSD 5.6 and Vultr VPS provider. Since then, VPN has remained a hot subject of interest for a lot of people, especially after learning about all of the spying around (NSA's leaks, Wikileaks, etc...). Around me I have seen more people starting to use a VPN, and I received some questions since my last article. The main need remains the same however: if you neither trust your ISP nor a dedicated VPN provider (log or security wise), your best option is to be your own VPN provider.

This new article to build your own VPN server is an upgrade of the previous one. At a glance, the upgrades are:
- Full Disk Encryption (FDE)
- OpenBSD 6.1 and new syspatch utility
- Comparison of OpenVPN and IPSEC
- Stricter firewall rules marking all inbound traffic to be blacklisted
- Scheduled Python script (instead of bash) to blacklist the intruders
- Separate CA/signing machine (optional)
- Multiple DNSCrypt proxy instances for failover
- OpenVPN: Certificate Revocation List/CRL (optional)
- OpenVPN: TLS 1.2 only
- OpenVPN: TLS cipher based on AES-256-GCM only
- OpenVPN: HMAC-SHA512 instead of HMAC-SHA1
- OpenVPN: TLS encryption of control channel (makes it harder to identify OpenVPN traffic)

The others OpenVPN's encryption parameters are identical: Diffie Helman 4096 bits, server's private RSA key of 4096 bits, TLS key of 2048 bits for HMAC, AES-256-CBC used for encrypting the traffic, and Perfect Forward Secrecy (PFS).

The steps described in this article have been made on a VPS from Vultr provider, with which I have no affiliation of any kind, I merely use it because it fits my needs: possibility to boot a custom ISO of any OS, console access, Two Factor Authentication with Yubikey, snapshots, and an affordable starting plan of 2.5$/month (512Mo RAM, 1 CPU, 20GB SSD, and 500GB of traffic). You are free to follow this guide and installation steps on any VPS provider of course! :-)

In what follows, I expect that you were able to boot on an OpenBSD 6.1 amd64 ISO, ready to install the OS. Also, as I did it on Vultr on a SSD VPS, drive letters will be specific to it. If you install your server on a mechanical HDD, instead of /dev/sd0a you will have /dev/wd0a, and instead of a RAID /dev/sd1 you will have /dev/sd0. Therefore you must adapt the commands from this article to your particular environement.


I have been asked which was better, the most secure, which one should we choose to make our VPN server. I do not intend to start a war as to which is best, and to make the suspens short, both are good. Both can be used to encrypt traffic with AES-256, they both can use certificates as well, and can work for remote "road warrior" nomade users, or mobile phones. Both use HMAC authentication for incomming packets, allowing them to drop "valid" IPSEC/OpenVPN packet which are however not signed. Both can be weaken by choosing weak encryption algorithm and/or weak passwords/keys. Fact is, I'm using both for professional use, it all depends on the context.

That being said, we can still find differences between both, which may help you choose.

IPSEC: has two easily identifiables UDP ports, 500 by default, and 4500 for NAT Traversal (NAT-T), and uses AH/ESP protocols. This means it can potentially be blocked voluntarily or unvoluntarily by an ISP or by a WIFI or hotel network. Also, my personal experience with IPSEC is that it is "sensitive" and can have packet loss when SA rekey timeout is reached, or when there is packet fragmentation. It can be difficult to diagnose when unexpected issues appear, such as packets not coming back despite VPN tunnel still being up, no timeout is reached, and no error messages from iked. On the other hand, OpenIKED on OpenBSD has native commands to create a CA and certificates, which is very handy. It enables us to choose from a wide selection of authentication and encryption algorithm, and the iked.conf syntax is rather easy. I find it generaly more suited for site to site VPN. Obviously IPSEC can be made perfectly stable and secure, however in my experience it requires more troubleshooting when something goes wrong.

OpenVPN: CA and certificates management require an external tool, either OpenSSL or a package such as Easy-RSA. About ports, a single one needs to be used, and we are free to choose the one we want, as well as the TCP or UDP protocol. OpenVPN is a SSL VPN and does not use a separate VPN protocol. This point allows you to circumvent potential network restrictions, as at worst you will always have at least ports 80, 443, and 53 available. OpenVPN has no problem with NAT and firewalls, and works flawlesly. In my experience, I found OpenVPN perfectly stable after 2 years of usage.

To be honest, when I started my new VPN server to make this article, I wanted to do it with IPSEC as iked was native to OpenBSD. I did manage to have a functional tunnel, however it never was stable no matter what I tried. It is very likely a configuration error on my side, but still it was pretty frustrating. When I finally went back to OpenVPN, I had it working at first try with a perfect stability. I personaly prefer OpenVPN, and it can also be configured to be pretty secure as well.

In my previous article, I did set up a scenario where everything was in your hands: the server, the encryption algorithm, the keys and certificates, the firewall rules. It was pretty secure, in part because of running on OpenBSD which enables a lot of security features by default. However, as some people mentioned it to me, if the VPS provider is either malicious, or hacked, or for any reason has to give access to your server or give a copy of it, all of your security falls flat. Indeed, your certificates, keys, and may be even the Certificate Authority, are all stored on the server, which is not encrypted. There is therefore in this scenario a required trust toward the VPS provider.

By doing a Full Disk Encryption (FDE), you are further hardening your VPN server from unauthorized access. Fortunately, FDE is natively supported on OpenBSD. From the official FAQ, OpenBSD uses AES in XTS mode. It is not specified if it is AES-128 or AES-256 though at this link. However I found a detailed analysis of OpenBSD encryption source code, and it clearly shows that AES-256 XTS is used.

Please note however that while it is an improvement to setup a FDE, and an absolute security requirement in my opinion nowadays, it is still not 100% secure as the VPS provider can do a snapshot of the running system and extract information from memory.


When you first boot onto the ISO to install OpenBSD, you end up on this screen:

We need to create an encrypted volume before proceeding with the installation. For that, we must escape to a Shell first (last option). The OpenBSD FAQ linked above advises to write random data first to the whole drive. Indeed, if we do not, it may be possible for an adversary to tell the difference between used and unused space. It costs nothing to do it, except some patience, and if we encrypt the whole drive it's better to do it right. As a reminder, drive paths from now on are based on a SSD of Vultr VPS, if you use a classical HDD, you will have to adjust the commands.
# dd if=/dev/random of=/dev/rsd0c bs=1m

This command reads data from /dev/random and writes it to the whole /dev/rds0c device. It takes 5 minutes on my server's 20GB SSD, but it can take a lot more time on bigger drives, especially on HDD. Now we need to initialise the disk and create label for it:
# fdisk -iy sd0
# disklabel -E sd0

Here, choose to create a partition using the entire disk, this way is easier. Notice we choose a "RAID" filesystem here, as it is what will allow us to enable encryption afterwards:
> a a
offset: [64]
size: [41929586] *
FS type: [4.2BSD] RAID
> w
> q
No label changes.

Now we will create an encrypted volume. By default, from the bioctl man page, there is 16 rounds of the KDF algorithm used when converting your passphrase into key. This is a defense against bruteforce, as it requires, for every passphrase to try, to make 16 rounds of it. It increases required CPU power, and will increase the time necessary to crack the passphrase. However, 16 rounds, althought conservative and being able to run on even less powerful systems, is not that much against someone having great CPU power to attack your passphrase. On a decent and recent system with fast SSD, upping it to 8192 rounds is transparent with no noticable delay after having typed the passphrase to boot the server (on my VPS server). However if I test it on a local VM on my computer, boot is delayed by 55 seconds, so it really depends on your hardware.

Choose here a strong passphrase! Having a high number of rounds with a weak passphrase is useless. If in the future you want to modify your passphrase, from a user shell you will have to type this command:
$ doas bioctl -P sd1

Before coming back to the setup, as we created a new sd1 device, we have to make sure the nodes are created for it:
# cd /dev
# sh MAKEDEV sd1

Last step, also from the official FAQ, is to zeroing the first chunk of the new device, where should normally be a Master Boot Record and disklabel instead of some garbage:
# dd if=/dev/zero of=/dev/rsd1c bs=1m count=1
# exit

Now you come back to the setup prompt, with an sd0 device filled with an sd1 encrypted volume. You just need to answer the questions, essentially:
Initial prompt : I (Install)
Keyboard layout: fr (for instance)
Hostname : MY-SERVER
Network : keep defaults and dhcp
Root password : choose a strong password, different than the boot passphrase
Start sshd : yes
Run X Window : no
Setup a user : no
Allow root ssh login : no
Timezone : choose your own (e.g Europe/Paris)

We do not create another user for now, and we deny root from connecting to SSH. This implies that for the begining of the setup which follows, you have to have an access to the server's console, that Vultr for instance provides.

Be carefull when the disk to install to is asked for, remember to change the default from the unencrypted device to the encrypted volume:
Which disk is the root disk? ('?' for details) [sd0] sd1

Then, for the following questions:
Use Whole disk : whole
Use Auto layout : a
Location of sets : http
Package selection : -g* [enter]
Package selection : done
Location of sets : done
# reboot


When you want to upgrade an existing system, always first read the official upgrade guide pertaining to your upgrade (here from 6.0 to 6.1). For instance, before upgrading from OpenBSD 6.0 to 6.1, some cleanup have to be made first, before booting onto the new version ISO.

If you already have an encrypted server, or if you want to know how you will update it when the next OpenBSD will be released, the install steps are different. The obvious way seems to boot onto the ISO, at the setup prompt drop to a shell, mount the encrypted volume, and continue with the setup. That is in fact correct, but the bioctl manpage, althought having a parameter to "detach" a volume, does not mention how to "attach" or "mount" an existing one. The parameter to use, althought not explicitely written in the manpage, is the "-c" parameter we used to "create" our volume. If the volume already exists, bioctl will just mount it, not overwrite it:
Once the volume is attached as sd1, as before we need to create nodes for it:
# cd /dev
# sh MAKEDEV sd1

Then quit shell with CTRL+D, and at the setup prompt select "(U)pgrade". Once done and your upgraded server is rebooted, follow the post-upgrade steps given at the official upgrade guide.

OpenBSD default settings are very secure, and no services are listening on the outside except SSH. However SSH is listening on the default 22 port, accepting password authentication. Before configuring our server, it is best to block any inbound access except from our computer public IP, and then take our time to lock down SSH. Let's start by a basic pf ruleset:
# vi /etc/pf.conf
block in quick from ! x.x.x.x # your public IP address
pass out quick

Replace "x.x.x.x" by your computer public IP address you are connecting from. You can check on if you don't know it. Of course this ruleset is temporary. Now apply it:
# pfctl -f /etc/pf.conf

Now we will create a regular user, that we will use afterwards. I'm creating a user named "guillaume" just for the example, but pick the one you want:
# adduser

First time this command is ran, some general questions are asked, keep the defaults. Then when a username is asked to create a user, enter yours, and keep the defaults for all other questions regarding your user. When that is done, we want to be able to run commands as root, in same way we used "sudo" in previous OpenBSD versions. Since 5.8, we have to use "doas" instead, which has an easier configuration syntax:
# vi /etc/doas.conf
permit persist guillaume as root

The "persist" option makes doas command request the password the first time, and then not asking it again for a period of time. If you do not use this option, a password is requested everytime doas command is used (which will makes you crazy while configuring a server!). Now, logout from root, and try your fresh new user and enjoy the doas command from now on :-) Of course this configuration is only temporary, afterwards you should restrict the commands your user is allowed to do. You can check the doas.conf manpage for more information.

We now have few things to do: create an SSH key, disable root login and password base authentication, and make SSH listening on another port as a bonus (to avoid automated scans adding "noise" to our logs). For Linux/BSD clients you can create a key with -t ed25519, but for Windows your SSH client may only be compatible with keys created using -t rsa. In the following I will suppose you have a Windows client.
$ cd /home/guillaume
$ ssh-keygen -t rsa

Then copy your public key to ~/.ssh/authorized_keys :
$ cd .ssh
$ cp authorized_keys

Copy the content of your private key "~/.ssh/id_rsa" (not on the remote computer you will use to connect to your router, and set strict permissions on it. If on Linux or BSD, do a "chmod 600", and you will be able to connect later with "ssh -i your_private_key your_server_ip". On Windows, I advise you to run a recent client such as Royal TS to SSH into your server. This software is free under 10 connections, but a licence is needed if you have more. A regular Putty could do the trick, but last time I tried it would not connect (with the regular ppk file converted with puttygen), and RoyalTS has some additional interesting features such as encrypting the database, multi-tab window, custom macro, and the absolutely vital possibility to select custom icons :-)

Now modify your SSH server with this temporary configuration, the TCP port 21598 being an example, choose the port you want. You can choose a higher port to avoid scans, or choose a port such as 443 to be able to connect to your server from everywhere, when outbound TCP port 22 could be blocked:
$ doas vi /etc/ssh/sshd_config
# Modify default listening port
Port 21598

# Authentication
PasswordAuthentication yes # temporary
PermitRootLogin no
AllowUsers YOUR_USER
AuthorizedKeysFile .ssh/authorized_keys
AllowTcpForwarding no
UsePrivilegeSeparation sandbox # Default for new installations.
Subsystem sftp /usr/libexec/sftp-server

Restart sshd :
$ doas rcctl restart sshd

Now you can connect by SSH with your user and its password, and then retrieve your id_rsa private key file. You will then need to convert it to a ".ppk" file to be able to use it to connect from Windows. One easy way to do it is to use puttygen. Just run this utility, open your id_rsa file from it, and convert it into id_rsa.ppk.

Connect from your remote computer with the private key, check that connecting with your regular user and with the SSH key fully works. Once it's working, modify the following line in /etc/ssh/sshd_config :
PasswordAuthentication no

Restart sshd :
$ doas rcctl restart sshd

On the client side, if you are using a Linux/BSD client, you can enable SSH key fingerprint visual display in /etc/ssh/ssh_config which displays your SSH key in hex format and an ACSCII graphic everytime you connect. Once you get used to the ASCII graphic of your server, you should notice if all of a sudden it is completely different (probably a man-in-the-middle):
$ doas vi /etc/ssh/ssh_config
# Display fingerprint in hex and ASCII graphic when connecting
VisualHostKey yes

You now have a SSH listening on a non default port, root denied from connecting in, password authentication disabled, and authencation based on SSH keys and passphrase. For further SSH hardening, read the following excellent article describing which protocols and ciphers to use for optimum security. I may in the future update the SSH settings given in this article to follow some of the advices from this page.

Finally, to update the system and packages easily, I really liked to use "openup" from M:Tier. However, starting with OpenBSD 6.1, a new "syspatch" command appears to easily update the base system. It won't take care of the additinal packages however, which have to be taken care of with the ports tree if you want to rely only on OpenBSD official commands and repositories. You can learn more details at the patches FAQ. "pkg_add -u" only upgrades packages if you are running the -current flavor, not the -release flavor we are running in our example. If you want the easiest way you can use openup from M:Tier, which is a third party not related to OpenBSD project, so you have to decide if you wish to trust their repository or not. If you want to use "openup":
$ ftp
$ chmod +x openup
$ doas openup
===> Checking for openup update
===> Installing/updating binpatch(es)
===> Updating package(s)

If however you want to use syspatch instead as I do, start it this way, and then update the external packages using the ports tree:
$ doas syspatch

To fetch the ports tree, if you don't use openup, you can follow the steps outlined in the patches FAQ link given above. Basically fetch the ports tree with CVS, run the "out-of-date" script to know which package needs an update, and run a "make update" in the affected port directories. I'll try to detail these steps later.

Here we go, a fully updated system. If you use the syspatch option "-c" it will list available updates. You can read syspatch manpage for more information. Let's continue to the next part.

Before going further, as "vi" is not my favorite text editor, let's install "nano" instead:
$ doas pkg_add nano

A few tweaks we can make before configuring further our server. As Vultr VPS are hosted on SSD, it is a good idea to add in the fstab file the mount options "softdep" and "noatime". The first one increase disk performance, while the second will prevent the "last access time" file properties to be written:
$ sed 's/rw/rw,softdep,noatime/g' /etc/fstab > ./fstab_tmp
$ doas mv fstab_tmp /etc/fstab
$ cat /etc/fstab

Now, remember we are running on a fully encrypted volume. However OpenBSD also encrypt the swap by default, therefore you can disable it as it is not necessary in our context:
$ doas nano /etc/sysctl.conf
# Disable swap encryption (whole disk is already encrypted)

Your server has booted with DHCP and has acquired its network configuration from your VPS provider. As the server IP address is fixed, I prefer setting manually the network configuration to avoid relying on another server (VPS provider's DHCP and DNS) I do not control. Modify the following files according to your server public ip address, mask, and gateway:
$ doas nano /etc/hostname.vio0
inet server_public_ip server_netmask

Add the gateway :
$ doas nano /etc/mygate

Our server will forward traffic between its VPN interface and its default network interface. We have to enable forwarding:
$ doas sysctl net.inet.ip.forwarding=1
$ doas nano /etc/sysctl.conf
# Enable forwarding

At this point you still rely on your provider DNS server in /etc/resolv.conf, we will take care of that later.

The pf ruleset below does many things:
- denies all inbound, except SSH and OpenVPN on non default ports
- protects SSH from SYN flood, and bruteforce
- detects accesses to all other ports and blacklist the miscreants for 24H (you cannot expect less from a Blowfish mascot!)
- allows VPN clients to make DNS requests to unbound on localhost (which uses dnscrypt, as it will be setup in the next part)
- does not log blocked network traffic from the provider's DHCP

You should modify this ruleset according to your chosen SSH and VPN listening ports (we will setup OpenVPN later, but you can choose a random port now). The scan detection and blacklisting concept can theoretically backfire, if someone sends spoofed packets with trusted IPs. However, as it is implemented, only incoming traffic will match the blacklist table. Therefore, if a spoofed packet is sent with a website IP you trust, it will not prevent you to access that website at all as your traffic will be outbound. Also, as we will write a script to parse pf logs and add IPs into the blacklist, we will add an exception for our own trusted client computer public IP address to avoid being locked out. As a last resort the remote console access from the VPS provider could allow us to login, if we were totally locked out for any reason. This adaptative behavior is not mandatory for your VPN server to be operational, but it is useful to block automatic scans on the Internet from querying your SSH and VPN ports once they hit your server on another port.

$ doas cp /etc/pf.conf /etc/pf.allow.conf
$ doas nano /etc/pf.conf
# Title: "Being your own VPN provider with OpenBSD v2"
# Author: Guillaume Kaddouch:
# Date: ruleset last modified: 2017 April 17 for OpenBSD 6.1
# Github:

# ---------------------------------------------------------------------------------------
ssh_port="21598" # just a random example, modify to match your chosen SSH port
vpn_port="21599" # just a random example, modify to match your chosen OpenVPN port

bad_ports="{ 1:66, 69:21597, 21600:65535 }" # adjust according to your SSH and VPN ports (+ DHCP)

table <internet> const { $all_networks, !self, !$private_networks }
table <myself> const { self }
table <bruteforce> persist
table <badguys> persist

# ---------------------------------------------------------------------------------------
set block-policy drop
set loginterface egress
set skip on lo
block log all
match in all scrub (no-df max-mss 1440 random-id)
block in log quick from <bruteforce> label "bruteforce"
block in log quick from <badguys> label "old_guys"

# --------------------------------------------------------------------------------
match in on egress proto tcp from <internet> to port $ssh_port
match in on egress proto { udp tcp } from <internet> to port $bad_ports
match in on egress proto udp to port $vpn_port
match in on $vpn proto { icmp udp tcp }
match in on $vpn proto { udp tcp } to $vpn_ip port domain
match out on egress tagged VPN_TUN_IN
match out on egress proto tcp from <myself> to port { http https }
match out on egress proto { udp tcp } from <myself> to port domain
match out on egress proto udp from <myself> to port https
match out on egress proto udp from <myself> to port ntp
match in on egress from { no-route urpf-failed } to any
match out on egress from any to no-route
match inet6 all
   tag SSH_IN
   tag BAD_GUYS
   tag VPN_TUN_IN
   tag VPN_DNS_IN
   tag HTTP_OUT
   tag DNS_OUT
   tag DNS_OUT
   tag NTP_OUT
   tag IPV6

# ---------------------------------------------------------------------------------------
match in tagged VPN_EGRESS_IN set tos lowdelay set prio 6
match out tagged VPN_FORWARD nat-to (egress) set prio 6

# Blocking spoofed or malformed packets, IPv6, and some bad traffic
antispoof log quick for egress label "antispoof"
block quick log tagged BAD_PACKET label "noroute_urpf"
block quick log tagged IPV6 label "ipv6"
block quick log tagged BAD_GUYS label "new_guy"

# Standard rules
# protect SSH from SYN flood and bruteforce
pass in quick tagged SSH_IN synproxy state \
(max-src-conn 10, max-src-conn-rate 5/5, overload <bruteforce> flush global)

# Redirect VPN clients DNS requests to unbound
pass in quick inet tagged VPN_DNS_IN rdr-to port domain

pass in quick tagged VPN_EGRESS_IN
pass in quick tagged VPN_TUN_IN

pass out quick tagged HTTP_OUT
pass out quick tagged DNS_OUT
pass out quick tagged VPN_FORWARD modulate state
pass out quick tagged NTP_OUT

# no log for
block in quick proto udp from port bootpc to port bootps
block in quick proto udp from any port bootps to port bootpc

If you prefer, you can now fetch this ruleset from this Github link.

Check the ruleset syntax, with the first command, and then apply it if no error returned:
$ doas pfctl -nf /etc/pf.conf
$ doas pfctl -f /etc/pf.conf

Now we have to make our script which will look for IPs blocked, because they dare approaching our server, labeled "new_guy". Script will be in /home/user/scripts:
$ doas pkg_add python3.5
$ cd ~
$ mkdir scripts
$ cd scripts
$ doas nano ./
If you do not see the embedded source code frame above (you are blocking scripts from, you can access with this direct link the script source code.

Edit the crontab to schedule execution of this script, as well as check every hour to expire table entries older than 24 hours. Be sure to make the script readable, executable, and writable only by root, as it will run in root's crontab. Replace "/home/your_user" below with your username:
$ doas chown root:wheel
$ doas chmod 700
$ doas crontab -e
# add badguys to the pf table to be blocked
*/5 * * * * python3.5 /home/guillaume/scripts/

# Clear pf tables
0 * * * * pfctl -t bruteforce -T expire 86400
0 * * * * pfctl -t badguys -T expire 86400

You can check with another script the state of your blacklist/badguys table, ports blocked to them once blacklisted , and number of blocked IP in your bruteforce table. Here is the script example, you can freely modify:
$ doas nano ./
If you do not see the embedded source code frame above (you are blocking scripts from, you can access with this direct link the script source code.

Below is also an example of a possible output from the second script:
$ doas chown root:wheel
$ doas chmod 700
$ doas ./

You now have a nice adaptative firewall, however as warned above, be careful as it can backfire if trusted IPs are not excluded and become blacklisted. It is a working configuration I had no trouble with, in my context, but in your situation it may have to be modified to fit your case.

6. DNS
We will use DNSCrypt to make our DNS requests encrypted, and Unbound to have a local DNS cache. This will allow us to avoid using our VPS provider DNS servers, and will also be useful to your future VPN clients which will be able to use your VPN server as their DNS server too, if they wish too (e.g mobile phones). Both dnscrypt and unbound will listen on the localhost only, not to the outside. They will be reachable nonetheless later to your VPN clients trough the VPN tunnel, using a firewall redirection.

$ doas pkg_add dnscrypt-proxy
$ doas rcctl enable dnscrypt_proxy
$ doas rcctl set dnscrypt_proxy flags -a -l /dev/null -R

You can choose your dnscrypt enabled DNS server at the following list (choose a logless DNSSEC enabled one).

Now let's start it:
$ doas rcctl start dnscrypt_proxy

Before configuring Unbound, which is the local DNS cache which will make requests to dnscrypt_proxy, we can configure an additional dnscrypt instance, as explained in the pkg readme. Indeed, dnscrypt DNS servers being public ones, they often goes into maintenance, become offline or temporarily unreachable. To address this issue, it is possible to setup multiple dnscrypt instances. Below are the steps to follow to add one, but you can add more if you wish. Notice the different local port 41 and different DNS server:
$ doas ln -s dnscrypt_proxy /etc/rc.d/dnscrypt_proxy2
$ doas rcctl enable dnscrypt_proxy2
$ doas rcctl set dnscrypt_proxy2 flags -a -l /dev/null -R
$ doas rcctl start dnscrypt_proxy2
$ ps aux | grep dnscrypt

You should see now two dnscrypt processes running, listening on ports 40 and 41, and linked to a different remote DNS server. This setup will be reflected in Unbound configuration below.

We now configure and enable unbound, already included in the base system. Unbound will drop privileges to user _unbound and will be chrooted in /var/unbound by default. Also by default, only localhost is allowed and everything else is refused. This is why it is unnecessary to specify the username/directory/chroot options below, or to define a default access-control. We just add what we need:
$ doas nano /var/unbound/etc/unbound.conf
do-not-query-localhost: no
access-control: allow
hide-identity: yes
hide-version: yes
auto-trust-anchor-file: "/var/unbound/db/root.key"

name: "." # use for ALL queries
forward-addr: # dnscrypt-proxy
forward-addr: # dnscrypt-proxy failover

Do not forget to modify your /etc/resolv.conf:
$ doas nano /etc/resolv.conf
nameserver # unbound is listening there at port 53

To prevent dhclient from overwriting our nameserver in resolv.conf, add this line to dhclient.conf:
$ doas nano /etc/dhclient.conf
supersede domain-name-servers

Run Unbound, and enable it to launch at startup :
$ doas rcctl enable unbound
$ doas rcctl start unbound

Now that the outbound DNS requests are only made using dnscrypt on UDP port 443, we can comment/disable/remove the rule that allows outbound DNS requests on UDP/TCP 53:
$ doas nano /etc/pf.conf
#match out on egress proto { udp tcp } from <myself> to port domain tag DNS_OUT

$ doas pfctl -nf /etc/pf.conf
$ doas pfctl -f /etc/pf.conf

Test that your DNS chain is working:
$ host has address mail is handled by 6 mail is handled by 10

Unbound is listening on locahost port 53, and when contacted is forwarding to dnscrypt listening on locahost port 40, itself contacting an external dnscrypt enabled DNS server.

We need to create a Certificate Authority (CA) which will enable us to create certificates for our VPN server, our home router, and any other client we may have. A Certificate Authority will also be able to revoke certificates, which will prevent unused or lost ones to be accepted by our VPN server.

This CA, as you can see, has a critical role. A breach of the CA would means an attacker could steal certificates and private keys and spy on our communications, and could create certificates for himself. Therefore, I strongly advise you to create a dedicated CA server, that you can store and run on your local computer as a virtual machine for instance that you can start on demand. It is possible though to follow the steps below directly on your VPN server, but I do not recommend it.

Ideally, from a dedicated OpenBSD 6.1 CA host:
$ doas pkg_add easy-rsa
$ cd /usr/local/share/easy-rsa/
$ doas cp vars.example vars
$ doas nano vars
# 2048 - > 4096
set_var EASYRSA_KEY_SIZE 4096
# sha256 -> sha512
set_var EASYRSA_DIGEST "sha512"

Now it's time to create our new Public Key Infrastructure (PKI) and CA :
$ doas easyrsa init-pki
$ doas easyrsa build-ca

Choose your CA's passphrase wisely, preferably a strong one, it will be requested for every subsequent certificates you will want to create.

Then, from easy rsa readme, the recommanded steps to create certificates is to install easy-rsa on every requesting hosts, server and clients, generate a request with "./easyrsa init-pki" and "./easy-rsa gen-req", import it on the CA server, and sign them. Then transport the newly created certs to each hosts. However this is not always doable, for instance if the client is a mobile phone.

If you prefer to do it all at once on the CA signing server directly:
$ doas easyrsa build-server-full your-server-name nopass
$ doas easyrsa build-client-full your-home-router-name nopass

The "nopass" option creates certificates without password, to allow openvpn to start automatically with the certificate without additionally prompting for a password. Then, we will create a Certificate Revocation List (CRL). This is optional, but I highly recommend it, as it will enable you to revoke certificates in the future if you need it. Without it, if you loose a certificate (stolen phone) or if you want to blacklist a certificate for any reason, the only possibility will be to create a whole new PKI and CA, and recreate all certificates. Better be safe than sorry and create a CRL:
$ doas easyrsa gen-crl

This will create the file /usr/local/share/easy-rsa/pki/crl.pem

Now we have to build 4096 bits Diffie-Hellman parameters, be warned it can take a while!
$ doas easyrsa gen-dh
$ doas mv ./pki/dh.pem ./pki/dh4096.pem

You can additionally generate an OpenVPN Pre-Shared Key (PSK) that will have to be copied to all server and clients:
$ doas pkg_add openvpn
$ doas mkdir -p /usr/local/etc/openvpn/secret
$ cd /usr/local/etc/openvpn/secret
$ doas openvpn --genkey --secret ta.key

On server, we will need to copy :
- ca.crt : Root CA certificate [.../easy-rsa/pki/]
- crl.pem : Certificate Revocation List [.../easy-rsa/pki/] (optional)
- dh4096.pem : Diffie Hellman parameters [.../easy-rsa/pki/]
- server.crt : Server Certificate [.../easy-rsa/pki/issued/]
- server.key : Server Key (private) [.../easy-rsa/pki/private/]
- ta.key : OpenVPN TLS PSK [/usr/local/etc/openvpn/secret]

On clients, we will need to copy:
- ca.crt : Root CA certificate [.../easy-rsa/pki/]
- client.crt : Client Certificate [.../easy-rsa/pki/issued/]
- client.key : Client Key (private) [.../easy-rsa/pki/private/]
- ta.key : OpenVPN TLS PSK [/usr/local/etc/openvpn/secret]

This way, your CA private key stays on your signing host, if you choosed a separate host as advised.

To transfer the required files to the aformentioned hosts, server and clients, an encrypted channel must be used. If you have network access from your signing host to your server and clients, you can do it directly with SCP. Or if you prefer doing it from an intermediate Windows machine, you can use WinSCP to connect simultaneously to the signing machine, server, and client, and transfer the files this way.

8.1 - SERVER

Now that our server is up and running, and our CA and certificates are created, we can finally setup OpenVPN on our server. Let's download our packages and create the required directories:
$ doas pkg_add openvpn
$ doas mkdir -p /usr/local/etc/openvpn/{public,secret}

Do not forget to copy your certificates and keys, by changing directory to the folder you copied them to earlier:
$ cd folder_where_certs_and_keys_are
$ doas mv *.crt /usr/local/etc/openvpn/public/
$ doas mv *.key /usr/local/etc/openvpn/secret/

Making sure these secret files are only accessible to root:
$ doas chmod -Rf 600 /usr/local/etc/openvpn/secret/
$ doas chown -Rf root:wheel /usr/local/etc/openvpn/secret/

Let's create the main OpenVPN server configuration file:
$ doas nano /usr/local/etc/openvpn/server.conf
# Server configuration
# SSL/TLS certificate and keys, PFS enabled by default

# Since OpenVPN 2.4, "tls-crypt" can be used instead of "tls-auth", as it does authentication and
# encryption of all control channel packets. Purpose of encrypting these packets: provides more
# privacy, makes it harder to identify OpenVPN traffic, and masks the pre-shared key
# (if I understand the official OpenVPN 2.4 manpage)

# ** WARNING ** as of 28 May 2017, "OpenVPN Connect" v1.1.1 app on iOS/iPhone does not
# yet support "tls-crypt" option. Consequently, if you have mobile phone clients,
# you should use "tls-auth /your_path/ta.key 0" instead on the server.

ca "/usr/local/etc/openvpn/public/ca.crt"
crl-verify "public/crl.pem" # Certificate Revocation List (optional)
cert "/usr/local/etc/openvpn/public/server.crt"
dh "/usr/local/etc/openvpn/public/dh4096.pem" # Diffie Helman 4096 bits
key "/usr/local/etc/openvpn/secret/server.key" # RSA 4096 bits
tls-crypt "/usr/local/etc/openvpn/secret/ta.key" # TLS 2048 bits for HMAC and encryption

# Protocols and ciphers
cipher AES-256-CBC # AES 256 bits
tls-version-min 1.2 # Only allow TLS 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
auth SHA512 # HMAC-SHA512 (default is SHA1)

# Network parameters
port 21600 # as an example, pick your own port
proto udp
dev tun
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"

# push our DNS server to clients accepting it (will not override a home router DNS configuration
# with fixed DNS settings). Usefull for mobile phones for instance, where installing
# dnscrypt requires a rooted phone
push "dhcp-option DNS"

keepalive 10 120
comp-lzo yes

# Limits
max-clients 5 # change this value if you plan on connecting from more clients

# Privileges, chroot
chroot /var/openvpn
user _openvpn
group _openvpn

verb 4
mute 20

Now we should prepare the chroot environnement, as OpenVPN will chroot itself after being started. We must copy the CRL file in the chroot folder as it is checked after OpenVPN has chrooted its process, making the initial "/usr/local/etc/openvpn/" directory not accessible. That's also why the CRL path in the previous configuration file is not a full path, as the root folder changes after initilization:
$ doas mkdir -p /var/openvpn/{tmp, public}
$ doas cp public/crl.pem /var/openvpn/public

It is time to start our server and to make it start at boot time:
$ doas /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ doas nano /etc/rc.local
# OpenVPN
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon

You should check with tail -f /var/log/messages   that OpenVPN started successfully. If something went wrong, check your files and folders ownership and rights. Make also sure that both client and server time are close enough, to avoid any trouble with your certficates.

8.2 - CLIENT

In my OpenBSD router article there is a chapter about an OpenVPN client installation and configuration. Below I will just provide the OpenVPN configuration file to use on the client side:
$ doas nano /usr/local/etc/openvpn/client.conf
# Client configuration (router, computer)
# SSL/TLS certificate and keys
ca "/usr/local/etc/openvpn/ca.crt" # public
cert "/usr/local/etc/openvpn/myhome.crt" # public
key "/usr/local/etc/openvpn/myhome.key" # secret
tls-crypt "/usr/local/etc/openvpn/ta.key" # secret (OpenVPN 2.4 or higher)

# Protocols and ciphers
cipher AES-256-CBC # AES 256 bits
tls-version-min 1.2 # Only allow TLS 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
auth SHA512 # HMAC-SHA512 (default is SHA1)

remote-cert-tls server
dev tun
proto udp
resolv-retry infinite
comp-lzo yes

remote YOUR_SERVER_IP 21600

# Privileges, chroot
user _openvpn
group _openvpn
chroot /var/empty

verb 3
explicit-exit-notify 5

Client keys must be copied from the CA server to the client over a secure channel, for instance by using SCP/WinSCP to transfer them trough SSH, as advised earlier.


A smartphone such as Android or iOS can download and install "OpenVPN Connect". Then you will have to transfer on the phone an OpenVPN configuration file, which will require to have the whole configuration in it, including certificates and keys. The configuration file has the certificates and keys inside it. Basically you just copy/paste the content of the required files and insert them between tags like below (as of 28 May 2017, "OpenVPN Connect" v1.1.1 app on iOS/iPhone does not yet support "tls-crypt". We should use tls-auth on both client and server) :
# Protocols and ciphers
cipher AES-256-CBC # AES 256 bits
tls-version-min 1.2 # Only allow TLS 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
auth SHA512 # HMAC-SHA512 (default is SHA1)

# Global options
remote-cert-tls server
dev tun
proto udp
resolv-retry infinite
comp-lzo yes

remote YOUR_SERVER_IP 21600

key-direction 1

verb 3
explicit-exit-notify 5
# ca.crt below, just a random example. Full extract is above 35 lines

# myphone.crt below, just a random example. Full extract is above 35 lines
Version: 3 (0x2)
Serial Number: 4 (0x4)
Signature Algorithm: sha512WithRSAEncryption

# myphone.key below, just a random example. Full extract is above 35 lines

# ta.key below, just a random example. Full extract is above 20 lines
# 2048 bit OpenVPN static key
-----BEGIN OpenVPN Static key V1-----
-----END OpenVPN Static key V1-----

This configuration file, you can name "myserver.ovpn" for instance, must be transfered into the phone via a secure channel. As I'm using SpiderOak I used the Hive folder (which is a synchronized folder among many clients/devices) to retrieve the file. However, once you copied with SCP the phone keys and certificate on your computer, I guess a classical USB transfer will do the job as well :-)

Your VPN server is now finished!

We have seen how to build an OpenVPN server based on OpenBSD with Full Disk Encryption, to benefit from OpenBSD's memory protection, randomness implementation, LibreSSL, and secure by default philosophy. I find the VPS server to be a cost effective way to build our own VPN server, with many benefits such as snapshot before an upgrade, full access to boot the wanted ISO, remote console access, datacenter country location choice, and Two-Factor authentication with Yubikey. It is a way to be in full control of your computer, your home router, and your VPN server at the other end.

I used previously systrace which was removed starting from OpenBSD 6.0, because an application could circumvent it. Systrace was replaced by Pledge which is aimed at being more secure, but it works differently. Now with pledge, programmers have to include pledge API calls inside their code to be able to benefits from Pledge. Basically an application can request a mode allowing it to open files, or manage memory, but as soon as it will try for instance a network action not previously requested, the process will be killed. Theo de Raadt himself presented this new security feature at Hackfest 2015, you can find in the following links the slides and the video. A lot of base programs are already pledge protected: cat, chmod, mkdir, tar, gzip, ping, ftp, doas, nc, openssl, tcpdump, ntpd, httpd, smtpd, etc... From this 2015 slide, more than 400 programs were converted in 6 months. Apparently however, if I'm not mistaken, OpenVPN is not yet in the list unfortunately.

Also, in my previous article I talked about Security vs Anonymity, I won't include it here but you can jump to this link if you never read it.

In the end, there is still benefits of using an external VPN provider such as AirVPN. You may spend less money yearly depending on your required traffic volume, and spend less time as you do not have to maintain a server or upgrade it.

By using an external VPN provider you choose convenience, whereas by managing your own server you prioritize control and trust. Make your choice!


Monday, 18 January 2016

My OSCE Review

Offensive Security Certified Expert (OSCE) is a certification earned when one passes the exam after following the Cracking The Perimeter (CTP) course. It is more specialised than OSCP, and can be a natural continuation after OSCP. You can read my previous OSCP review to learn about my experience with it.

In this review, I will of course give my experience and opinion about the course and the exam, but will also first cover the path between OSCP and OSCE. Indeed once OSCP achieved, if you want to continue with OSCE, a lot of questions may arise: can I jump directly from one to the other? Should I learn or pratice particular topics? Is there a gap between OSCP and OSCE? How does PWK and CTP courses compare? etc... I wondered myself all of these questions, and I had to read all reviews and ask these very questions to OSCE's as well. Below I will thus cover my own experience for this particular topic, that many OSCP may wonder about.

First of all, there is a challenge one has to do to register for CTP course. You cannot simply register, pay, and start the course. This challenge is there to prevent people not having the sufficient knowledge from hurting themselves with a course and certification above their reach (with their current knowledge). This alone is a strong indicator that there is indeed a gap between OSCP and OSCE. However, for the story, I was still able to find the challenge solution right after OSCP, despite not having the required knowledge. It would have been anyway a wrong idea to register and do the CTP course directly, as I would not have been prepared at all.

After investigating about the required knowledge to know before hand, I then made myself a learning program to follow to get me to the necessary level. Have I not done that, I would have had a nightmare following the CTP course and would have miserably failed the exam. This is based on my personal knowledge level however, and it may not apply to an OSCP already a pentester, and used to find 0-days and develop exploits everyday for the breakfast. If however you got your OSCP but that you never done more than the stack overflow covered in PWK, and you are not particularily fluent in assembly, then the program I followed may be well suited to you as well.

The program described below is done to cover: shellcode, assembly, reversing, and exploit techniques such as stack overflow, SEH, and Egghunter. It is a minimal program which was enough for me as I praticed a lot, but other people like to add more topics such as fuzzing.

1) My first biggest advice is to take the intermediate SecurityTube Linux Assembly Expert (SLAE) certification which can be quickly made depending on time spent on it (3 weeks for me on holidays). It allowed me to learn assembly easily, to build shellcode, learn about polymorphism and encoders, and overall a good knowledge of basic x86 assembly. This is totally security oriented, not a general and boring assembly course. This was what helped me the most and I heartedly recommend it if you want to get the OSCE certification. CTP course per se does not require you to be an assembly expert, but the more you know it, the more you will be able to focus on exercices instead of fighting with assembly.

2) My second advice is after SLAE, to improve your stack overflow knowledge, and learn about SEH and Egghunter, by practising the following exploit developpement tutorial websites:
- : Windows Exploit Development Tutorial Series (less detailed)
- : Windows Exploit Development (more details)
- : Exploit Writing Tutorials (a lot of details!)

Do all of the exercices about stack overflow, SEH, Egghunter, and Win32 shellcoding. There is no need to learn other kind of exploits as they are not covered in CTP.

3) As a third step, you can go to and take random stack/SEH/Egghunter exploits and recreate them from scratch by yourself, without reading first and memorising the solution (you may find a different way than the original exploit). Optionally, you could try to find yourself unknown flaws on various softwares (0-days!). To my own surprise, I myself found 3 vulnerabilities, including one remote code execution (CVE-2015-7874) in KiTTY portable software. That was not obvious to me, at first I though it was not exploitable, but after some acrobatic movements I found a way. I used this opportunity as an exercice to practice more, to find my own way of thinking, and to get used to assembly and shellcode.

I did all of the above in 4 months. I could have taken more time if I did SLAE while I was working and not on holidays, or I could have made it shorter if I practiced less by doing less exercices. It is just a matter of being confortable with the aformentioned subjects. If in 2 months you feel absolutly ok, then that's fine. It is totally individual, and depends on you current experience and knowledge. This learning program I designed is just an example I built for myself, that may be useful if you had no idea what to work on.

Once you successfully passed the CTP registering challenge and have received your course material, some differences with PWK/OSCP jump out. Firstly, instead of a 350 pages course you have a 150 pages one. This means CTP covers less topics than PWK, but is more specialised (9 topics, more details on the course syllabus). As such, the required learning time is less than PWK, you can go over the course more quickly, but then you can use more time to exercice. CTP was clearly less intense than PWK was for me, also I was much better prepared and I could focus on the topics and enjoy the course. Secondly, in the course there is few gaps or missing parts, to prevent the student to blindly follow the course without thinking and understanding what is talked about. The course is an exercice in itself. Lastly, if you are well prepared the course might seems not that hard, however the course is only a way for you to do more research. Only following the course, and doing once the requested exercices, is a sure way to fail the exam.

The lab is also very different than PWK. There is not plenty of servers to hack, but instead few machines you have full control of, and that will allow you to replicate the course exercices. You are provided with a Backtrack virtual machine, and like PWK you have a VPN connection to your lab. If you enjoyed hunting servers to get your OSCP, you will find CTP to be very different on that point.

Briefly, CTP takes some topics covered in PWK such as XSS/LFI/RCE/AV evasion, go deeper with them, and then add new topics such as SEH/Egghunter/ASLR/Encoding/Router hacking. The exploit modules cover harduous scenario where exploitation is not obvious, or even a nightmare, that require multiple tricks and sorcery to get it working. This is why it is very important to be well prepared before taking CTP to avoid being hit too hard by the course, and be able to follow it mostly fluently. Although there is web modules and one network one about Cisco routers, all of the others require you to live in a debugger. OllyDbg is the debugger used in the course, but I prefered to use Immmunity instead combined with the excellent mona module. I used Immunity for my CTP preparation, then CTP itself, and finally for the OSCE exam.

Regarding the fact that some of the course is dated, I did not find it to be a problem at all. All modules are still very relevant. For instance, the AV evasion module if applied as is will not bypass anymore modern antivirus. However with some custom modifications, it is still perfectly possible to evade even the best AV out there. Also, old tools such as msfpayload and msfencode are used, but nothing prevents you from using msfvenom instead (from Backtrack or from a secondary Kali VM for instance). Of course doing so will require slight modifications sometimes to follow the course and make things working, and can add some headaches, but it is perfectly possible.

Finally, I see CTP as a very exciting course, often seen as "hard" (and somehow it is), but for which, with enough preparation, is really fun to go trough. I finished CTP in 5 weeks, as at the end of each module I did the given exercice multiple times, and I searched for similar exercices I additionaly did. Then, for my revision program, I used the remaining 3 weeks as below.

My pre-exam revision program:
- I took my time to go over the course again starting from scratch, took eventually missing screenshots
- I did again the exercices until I felt really confortable with them
- I did additional exercices
- I automated and scripted everything I could, that I have not already automated while doing the course
- I made additional research on each topics to go further
- I tried to anticipate traps Offensive Security could throw at me in the exam

I have cut my program in 3 weeks, so that I would not go over the course too fast, which allowed me to thoroughly work the 9 topics. I wanted to be able to do any exercice from any topics as naturally as possible to have more time while the exam to think about the problem and the solution, without loosing time remembering how to proceed. I took my notes together, screenshots and visual schemas, scripts, additional research exercices and links, and kept close to me few "trick" scripts or code I made in anticipation to traps I could foresee in the future exam (with little imagination, it is obvious Offsec will have some ambush for you!). Once I felt really prepared, I booked the exam for the January 06 2016.

The exam is a 24 48 hours marathon where you have to accomplish some tasks, and reach at least 75 points to pass. There is either "easier" tasks giving a low ammount of points, or the hardest tasks which give you the double. The way the points are distributed over the tasks, you must nearly have them all to pass.

That was to objectively describe the exam

Now, to describe my experience: the exam is brutal, I was sometimes in total despair while the exam, and at multiple times I felt like I was getting nowhere and that it was lost... Before the exam I though I would be so much prepared I would overcome the easiest tasks easily and attack the hardest ones with a great mood, but the exam was much harder than I anticipated. No matter how prepared you are, the exam will be hard. If you are not prepared enough, and just followed the course without mastering what was taught, you will fail the exam. I have read some OSCE reviews arguing about if everything to pass OSCE was in the course or not, and sometimes the answer I have read was "yes and no". To elaborate a bit about this, yes the exam's topics are directly from the course, however to overcome surprises encountered in exam's challenges, external research helps a lot. In all cases, you can only succeed if you mastered what you did learn and if you are able to apply them creatively in unknown situations. I am aware that seems vague, but I cannot be more precise :-)

Now to be more specific about what happened. I started the exam on Wednesday at 10AM. I put so much pressure on my shoulders that I was feeling sick since Tuesday, and I did not have the good night sleep which is advised. Once I received the exam instructions and saw the challenges, I jumped on the "easiest" exercices as I though I would be able to go over them quickly. Of course Offsec did put some obstacles on the way, and I have found that I needed everything I learned from exam preparation to painfully get these challenges. In 7 hours I was able to get them, but with only 30 points I was far from the required 75 points to pass. It put me anyway in a great mood as I did not loose time on them, and I had plenty of remaining time to tackle the hardest ones. Of the two remaining challenges, by reading the instructions one seemed to me much more difficult, as it was about a subject I considered to be my weak spot (although I did practiced it as much as I could). I decided to go for the other one first as I felt more confortable with it. I quickly found the first step, but then it seemed like a deadend. I then went for a quick sleep for 5 hours, and get up and resumed where I left. Sleeping is absolutely necessary, your brain cannot work efficiently without it, even with cafein! Given the fact I was stuck, I looked at every possible angles I could see at that time to see if there was another starting/entry point, but found none. So I found the beginning of the exploitation, but then nothing worked, I was truly stuck... 6 hours after I started this challenge, I realised I was getting nowhere and decided to switch to the other second challenge I did not yet try. Unlike what I expected, I quickly found the first exploitation step. That highlights the fact that you should try every exercice, even if you think you will fail them, as you could do better than you think. However then, I was here too unable to find the following step, everything I learnt and tried fell short...

At that point it was very hard to understand the situation. I prepared as much as I could for the exam, I did additional research and exercices, anticipated everything I could think of, had some nifty tricks and scripts under the belt to help me, but still the challenges were beyond my capabilities... That was the hardest moment, when you realise you are still not good enough to surpass the challenge.

Try Harder. Yes, trying harder is the only possible way, if you badly want the certification, it is not possible to give up. It is a good time to take a break, rest, drink a coffee, walk, why not taking a shower. Then, I resumed the second challenge, and after some tries, I had an idea which led me to more research. Later on, I finally found something very interesting which happened to work! I was finally able to move forward and do the remaining of the challenge quickly, and got my score up to 60 points. I then moved back to the first challenge I was stuck earlier, and resumed my efforts on it. To pass the exam the full 30 points were not needed, only half of it would be enough. However as stuck as I was, I did not have enough points. It was still the second day after one night of sleep, I was not late on my timing, so I tried to relax and be creative. As I had no idea how to proceed, I have written a draft of some possible paths to follow, without having a clear vision of the entire picture. I then went on testing these various paths, and although I had some failures, progressively it narrowed down the possibilities. At the end I was nearly sure of the technique to use to progress, but was still unable to exploit it! The feeling I had at that moment was like trying to make a Rubik's Cube, moving forward step by step, without being sure to reach the end (disclaimer: I'm not good at Rubik's Cube!). Suddenly, out of nowhere, I had the best idea I had in hours as to what was the big picture, how to progress, what it would lead to, and how it should give me a remote shell at the end. Of course it was still a theory, but it all became clear. Then it was just a matter of making it to work, and although I never endured so much pain in an exam, I found one way to get it working. I had to use everything I knew, and learn some new knowledge in the process, but I got it. When you get you remote shell on your last target, after so much suffering, tears and blood, you feel ecstatic!

At that point it was 37 hours after my exam started (23h00 or 11h PM), and although the method I used on the last exercice may not give me full points, even half of it would be ok. I was initially ready to go trough this second night without sleeping, but as I found the solution sooner, I choosed instead to sleep another 5 hours, instead of improving my last challenge solution. The next morning, I started to write my report, which ended up taking most of the day. It was longer than OSCP report, as I have taken a lot of screenshots, and I went on many directions, done many mistakes and had many failures, and the path to every solution was not a straightforward step by step process. I have finished and sent my report around 18h (6h PM).

I was then exhausted, but satisfied of the result. I kept my fingers crossed until I received the result next monday, an email from Offensive Security telling me I successfully passed the exam and got the OSCE certification :-) I was lucky enough to pass it at first try.

Going from OSCP to OSCE is definitely possible, even if you are not working in the offensive security field. It requires more work in that case, some perseverence, and a well constructed preparation. The CTP course should not be rushed, even if it easy to go trough it quickly just following it (minus few missing parts you have to figure out yourself). I personally found that taking the 2 months for the course was fine, while other reviews say that 1 month is enough. I think it really depends on your expertise level to begin with. For me, 5 weeks on CTP and 3 weeks for the revision and to prepare the exam was perfect.

The exam is a monster of its own. Different strategies are possible, such as doing the hardest challenges first, get most of the points, and ending with the easiest ones. That worked for me for OSCP, as I nearly did this begining by the challenge giving the most points. However in OSCE exam I would have been in total despair should have I done it that way. Indeed I would have been stuck on the hardest challenges with 0 points in my pocket, that would have been an unbearable path. It is easier to be stuck at something when at least you got the other points, and you are good on the timing. That is my personal opinion though, I have read g0tm1lk review where he apparently found the hardest challenges the easiests, and inversely for the easiest ones. In all cases, taking frequent breaks and resting is essential. While I prefer to work without any music as it distracts me, if you work better with it then go for it. Anything that puts you in a confortable and productive state of mind can only help. The exam is unique in the way you also learn a lot while doing it, as you need to improve your skills while doing the challenges.

I was able to obtain OSCP and OSCE certifications in one year, including the 4 months preparation for CTP. It was a full year dedicated to Offensive Security courses, and what I earned from them is above what I initially expected when starting PWK one year ago. CTP/OSCE is clearly for people who knows learning by themselves, and who are highly motivated and dedicated. CTP course is fun to follow, but OSCE exam is traumatic! However once you earn the coveted certification, it is an extremely rewarding moment, being a recognition of months of hard work.

Cracking The Perimeter course and OSCE exam are a wonderful experience teaching you a lot. I heartedly recommend them.

Thanks for reading.