Detecting VPN (and its configuration!) and proxy users on the server side
A lot of people use VPN every day. Somebody use it in always-on mode to circumvent government or corporative internet censorship, while somebody use it from time to time to bypass geographic restrictions. You may already know that huge video and music streaming services and game shops never really liked VPN users who easily bypass all restrictions to unblock country restricted content or to buy a game for less. Examples are plentiful: Netflix changed their ToS recently so that it can now terminate your account contract if you’re found to be circumventing its geo-restrictions, Hulu was also noticed for blocking VPN users, and Steam has been always suspicious to non-Russian speakers from Russia. Recently some companies tries to block not individual users but entire IP addresses of VPN services, which is troublesome for both users and VPN services. Seems like they don’t have any automatic tools and block addresses manually. While I’m against any type of censorship, I was curious if it is possible to detect VPN or proxy users on the server side.
And the answer is yes, under certain conditions. And pretty accurate.
MSS and MTU
MTU or Maximum Transmission Unit stands for maximum data which could be transmitted in one packet. Every network adapter have its MTU value, even the routers between you and the remote side which transit your packets. Most of the time it is set to 1500, there are some exceptions though.
When you web browser or any other software working with the network creates TCP connection to the remote side, it adds Maximum Segment Size (MSS) value into TCP header, which informs remote size of the maximum TCP data size initiator can receive without packet fragmentation. This value is very similar to MTU.
As you try to open a web page with PPTP, L2TP(±IPsec) or IPsec IKE connected, your packet is encapsulated into another packet which introduces overhead. Large packets which could be sent without fragmentation without VPN connected now should be fragmented in order to be successfully delivered via your network, which lowers your speed and adds latency. In order to mitigate excessive fragmentation, OS sets lower MTU on the VPN interface then your real network interface MTU, preventing huge packets which would require fragmentation to be created. As far as I understand there is no standard or usual MTU sizes for PPTP, L2TP or IPsec. MTU value for said protocols is set by VPN administrators approximately, according to the minimum MTU size among all VPN users. OpenVPN, the most popular VPN solution, has chosen the other way.
To support old or just crappy software, OpenVPN doesn’t decrease interface MTU but decreases MSS inside encapsulated packet. That’s done with the mssfix setting which calculates OpenVPN overhead for the packet encapsulation and encryption and sets MSS accordingly for the packets to flow without any fragmentation. It is configured to work with any link with MTU 1450 or more by default. Because of this unique MSS values, we can determine not only if the user is connected via OpenVPN , but also used connection protocol (IPv4, IPv6), transport protocol (UDP, TCP), cipher, MAC and compression as they affect MSS.
Let’s take a look at a typical MSS values:
| Protocol | Block size | MAC | Compression | MSS |
| UDP | 64 | SHA1 | - | 1369 |
| UDP | 64 | SHA1 | + | 1368 |
| TCP | 64 | SHA1 | - | 1367 |
| TCP | 64 | SHA1 | + | 1366 |
| UDP | 128 | SHA1 | - | 1353 |
| UDP | 128 | SHA1 | + | 1352 |
| TCP | 128 | SHA1 | - | 1351 |
| TCP | 128 | SHA1 | + | 1350 |
| UDP | 128 | SHA256 | - | 1341 |
| UDP | 128 | SHA256 | + | 1340 |
| TCP | 128 | SHA256 | - | 1339 |
| TCP | 128 | SHA256 | + | 1338 |
If cipher uses 64 bit cipher then it’s probably Blowfish. If 128 — probably AES.
To prove my theory 2 VPN services has been tested: VyprVPN and ibVPN. Both of them could be identified using this method. If you don’t want to be identified, you can disable mssfix, just set it to zero on both server and client. With mssfix 0 your MSS would be 1460 which corresponds to MTU 1500 for IPv4 connection, and you’ll get fragmentation which leads to lower connection speed and higher latency. It may be better to disable OpenVPN mssfix and use more generic MSS values, like 1400 or 1380 (should be modulo 2 or better 10) as this values are often used for cellular connections. This could be set up using iptables on Linux.
There aren’t really much ways to detect proxy users if it doesn’t add any additional headers like X-Forwarded-For. But what drastically difference VPN from proxy? Remote VPN server receives packets your OS has created while proxy creates packets on its own and gets from you only data which should be transmitted. Different OS versions have their own unique fingerprints. Proxy is usually running under Linux or FreeBSD while web is browsed from Windows. Users are usually not aware that their OS version is transmitted in browser’s User-Agent header and don’t change it. That’s handy for us.
There is a great project called p0f which is very suitable for out needs. It can detect OS, MTU and browser passively and notify us about difference in OS and User-Agent fingerprints. It also has an API. A bit of modifying work and updating its signatures and voilà! we can detect popular VPN protocol users, proxy users and users who spoof their User-Agent header.
After some thoughts I decided to make a simple web service as I didn’t find anything close to my ideas. That developed into ＷＩＴＣＨ？which easily tells you about your OpenVPN connection details (if you didn’t touch mssfix), detect your OS and match it to User-Agent fingerprint. It also parses PTR record to detect are you using home or corporate ISP.
First seen = 2015/07/24 17:19:29
Last update = 2015/07/24 18:39:37
Total flows = 7
Detected OS = Linux 3.11 and newer
HTTP software = Firefox 10.x or newer (ID seems legit)
MTU = 1409
Network link = OpenVPN UDP bs64 SHA1
Language = Russian
Distance = 15
Uptime = 1 days 19 hrs 39 min (modulo 165 days)
PTR test = Probably home user
Fingerprint and OS match. No proxy detected.
OpenVPN detected. Block size is 64 bytes long (probably Blowfish), MAC is SHA1.
ＷＩＴＣＨ？ also detects Tor Browser users because Tor exit nodes are usually running on Linux or FreeBSD and Tor Browser has Windows User-Agent on all platforms.
I found interesting things while testing this service:
- Beeline (cellular operator) proxifies all the mobile connections via proxy running on Linux. This was detected while opening ＷＩＴＣＨ？on the iPhone.
- MTU on the cellphones differ a lot from phone to phone. If you use one SIM on different cellphones you’ll get different MTU values. I suppose it’s bound to the cellular operator configuration and exact GSM module in your cellphone.
- Mssfix code in OpenVPN is very slow. If you’re into networks, C and have courage to fix or speed up it, please do.
UPD 11.04.2018: Windows 10 disabled Single Sign-on for SMB resources when Microsoft Account is configured. The hash of local account or IPsec credentials are still leaked to third-party hosts.