Transparent SSL Interception Bridge with mitmproxy

Hopefully you've heard of mitmproxy, a wonderful little Python tool for intercepting, decrypting, and dissecting SSL traffic. It also makes it very easy to decrypt SSL traffic for an entire network with Wireshark/TShark (see bottom of article).

Image Credit: Nick Charlton

It's a fabulous tool, but the setup instructions in the documentation are less than fabulous.

If you've tried to set it up for yourself, you might've run across Nick Charlton's excellent tutorial. He tells you how to set up an Ubuntu Server machine as a router, which is good for many scenarios and certainly gets the job done.

But what if you want the proxy to be as transparent as possible? More transparent than a router; how about an SSL-intercepting switch?

In my opinion, this is a much better way to deploy mitmproxy as it allows you to use a more stable, well-known platform (in my case pfSense) as your router. You simply drop in the mitmproxy machine between your switch and your router, and it will appear just like any other switch while silently intercepting and decrypting all your network's SSL traffic.


Setup

To set this up, I used an Ubuntu Server 16.04 LTS install with an extra NIC added (making this machine essentially a two port switch).

It is important to note that many hypervisors, most notably VMware's ESXi, will not allow you to do this. ESXi in particular has vSwitch code that is incompatible with bridge VMs like this because of some strange assumptions it makes about ARP. Supposedly you can set the switches in promiscuous mode to fix the problem, but I had no luck with that. My recommendation: if you need to do this in ESXi, do it the Nick Charlton set-it-as-a-router way.


Step 1. Install bridge-utils and configure the network interfaces. For example, in my instance: - eth1 is connected to the pfSense router - eth0 is connected to the client PCs - The config below sets up a bridge, br0, with an IP of 192.168.1.3. Add this to /etc/network/interfaces.

auto br0  
iface br0 inet static  
        address 192.168.1.3
        netmask 255.255.255.0
        gateway 192.168.1.1
        dns-nameservers 8.8.8.8 8.8.4.4
        bridge_ports eth0 eth1
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0

Step 2. Install iptables firewall and ebtables, which is a layer-2 firewalling program (necessary since this machine is pretending to be a switch).

Step 3. Make sure that clients behind this bridge can still obtain IPs through DHCP, ping Internet hosts, and other basic networking tasks. All that should work since this machine is behaving exactly like a switch right now. If it doesn't behave as expected, make sure it is not your hypervisor. I can confirm it works in VirtualBox, but does not work in ESXi, and I have not tested others.

Step 4. Install mitmproxy and its dependencies through pip

sudo apt-get install python3-dev python3-pip libffi-dev libssl-dev  
sudo pip3 install mitmproxy  # or pip3 install --user mitmproxy  

Step 5. Test mitmproxy installation by starting it. It should not actually be recieving traffic yet, we just need to start it once so it will generate all its certificates and config files and such. sudo mitmproxy -T --host will start it in transparent proxy mode, and its config files will be stored in /home/youruser/.mitmproxy.

Step 6. Now the cool part. We need to use ebtables, a layer 2 firewalling program, to redirect traffic to our machine, then use iptables to redirect it to the right port for our proxy. Add the following rules, adjusting your interface names accordingly:

sudo ebtables -A BROUTING -p IPv4 --ip-proto tcp --ip-dport 80 -j redirect  
sudo ebtables -A BROUTING -p IPv4 --ip-proto tcp --ip-dport 443 -j redirect  
sudo iptables -A PREROUTING -i br0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080  
sudo iptables -A PREROUTING -i br0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8080  

Note that neither iptables nor ebtables rules will persist on reboot unless you take special actions.

Step 7. Start the proxy with sudo mitmproxy -T --host.

Step 8. On a client behind the bridge, confirm you still have access to the internet by pinging a public IP address. Then visit http://mitm.it and follow the instructions to install the proxy's internal certificate on your operating system.

Congratulations, you have a working mitmproxy installation! Visit an HTTPS webpage on your client PC and you should be able to navigate through the decrypted HTTP traffic on your mitmproxy machine.

More Decryption

While the exact setup is outside the scope of this tutorial, it is easy to decrypt captured HTTP traffic from your network in WireShark using mitmproxy. You need to set the MITMPROXY_SSLKEYLOGFILE environment variable on your proxy server. This will tell the proxy to dump all the TLS Master Secrets to a file, which you can then feed into Wireshark.