[ Beneath the Waves ]

XMPPPeek

article by Ben Lincoln, software by Ben Lincoln and iamultra

 

This script was originally based on iamultra's xmppmitm.py, but has been modified almost beyond recognition. I put it together specifically for the use described in the Motorola Is Listening article, but it should work (possibly with minor modification) for most encrypted XMPP traffic.

Important: this is not a production-grade script. It should work fine for intercepting traffic, but don't depend on it running without incident for multiple days in a row unattended.

xmppmitm.py was written in a way that is very specific to standard Jabber servers - it sends forged server communication to the client before opening the channel to the real server, and then it sends forged client communication to the server before actually connecting the client and the server, and it does this using hardcoded XML in the script. This didn't work for the slightly-different traffic between my phone and Motorola's Blur servers for a variety of reasons.

xmpppeek.py immediately connects the client to the real target server, waits for the TLS negotiation to be completed (in cleartext - XMPP is similar to IMAP in this respect), and then creates separate SSL connections to the client and the server to form the man-in-the-middle bridge.

Please note that I haven't put a lot of effort into cleaning up the code - it works well enough for my purposes, and because I'm still very new to using Python I didn't want to spend even more time trying to e.g. replace the copy/pasted SSL-bridging code with a call to a separate function, or refactor the whole thing as OO, which I didn't even know Python supported until recently. If I have time later, I'll publish an updated version. There are some other features I have in mind as well, such as the ability to auto-generate the appropriate SSL server certificate for each target it connects to, as well as re-introducing the ability from xmppmitm.py to dynamically determine the target based on the client's request (which I stripped out because the way it was done in the original script wouldn't work with Motorola's Blur servers).

This script does have a basic ability to attempt to strip out the TLS negotiation attempt altogether (which would cause the communication to occur without being encrypted). Motorola's Blur servers will not allow unencrypted communication, so I didn't put a lot of effort into making that functionality accessible either. If you want to play around with it in the current version, change this line:

stripTLSRequest = 0

...to this:

stripTLSRequest = 1

The script comes preconfigured to delimit actual messages between the client and server with }}} at the beginning, and {{{ at the end. This is to make it blindingly obvious where the first and last byte are, in the case that non-printable characters are sent. If you would like to change this, modify the messageDelimiterStart and messageDelimiterEnd variables near the top of the script.

The script also comes preconfigured to close the communication channel if the client sents a single ASCII space (0x20) character instead of an XML message, because this is how the system I tested it against seemed to behave. If you would like to change this, modify this line:

closeChannelOn0x20 = 1

...to this:

closeChannelOn0x20 = 0

It will also write (in append + binary mode) to the file xmpppeek-log.txt in the working directory from which the script was called. The log file path is another variable near the top of the script. If you would like to disable logging entirely for some reason, change this line:

writeToLog = 1

...to this:

writeToLog = 0

I believe the script is generic enough that it should work with most/all XMPP systems (e.g. actual Jabber IM), except for ones that require client-certificate authentication.

Before running the script, you'll need to set up your system to forward traffic between the interfaces, except traffic to the target system (denoted by IP address as X.X.X.X in the script below - replace that with the real target), which will be re-routed to the local port the script will be listening on. This is the shell script I used for that, which is a slightly-modified version of the one from the original Mallory guide. Note that this script has been updated slightly since the initial release of XMPPPeek, and is now included in the tarball download as well.

#!/bin/sh

echo "WAN (External) Interface: "

read wanInt

echo "LAN (Shared) Interface: "

read lanInt

#echo "Stopping network manager"

#/etc/init.d/NetworkManager* stop

#service network-manager stop

echo "Stopping dnsmasq"

/etc/init.d/dnsmasq stop

echo "Configuring interface $lanInt"

#ifdown $lanInt

#ifconfig $lanInt down

ifconfig $lanInt 192.168.137.1 netmask 255.255.255.0

#ifup $lanInt

#ifconfig $lanInt up

echo "Starting DHCP server"

dnsmasq --interface $lanInt --no-hosts --no-poll --except-interface=lo --listen-address=192.168.137.1 --dhcp-range=192.168.137.10,192.168.137.100,60m --dhcp-option=option:router,192.168.137.1 --dhcp-lease-max=50 --pid-file=/var/run/nm-dnsmasq-$lanInt.pid

echo "Stopping firewall and allowing everyone..."

iptables -F

iptables -X

iptables -t nat -F

iptables -t nat -X

iptables -t mangle -F

iptables -t mangle -X

iptables -P INPUT ACCEPT

iptables -P FORWARD ACCEPT

iptables -P OUTPUT ACCEPT

iptables -t nat -A PREROUTING -i $lanInt -p tcp --dport 5222 -j DNAT --to-destination 192.168.137.1:5222

echo "Turning on Natting"

iptables -t nat -A POSTROUTING -o $wanInt -j MASQUERADE

echo "Allowing ip forwarding"

echo 1 > /proc/sys/net/ipv4/ip_forward

echo "Adding 4.2.2.1 to resolv.conf"

echo "nameserver 4.2.2.1" >> /etc/resolv.conf

echo "GO GO gadget gateway"

To use XMPPPeek itself, you'll need to generate an SSL server certificate and corresponding private key in PEM format, and you'll need to strip the passphrase off of the private key file.

If the target server is listening on a TCP port other than 5222, you'll also need to make a minor edit to the script to change that variable.

At that point, just run the traffic-forwarding shell script above (or your own equivalent), and the syntax for XMPPPeek is:

python ./xmpppeek.py TARGETSERVERNAME CERTFILE KEYFILE

e.g.

python ./xmpppeek.py jabber.server.co.uk ../xmpp/newcert.pem ../xmpp/newkey.pem

Then have your client attempt to connect via an interface that is routed through the system doing the forwarding, and you should see something like this:

[2013-06-28 21:56:33.833784-07:00] [Server started]

[2013-06-28 21:56:33.834180-07:00] [Listener ready on port 5222]

[2013-06-28 21:56:33.834309-07:00] [Main thread waiting for client connection]

[2013-06-28 22:06:19.657455-07:00] [Client connect from 192.168.1.18:44700]

[2013-06-28 22:06:19.657806-07:00] [Main thread waiting for client connection]

[2013-06-28 22:06:19.658097-07:00] [Server connect to jabber.server.co.uk]

[2013-06-28 22:06:19.958327-07:00] [Client initiated TLS negotiation]

[2013-06-28 22:06:19.958928-07:00] [(C2S) 192.168.1.18:44700 -> jabber.server.co.uk:5222] }}}{{{

[2013-06-28 22:06:20.027926-07:00] [(S2C) jabber.server.co.uk:5222 -> 192.168.1.18:44700] }}}{{{

[2013-06-28 22:06:23.029858-07:00] [Server agreed to TLS]

[2013-06-28 22:06:23.030109-07:00] [(S2C) jabber.server.co.uk:5222 -> 192.168.1.18:44700] }}}{{{

[2013-06-28 22:06:23.030288-07:00] [Client and server have agreed to an encrypted channel]

[2013-06-28 22:06:23.030393-07:00] [Creating SSL-wrapped socket to client]

[2013-06-28 22:06:23.633849-07:00] [SSL-wrapped socket to client created]

[2013-06-28 22:06:23.634451-07:00] [Creating SSL-wrapped socket to server]

[2013-06-28 22:06:23.995126-07:00] [SSL-wrapped socket to server created]

[2013-06-28 22:06:23.995778-07:00] [Successfully created SSL bridge]

[2013-06-28 22:06:24.005157-07:00] [(C2S) 192.168.1.18:44700 -> jabber.server.co.uk:5222] }}}{{{

[2013-06-28 22:06:24.084141-07:00] [(S2C) jabber.server.co.uk:5222 -> 192.168.1.18:44700] }}}{{{

[2013-06-28 22:06:24.503149-07:00] [(C2S) 192.168.1.18:44700 -> jabber.server.co.uk:5222] }}}XXXXXXXXXXXXXXXX1-8cb2237d0679ca88db6464eac60da96345513964BlurDevice{{{

[2013-06-28 22:06:24.582878-07:00] [(S2C) jabber.server.co.uk:5222 -> 192.168.1.18:44700] }}}{{{

[2013-06-28 22:15:25.106809-07:00] [Client sent a single space - closing this channel]

[2013-06-28 22:15:25.107099-07:00] [(C2S) 192.168.1.18:44700 -> jabber.server.co.uk:5222] }}} {{{

[2013-06-28 22:15:28.108536-07:00] [Disengaging bridge (192.168.1.18:44700 -> jabber.server.co.uk:5222)]

[2013-06-28 22:15:28.108772-07:00] [Closing client socket (non-SSL) (192.168.1.18:44700 -> jabber.server.co.uk:5222)]

[2013-06-28 22:15:28.109024-07:00] [Closing target socket (non-SSL) (192.168.1.18:44700 -> jabber.server.co.uk:5222)]

[2013-06-28 22:15:28.109317-07:00] [Closing client socket (SSL) (192.168.1.18:44700 -> jabber.server.co.uk:5222)]

[2013-06-28 22:15:28.109560-07:00] [Closing target socket (SSL) (192.168.1.18:44700 -> jabber.server.co.uk:5222)]

 
Download
File Size Version Release Date Author
XMPPPeek 3 KiB 0.1b 2013-07-12 Ben Lincoln, iamultra, and 0xD1AB10
Includes updated versions of the port-forwarding shell scripts based on the ones in the Mallory and Me article.
 
Download
File Size Version Release Date Author
XMPPPeek 3 KiB 0.1a 2013-07-09 Ben Lincoln, iamultra, and 0xD1AB10
Now includes the port-forwarding shell scripts based on the ones in the Mallory and Me article as well as xmpppeek.py itself.
 
Download
File Size Version Release Date Author
XMPPPeek 2 KiB 0.1 2013-06-26 Ben Lincoln and iamultra
 
 
[ Page Icon ]