Setting Up a Transparent SSL Proxy – Step-by-Step Guide

httpsiptablesman-in-the-middlessltransparent-proxy

I've got a linux box set up with 2 network cards to inspect traffic going through port 80. One card is used to go out to the internet, the other one is hooked up to a networking switch. The point is to be able to inspect all HTTP and HTTPS traffic on devices hooked up to that switch for debugging purposes.

I've written the following rules for iptables:

nat

-A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.2.1:1337
-A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 1337

-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE

On 192.168.2.1:1337, I've got a transparent http proxy using Charles (http://www.charlesproxy.com/) for recording.

Everything's fine for port 80, but when I add similar rules for port 443 (SSL) pointing to port 1337, I get an error about invalid message through Charles.

I've used SSL proxying on the same computer before with Charles (http://www.charlesproxy.com/documentation/proxying/ssl-proxying/), but have been unsuccessful with doing it transparently for some reason. Some resources I've googled say its not possible – I'm willing to accept that as an answer if someone can explain why.

As a note, I have full access to the described set up including all the clients hooked up to the subnet – so I can accept self-signed certs by Charles. The solution doesn't have to be Charles-specific since in theory, any transparent proxy will do.

Thanks!

Edit: After playing with it a little, I was able to get it working for a specific host. When I modify my iptables to the following (and open 1338 in charles for reverse proxy):

nat

-A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.2.1:1337
-A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 1337

-A PREROUTING -i eth1 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.2.1:1338
-A PREROUTING -i eth1 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 1338

-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE

I am able to get a response, but with no destination host. In the reverse proxy, if I just specify that everything from 1338 goes to a specific host that I wanted to hit, it performs the hand shake properly and I can turn on SSL proxying to inspect the communication.

The setup is less than ideal because I don't want to assume everything from 1338 goes to that host – any idea why the destination host is being stripped?

Thanks again

Best Answer

The issues you're seeing are the same that prevent the use of multiple certificates on a single IP address/port (without using Server Name Indication).

In plain HTTP, your transparent proxy can tell which host the client wants to connect to by looking into the Host header.

When the HTTPS MITM transparent proxy gets the request, it can't know which host name the client was requesting in the first place. (I'm not even sure it can get the IP address with these rules, which might at least have allowed it to make a guess using a reverse DNS lookup, even though it's unlikely to work in the general case.)

  • In order to get the expected host name, the MITM proxy would have to read the Host header in the HTTP message, which can only occur after a successful handshake.
  • In order to have a successful handshake, the MITM proxy needs to generate a spoof certificate matching the expected hostname.

As a result, the MITM proxy can't know which certificate to generate before the handshake.

This can work with a non-transparent MITM proxy, because you would at least get the intended host name via the HTTP CONNECT method.

Related Topic