wiki:debugging/MITM

Debugging encrpyted networked software using a Man in the Middle (MITM) approach

Sometimes you need to debug piece of software that makes encrypted connections out to a remote host not under your control. If that software is failing, and you suspect something is going wrong in the network session to trigger the error, you might want to set up your own Man In The Middle (MITM) sniffer to see specifically what's going on in cleartext. This page describes how to do that if the outbound connection uses TLS connections, and the software is being run on a reasonable OS like debian.

Advantages to this technique

  • you don't need the source for the software in question.
  • even if you have the source, you don't need to worry about recompiling or modifying it, which might potentially change the behavior of the software in question (especially a problem if it's complex code that you don't fully understand)

Disadvantages to this technique

  • It's a hassle to set up
  • It makes your software (while you're debugging) potentially vulnerable to other MITM attacks
  • It requires superuser access to the machine you're debugging on
  • It can potentially disable other software on the same host, if that software is also trying to connect to the same external server

Assumptions and Definitions

The remote server your dubious software is attempting to connect to is remote.example.net -- if you aren't sure how to figure this out, you could try debugging/strace?ing your program and looking for gethostbyname() calls, or setting up a dnscache instance, directing your software to it, and reading the logs of what lookup it's doing.

The remote server lives at IP address 192.0.2.17.

You can make a temporary directory to hold all files related to this approach in /tmp/mitm

The remote server is listening on port 443 (HTTPS). If it's a different port, adjust accordingly.

How to set up the MITM

  • make a new self-signed TLS cert and key which claims to be remote.example.net. Put them (PEM-encoded) in /tmp/mitm/fake.crt and /tmp/mitm/fake.key.
  • Configure the TLS client modules for whatever tool you're using to trust /tmp/mitm/fake.crt as a legitimate certificate authority. Depending on the tools you're using, this might require installing /tmp/mitm/fake.crt in a system-wide location, though you might also be able to pass arguments to the program indicating new CAs to trust.
  • create a new loopback interface IP address on your host -- this has to be in the 127.x.x.x/8 range. Let's say you choose 127.0.2.2.
  • if any package on your host (like a web server?) is listening on port 443 on all IP addresses, change its configuration to only listen on the external IP addresses (or every address but 127.0.2.2, at any rate)
  • install socat on your host, and set up a socat redirector between your loopback and remote.example.net, but logged. Using socat's OPENSSL-LISTEN and OPENSSL I/O types lets you make the connections SSL aware, so that the logs come out in the clear. Make sure the listening socket uses /tmp/mitm/fake.key and fake.cert. It might look something like this (Completely untested!):
    socat -v OPENSSL-LISTEN:443,bind=127.0.2.2,reuseaddr,cert=/tmp/mitm/fake.crt,key=/tmp/mitm/fake.key OPENSSL-CONNECT:192.0.2.17:443,verify=0 2>>/tmp/mitm/transaction.log
    
  • change the /etc/hosts file on your server to point remote.example.net at your new loopback address (127.0.2.2)

With this infrastructure set up, you can now try to make another test payment via your usual process, and see a log of the actual HTTP traffic in /tmp/mitm/transaction.log. You'll be able to see exactly what data is getting passed between the two hosts.

Notes

  • each run of socat will only log a single HTTPS session. If the tool you're debugging requires multiple connections for a single transaction, all connections after the first will fail. You might want to include the "fork" option on the OPENSSL-LISTEN side of the socat invocation in that case.
  • to tear down (and return the system to its normal state), the main thing you'll need to get rid of is the /etc/hosts entry. Getting rid of the other stuff is the Right Thing, but if you do that and forget about the /etc/hosts entry, you'll have effectively blocked your host from communicating with remote.example.net.
  • The outbound half of the socat connection has certificate verification disabled. It needs this because we're accessing it by IP address, but the certificate offered often only includes the DNS name of the host. If remote.example.net actually has a clever administrator, they might have gotten a cert that includes the IP address in a SubjectAltName X.509 extension field. If this is the case, you should remove the verify=0 option. Leaving certificate verification disabled is insecure because it allows anyone else in the network path to the remote machine to do a MITM attack like this one. Do NOT leave anything like this up for long or use it for more than a handful of test debugging runs. Data transmitted over this link are not as easily vulnerable as if they were transmitted in the clear, but TLS without cert verification isn't worth much.
  • many of the steps involved in this setup require superuser access to the host in question. Use caution and take notes as you work!
Last modified 10 years ago Last modified on Nov 26, 2007, 11:27:56 PM