Earlier this month, I was traveling for work and I found myself at LAX. While getting ready to get on the plane, I noticed that my iPhone had joined to an Access Point. I assumed it was the “Free WiFi” that airports offer. I typically join these networks only when I have to and I usally VPN out before I do anything. Part of my manual process is joining these “untrusted” networks and disabling “Auto Join”. So I was suprised to see that my phone had automatically joined.
Something like this:
What I found out however, is that T-Mobile has pushed a configuration to my phone to a) authenticate to this AP and b) has overwritten my ability to opt-out or disable joining.
Here is some of the conversation I had with them on twitter:
“PassPoint Secure” auto authenticates via T-Mobile? @Apple won’t let me “forget” or disable “auto connect” on a it. I never authorized this. Resetting Network Settings to factory had no effect. Note that I never select “PassPoint Secure” in the attached video. WTF @TMobile? pic.twitter.com/vA6epWM05g— Joubin Jabbari (@joubinj) October 27, 2018
Now, I'm more than sure that there was some fine print somewhere that I didn't read.
The thought process is that these networks are less secure than LTE. Whether you agree or not that LTE is more secure than Wi-Fi networks, we can all agree that it is a different threat model. My justification for that logic is simple. Tools (software and hardware) required for causing mischief in on Wi-Fi is available on all laptops and phones whereas the same tools are a bit more limited for GSM, CDMA, LTE and so on.
WiFi networks can be compromised and we know that WiFi data in transit encryption has had some flaw. On the other hand, a traditional laptop or phone cannot simply compromise the communication channel of mobile provides. It's not that it requires expensive hardware or hard to find software, it doesn't. It's simply that most devices aren't capable of doing this. The pool of Threat Agents that are able to carry out attacks on the WiFi network is much larger than those for mobile networks. In my threat model, threat agents are people or processes. Meaning that they don't have to be physically co-located in a trust boundary. In the WiFi attack scenarios, besides the malicious threat agent, a compromised device is just as effective. The same is not true for the mobile network. Granted, there are other ways to hack mobile networks, but thats besides the point here.
The solution is rather simple and something I wanted to have anyway for a long time. Back when I was an Android owner, customizing my device was rather easy, be it at a significant device integrity risk.
I like the approach for threat modeling with an emphasis to push all controls to the most central component.
In a perfect world, I would want the following to be true:
As a side note, iOS requires that all of the applications installed communicate via TLS. This was widely controversial at the time of the announcement. But today, that line of thinking is one of the primary reasons for me owning an iOS device.
Back to controlling the confidentiality and the integrity of our communication.
I began to look into means of enabling a VPN whenever I connect to non-trusted (any WiFi I don't own) WiFis. Before I started this project, I didn't know much about Mobile Device Management (MDM) technologies. I knew that they existed, but I didn't realize how easy it was to deploy. It requires no infrastructure to take advantage of some of the benefits.
The first part of this is having a VPN to connect to. Before I started this project, I ran PiVPN. Its a simple script that installs OpenVPN on a Raspberry Pi. It has some command line utilities to manage certificates. I never had an issue with my OpenVPN setup. But OpenVPN is not natively supported by iOS and requires an additional app. As a result, I needed to setup a VPN server that is supported by iOS nativly.
From that list, only the IKEv2 supports WiFi whitelisting, and only to an extent. I had read some documentation that the configuration pratameters exposed through
Configurator 2 can be extended manually. Given that, I simply chose the
IPSec as my forward path.
In the past, I had attempted to create a
L2TP tunnel since MacOS doesn't nativly support
OpenVPN either. Given that I had failed in the past, I wasn't optomistic. Typically these VPN install and configuraitions are not for the faint hearted. To my surprise, there is a
Docker for everything. I simply grabbed the
docker-compose from this project, generated some random usernames, passwords, and shared scretes with my password manager, and I had a fully functioning
IPSec VPN server in under 5 minutes - granted that I had Docker installed and working for other services at my house.
Here is my compose file:
version: '2' services: vpn: image: hwdsl2/ipsec-vpn-server restart: always env_file: - ./vpn.env ports: - "500:500/udp" - "4500:4500/udp" privileged: true hostname: ipsec-vpn-server container_name: ipsec-vpn-server volumes: - /lib/modules:/lib/modules:ro
and here is my vpn.env file
# - DO NOT use these special characters within values: \ " ' VPN_IPSEC_PSK=SOMETHING_RANDOM VPN_USER=SOMETHINGELSE_RANDOM VPN_PASSWORD=YET_ANOTHER_RANDOM
Here is what the network configuration looks like regarding the VPN tunneling.
Note that the Network Tap, VPN Server, and DTLS Server are all Docker containers. You have to be careful running some of these on the same host, more so than regular VMs since there is no Hypervisor to pass through. A comprimise of any of the Dockers means the host Server is compormised.
I found a great post by nerd.one explaining how to generate a mobile config profile. Unfortunalitly, depending on your specific configuraitons, you will have to play around with the profile to get this working. Since the asdasd explains everything step by step, I recommend going through that slowly and actually underestand the function of each of the tags in the XML.
Here is what mine looks like
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadContent</key> <array> <dict> <key>UserDefinedName</key> <string>Home: WiFi</string> <key>PayloadDisplayName</key> <string>Home: WiFi</string> <key>PayloadIdentifier</key> <string>io.jabbari.vpn.homewifi</string> <key>PayloadUUID</key> <string>85284094-A9F5-47D7-A1CD-6F831B2FFAC0</string> <key>VPNType</key> <string>IPSec</string> <key>IPSec</key> <dict> <!-- RemoteAdress should be the VPN server's IP or DNS name --> <key>RemoteAddress</key> <string>Change me to the IP address or url of your server</string> <!-- SharedSecret must be base64 encoded --> <key>SharedSecret</key> <data>Change me for the shared secret from vpn.env</data> <!-- XAuth Configuration --> <key>XAuthEnabled</key> <integer>1</integer> <!-- XAuthName is the login name used for authentication --> <!-- Remove the following two lines if you don't want the username to be stored in this file --> <key>XAuthName</key> <string>Change me for the username from vpn.env</string> <!-- XAuthPassword is the password used for authentication --> <!-- Remove the following two lines if you don't want the password to be stored in this file --> <key>XAuthPassword</key> <string>Change me for XAuthPassword from vpn.env</string> </dict> <key>OnDemandEnabled</key> <integer>1</integer> <key>OnDemandRules</key> <array> <dict> <key>InterfaceTypeMatch</key> <string>WiFi</string> <key>SSIDMatch</key> <array> <string>Wifi to allow one</string> </array> <key>Action</key> <string>Disconnect</string> </dict> <dict> <key>InterfaceTypeMatch</key> <string>WiFi</string> <key>Action</key> <string>Connect</string> </dict> <dict> <!-- VPN Default state --> <key>Action</key> <string>Disconnect</string> </dict> </array> <key>OverridePrimary</key> <true/> <key>IPv4</key> <dict> <key>OverridePrimary</key> <integer>1</integer> </dict> <key>PayloadType</key> <string>com.apple.vpn.managed</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </array> <key>PayloadDisplayName</key> <string>VPN Configurations</string> <key>PayloadIdentifier</key> <string>TW.BAB78424-28FB-4654-915D-93D0CB87CC7B</string> <key>PayloadRemovalDisallowed</key> <false/> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>A9F4B095-4336-4ECD-A2B2-3D52D778E743</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </plist>
That's it. You can now email, AirDrop, or iMessage the profile to whatever iOS (MacOS) device you want and install it.
Optionally, if you have an Apple developer account or a code signing certificate handy, you can sign the file from above before sending it.
This is the command that I have to do that
/usr/bin/security cms -S -N "Mac Developer Application" -i VPNConfigurationProfiles.mobileconfig -o signed.mobileconfig
In this case, I would send the signed file off to the device for installations.