Saturday, October 26, 2013

Creating a simple and fast packet sniffer in C++

I have seen several articles on the web about writing packet sniffers using C and C++ which suggest using raw sockets and dealing with protocol headers and endianness yourself. This is not only very tedious but also there are libraries which already deal with that for you and make it extremely easy to work with network packets.

One of them is libtins, a library I have been actively developing for the past few years. It has support for several protocols, including Ethernet, IP, IPv6, TCP, UDP, DHCP, DNS and IEEE 802.11, and it works on GNU/Linux, Windows, OSX and FreeBSD. It even works on different architectures such as ARM and MIPS, so you could go ahead and develop some application which could be executed inside routers and other devices.

Let's see how you would sniff some TCP packets and print their source and destination port and addresses:
#include <iostream>
#include <tins/tins.h>
using namespace std;
using namespace Tins;
bool callback(const PDU &pdu) {
    const IP &ip = pdu.rfind_pdu<IP>();
    const TCP &tcp = pdu.rfind_pdu<TCP>();
    cout << ip.src_addr() << ':' << tcp.sport() << " -> " 
         << ip.dst_addr() << ':' << tcp.dport() << endl;
    return true;
}

int main() {
    // Sniff on interface eth0
    Sniffer sniffer("eth0");
    sniffer.sniff_loop(callback);
}
This is the output I get when executing it:


As you can see, it's fairly simple. Let's go through the snippet and see what it's doing:
  • The callback function is the one that libtins will call for us each time a new packet is sniffed. It returns a boolean, whch indicates whether sniffing should go on or not, and takes a parameter of type PDU, which will hold the sniffed packet. This library represents packets as a series of Protocol Data Units(PDU) stacked over each other. So in this case, every packet would contain an EthernetII, IP and TCP PDUs.
  • Inside callback's body, you can see that we're calling PDU::rfind_pdu. This is a member function template which looks for the provided PDU type inside the packet, and returns a reference to it. So in the first two lines we're retrieving the IP and TCP layers, and then we're simply printing the addresses and ports.
  • Finally, in main an object of type Sniffer is constructed. When constructing it, we indicate that we want to sniff on interface eth0. After that, Sniffer::sniff_loop is called, which will start sniffing packets and calling our callback for each of them.
Note that this example will run successfully on any of the supported operating systems(as long as you use the right interface name, of course). The endianness of each of the printed fields is handled internally by the library, so you don't even have to worry about making your code work in Big Endian architectures.

Now, you may be wondering whether using libtins will make your code significantly slower. If that is your concern, then you should not worry about it at all! This library was designed keeping efficiency in mind at all times. As a consequence it's the fastest packet sniffing and interpretation library I've tried out (note that I tried several, such as scapy, dpkt, impacket and libcrafter). Go ahead and have a look at these benchmarks to see how fast it actually works.

libtins allows you to implement fast packet sniffers in very few lines of code. It also supports additional features like reassembling and following TCP streams, decrypting WPA2 traffic (both TKIP and AES) and defragmenting IP datagrams.

If you want to learn more about libtins, please visit this tutorial, which covers everything you should know before starting to develop your network sniffing application!

Tuesday, June 4, 2013

Decrypting WEP/WPA2 traffic on the fly

This is the first application I've developed using libtins, a packet crafting and sniffing library I've been developing for a while. In the latest release of that library, I've added support for WPA2 decryption, so this application does very few things and does not handle encription at all; the library does so.

The decryption of WEP and WPA2 traffic has been available for a while now. Applications such as wireshark, tshark and airdecap have supported this for quite some time. However, after adding this decryption feature to libtins, I wondered why there were no applications that let you decrypt the traffic directly from a network interface and make it available, decrypted, for any other application. This is where dot11decrypt was born.

 

Objective


The application sniffs a network interface looking for WEP and WPA2 encrypted traffic. It also analyzes EAPOL(802.1X) handshakes in order to track the nonces shared by peers, which will later be necessary while decrypting WPA2.

Once a packet is decrypted successfully, the 802.11 frame is replaced by an Ethernet header, and the whole packet is written to a tap interface. You now can read those decrypted packets using any other tool, such as Wireshark or ngrep, and perform any kind of analysis.

What is required for decryption

dot11decrypt does not crack any of the above mentioned encryption algorithms. So if you're looking for a wireless cracking tool, then this is not one of them.

In order to crack WEP encrypted traffic, you need to provide the access point's BSSID and the WEP key. The syntax required to indicate that decryption data is the following:
wep:[BSSID]:[KEY]
For example:
wep:00:01:02:03:04:05:mypassword
Indicates that the access point whose BSSID is "00:01:02:03:04:05" uses WEP encryption and the WEP key is "mypassword".

On the other hand, WPA2 traffic is a little bit more complex. In order to generate the first set of keys required to decrypt the traffic(the Pairwise Master Key or PMK), both the pre-shared key and the network SSID(you network's "name") are required.

In order to specify both of this attributes, the following syntax is used:
wpa:[SSID]:[PSK]
As an example:
wpa:MyAccessPoint:MySecretKey
Indicates that any access point which broadcast the SSID "MyAccessPoint" will be decrypted, assuming the PSK is "MySecretKey".

How it works

 

Decrypting WEP frames is fairly simple, given the WEP key, it's just using RC4 over the encrypted data.

Decrypting WPA2, however, is a little bit trickier. In order to decrypt a WPA2 encrypted frame, the following is required:

  • The PMK(mentioned a few lines above).
  • The association SSID -> BSSID.
  • A valid 4-way handshake between the client which sends or is about to receive that frame.
The application initially computes the PMK. Since you only provide the network SSID, then the application will look for beacon frames so as to know which BSSID is broadcasting the given SSID.

After that, when a client performs a handshake against those BSSIDs, a Pairwise Transient Key(PTK) is computed and stored. At that point, any packet sent from or to the associated client will be decrypted using that PTK. If any client is deauthenticated and then authenticated again, that new handshake will be taken into account and used to decrypt its packets.

Luckily for us, all of the above mentioned is already implemented and performed automatically by libtins: inspecting beacon frames looking for the SSID, capturing 4-way handshakes and decrypting the traffic. If you want to have a look at that code, have a look at the WPA2Decrypter class.

Note that WPA2 decryption works for both AES(CCMP) and TKIP encrypted frames, so this works for WPA as well(since this uses TKIP).

Compiling the application

 

In order to compile dot11decrypt, the latest version of libtins is required(version 1.1 at the moment of writing). You can download it from the project's github entry. The library must be compiled using support for WPA2 decryption(this is enabled by default).

Since the application uses some C++11 features, a fairly recent C++ compiler is needed as well. g++ 4.6 is enough. g++ 4.5 might do.

dot11decrypt's source code can be downloaded from github. After you've got these, just go ahead and do the usual:
./configure
make

Using it

 

The application takes as its first argument, the interface in which to listen for packets. This must be a wireless interface in monitor mode. The rest of the arguments specify the data which will be used to decrypt the data, using the syntax mentioned near the beginning of this post:
./dot11decrypt wlan0 wpa:MyAccessPoint:some_password
./dot11decrypt mon0 wep:00:01:02:03:04:05:blahbleehh
After running it, you'll get an output similar to the following:
Using device: tap0
Device is up.
The tap0 interface will now be used to output the decrypted traffic. tcpdump or any other network sniffing tool can be used to process the data. Note that the 802.11(and possibly the RadioTap encapsulation used) and LLC+SNAP frames will be removed and replaced by an Ethernet header.

Note that you require either root privileges or the CAP_NET_ADMIN capability on the executable to run this application successfully.

Example

In this example, I'm going to sniff and decrypt the traffic sent from my phone.

The mon0 interface, the one I'll be using, is in monitor mode. This is the output of running tcpdump on that interface, filtering only IEEE 802.11 data frames for which the second address in that frame is the access point's BSSID:


As you can see, there are several Dot11 QoS Data frames, all of them encrypted.

Now, I'm going to execute dot11decrypt providing the SSID and the WPA2 PSK:


A new tap interface has been created, named tap0. Every decrypted packet will be written to it.

At this point, I connected my phone to the access point. The application captures the 802.1X handshake and it will start decrypting the traffic. In the image below, you can see how the traffic sniffed from the tap0 interface is no longed encrypted:


I hope you find this application useful!