Monitoring Android Traffic with Wireshark
The ubiquity and convenience of smartphones has been a real boon for getting information on the go. I love being able to jump on a Wi-Fi hotspot, catch up on my mail, check my banking balance or read the latest tech news—all without having to bring along or boot up a laptop. Now that mobile development is mainstream, most of this access is done via specialized apps, instead of via a Web browser.
This migration away from direct Web access in favor of dedicated smartphone apps has made for a richer user experience, but it also has made knowing exactly what is going on "under the hood" a lot harder. On our Linux boxes, there are many tools to help user peer into the internals of what's going to and from the machine. Our browsers have simple HTTP versus HTTPS checks to see if there's encryption, and there are simple but easy-to-use browser plugins like Firebug that let us view exactly what's being sent and retrieved over the Web. At the operating system level, powerful tools like Wireshark let us drill down even further, capturing all traffic flowing through a network interface. Smartphones usually are locked up to a point where it's almost impossible for a regular user to run any network monitoring or tracing software directly on the phone—so how can a curious user get access to that phone traffic?
Fortunately, with just a little bit of work, you can use Linux to transform almost any laptop into a secret-sharing wireless access point (WAP), connect your phone and view the data flowing to and from the phone with relative ease. All you really need is a laptop running Linux with one wireless and one Ethernet connection.
The first step is to set up your own "naughty" WAP where you can capture and log all the Internet traffic passing through it—simulating the kind of information that a rogue employee could be obtaining from a coffee-shop Wi-Fi hotspot. Let's do this in a distribution-independent way that doesn't mess around with your existing router (no need to change security settings) and doesn't require rooting or installing anything unseemly on your phone.
It may be tempting to try a shortcut for capturing this traffic. Here are a few techniques I tried and discarded before sticking with a hostapd/dnsmasq/iptables solution.
Ubuntu's Built-in Hotspots:
Ubuntu has a handy "Use as Hotspot" feature tucked away in its networking settings. Unfortunately, it creates hotspots in ad hoc mode, which isn't compatible with most versions of Android. I didn't try Fedora's implementation, but the method I recommend instead will work on any distribution.
It's tempting just to put the wireless card in monitor mode and capture all wireless traffic, independent of SSID. This is pretty cool, but there are quite a few "gotchas":
The drivers for your wireless card must support monitor mode. Many, but not all cards support this mode.
Your capture needs to include the four WPA "handshake" packets.
You'll probably have to compile and use airmon-ng to start monitor mode and then capture on the mon0 pseudo-device airmon creates.
If the WAP is using encryption, the packets you capture also will be encrypted. Wireshark does have a facility to help decode the packets, but you'll need to enter information about the security scheme used by the WAP and toggle a few sets of options until the decoded packets look right. For a first-time user, it's hard enough making sense out of Wireshark dumps without having to worry about toggling security options on and off.
Capturing with the Android Emulator:
Another approach would be to use an Android emulator on your capture device, install and then run the target application, and capture the traffic from the emulator. It's much harder than it sounds actually to get a banking app on the emulator though:
Due to recent Android licensing changes, the major Android VMs no longer include the Google Play store. (I tried both the Android SDK and the free product from Genymotion.)
If your phone isn't rooted, it's not easy to get the application's .apk off your phone and onto the VM.
To turn a laptop into a WAP, you'll first use hostapd to use the wireless card as an access point mode (broadcasting an SSID, authenticating with security and so on). Next, you'll use dnsmasq to provide DNS and DHCP services for clients connecting on the wireless connection. Finally, iptables' masquerading features will be used to direct IP traffic from clients on the wireless connection to the Internet (via your Ethernet connection), and then rout responses back to the correct client on the wireless side.
hostapd is a small utility that lets you create your own wireless
access point. Installation is straightforward, and configuration is
just as easy. Most wireless cards and modern kernels will be using the
mac80211 driver. Check yours via
lsmod|grep mac80211. If that's your
driver, find your wireless device via
ifconfig, and set up the SSID of
your choice as shown below for an unsecured, totally open access point:
===[/etc/hostapd/hostapd.conf]====== interface=wlan0 driver=nl80211 ssid=WatchingU channel=1 ===[/etc/hostapd/hostapd.conf]======
I recommend not using Wi-Fi security for this test; it would be overkill, as your access point will only be temporary. Should you desire a more permanent solution, hostapd supports many different authentication options.
Now that hostapd is ready to start letting clients connect to your
wireless connection, you need dnsmasq to serve DCHP and provide DNS for
your access point. Fortunately, dnsmasq is also very easy to install and
configure. The example below is the minimum required. Make sure the
dhcp-range you specify will not conflict with anything already on your
network. By default, dnsmasq will read your existing /etc/resolv.conf
and propagate the DNS settings listed there to its clients. That's a
pretty sane default configuration, but if you need something else,
no-resolv option and specify the DNS servers
========[/etc/dnsmasq.conf]=============== interface=wlan0 dhcp-range=10.0.0.3,10.0.0.20,12h ========[/etc/dnsmasq.conf]===============
The final piece of your wireless access point is iptables, which will use IP Masquerading to get the traffic from the wireless connection, send it over the wired connection and route any responses to back to the correct source on the wireless side. There are many distribution-specific ways to save and script iptables rules, but it's simpler to create a distribution-independent shell script to enable iptables and network address translation (NAT). A script for iptables that ties in hostapd and dnsmasq would look like the following (modify the wlan0 and eth0 entries to match your system):
=======[makeWAP.sh]============== #!/bin/bash export DEV_IN=wlan0; export DEV_OUT=eth0; echo "Bringing up $DEV_IN" #This address/mask should match how you configured dnsmasq ifconfig $DEV_IN up 10.0.0.1 netmask 255.255.255.0 echo "Starting dnsmasq" dnsmasq echo "Configuring iptables" #Clear everything in iptables iptables -Z; iptables -F; iptables -X; #Turn on iptables NAT, forwarding, and enable #forwarding in the kernel iptables --table nat --append POSTROUTING --out-interface ↪$DEV_OUT -j MASQUERADE iptables --append FORWARD --in-interface $DEV_IN -j ACCEPT ↪sysctl -w net.ipv4.ip_forward=1 echo "Starting hostapd" hostapd /etc/hostapd/hostapd.conf 1> /dev/null =======[makeWAP.sh]==============
To test everything, connect your capture laptop to a wired connection
with Internet access and disconnect any existing wireless connections.
Run the makeWAP.sh script (
sudo ./makeWAP.sh) to start up the WAP.
On the phone, turn off mobile data (for Android 4.3, this is done via Settings→Data Usage→Mobile data→Off), turn on Wi-Fi, and connect to the new WAP (in the example above the SSID would be "WatchingU"). Once connected, test a few sites to make sure you can access data from the Internet.
If everything works, congratulations, you have transformed your laptop into the world's most ridiculously overqualified wireless router!
Wireshark is a network packet analyzer that you'll use to capture and make sense of the data flowing on your newly created access point. You'll be merely scratching the surface of its capabilities, as it is an extremely powerful tool with abilities stretching well beyond "poke at a few packets" as used in this project.
Install Wireshark for your version of Linux. If at all possible, get version 1.10 or higher, as 1.10 adds support for decoding gzip'ed HTTP data on the fly (and there's a lot of that). Prior to 1.10, you'd have to save the TCP stream to a file, edit out the header and then gunzip it to view the raw data. This becomes tedious quickly, so having Wireshark do all that for you behind the scenes is awesome.
When running Wireshark for the first time, if it complains that there are
no devices available for capture, you have to give your ID permissions
for the various devices and applications used by Wireshark. For Ubuntu,
sudo dpkg-reconfigure wireshark-common, and select the option to
let nonroot users capture packets, and make sure your ID is in the
"Wireshark" group. For other distributions, search for which devices
and scripts need to be owned by which groups.
Before moving on to capturing traffic, shut down every non-essential app and service on the phone to make it easier to find the traffic of interest. The fewer packets you have to sort through, the better.
Capturing Unencrypted Web Traffic
Before you start looking for sensitive data, let's first get familiar with what unencrypted traffic looks like in Wireshark.
From the Wireshark starting screen, select the wireless device (wlan0) and then the "Start" icon to start a new capture.
On the phone, use a browser to go to http://www.linuxjournal.com.
Once the page finished loading on the phone, press the "Stop" icon in Wireshark, and save the capture file somewhere safe, called something like "Capture_LJ.pcapnp".
Now, let's take a look at this dump. With the dump file open in Wireshark, go to View→Name Resolution and make sure "Enable for Network Layer" is checked. This will improve readability by translating IP addresses to hostnames. The initial view (Figure 1) can be sort of intimidating, but there are some simple tips to make decoding this data easier.
Figure 1. Wireshark Output
As shown in Figure 1, Wireshark's dump screen has one row per TCP packet, but the data is more easily consumed when reassembled into a full TCP stream. To get the full stream, right-click on any row where the source or destination is www.linuxjournal.com, and choose "Follow TCP Stream". This automatically will find all the related packets and group them together in an easier-to-read format.
Figure 2. Follow TCP Stream
In this example, you can see the HTTP GET request from my phone in red, and the HTTP response from the Linux Journal Web server in blue. Here is where you can start to see unencrypted information flowing back and forth from the server. Since the server response's "Content-Type" header indicates that the response is a JPEG image, you can view that image with a little bit of extra manipulation. Press the "Save As" button to save the stream to a temporary file (use RAW format), then use an editor like emacs or vi to trim out the header text from the image binary contents. It takes a little bit of practice, but it's usually pretty obvious where the HTTP header stops and the binary bits begin.
Figure 3. Raw TCP Dump
Once you've removed the header (and any stray footer or additional header sections), you can save the file with a .jpeg extension and view it.
Continue browsing through the dump manually and look for interesting
TCP segments. You also could take a more systematic approach by using
Wireshark's filtering capabilities. Use a filter like
1 (Figure 4), and keep iterating the stream ID until you've seen
all the streams, drilling down with "Follow Stream" if the packets
Figure 4. Filtering to a Single TCP Stream
Capturing Low-Sensitivity Application Traffic
Now that you're getting a little more comfortable with capturing and viewing dumps with Wireshark, let's try peeking at the information coming to and from an Android application. For this next test, I used the app "reddit is fun" since it sends and receives non-sensitive data that is probably not encrypted.
Capture an app search or query using the same technique as before: start Wireshark on the laptop, launch and exercise the app from the phone, then stop Wireshark and save the capture file.
Figure 5 shows an example TCP stream from "reddit is fun".
Figure 5. Gzip-Encoded JSON
Again, the request from the app is in red, and the response from the reddit server is in blue. Note that since the request is not encoded, anyone monitoring the WAP would be able to detect your interest in "Raspberry Pi" data. The content-type of the response is JSON, and even though the Content-Encoding is set to "gzip", Wireshark is letting you view the content body as pure JSON. If the data in your TCP Stream page looks garbled, you may have an older version of Wireshark that doesn't support on-the-fly gzip decoding. Either save the contents to a file and gunzip on your own, or upgrade your version of Wireshark.
Note: look at that hilarious "Server" header in the response—is some clever reddit engineer sending an SQL injection attack to some script kiddies?
Capturing High-Sensitivity App Data
By now, the process to capture traffic from an app should be pretty straightforward. Let's try running a banking or high-sensitivity app and use the tricks described earlier to see if you can detect the application sending any information in the clear that it shouldn't. To be perfectly honest, the odds of finding such a low-level (and easily avoidable) flaw are going to be very, very low. Android application development is pretty mature now, and the Android libraries make using SSL encryption pretty easy. It feels good to double-check though, so follow the same steps as before, but log on to a banking application of your choice.
Now, as you step through the TCP streams, you should note a few major differences. Most of the traffic will be HTTPS instead of HTTP, and the protocol will be TLS instead of TCP or HTTP. In addition, the TCP stream no longer will contain human-readable content, even after trying the standard gunzip tricks (Figure 6).
Figure 6. Encrpyted Traffic
Step through the TCP streams, following each one, and verify that there's no plain text or unencrypted communications that are exposing anything scary.
Now that you've almost certainly not found anything scary, where else can these network monitoring skills be applied? Here are some fun ideas:
Attach a console like a Wii or PS3 and see what kind of information it sends at startup and logon.
Create a WAP that doesn't actually go anywhere and just see what tries to connect. Maybe there's a device using Wi-Fi that you didn't even know about?
Get the SSL certificate for a server you support, and try out Wireshark's SSL decoding.
Reverse the wlan0 and eth0 designations in the scripts and set up the system backwards (connect the laptop's Wi-Fi to your existing WAP, and plug a device in to the laptop's Ethernet port) to monitor the output of wired-only devices. My "smart" Blu-ray player was communicating with all sorts of unexpected places at startup!
- March 2015 Issue of Linux Journal: System Administration
- High-Availability Storage with HA-LVM
- DNSMasq, the Pint-Sized Super Dæmon!
- Localhost DNS Cache
- Real-Time Rogue Wireless Access Point Detection with the Raspberry Pi
- Days Between Dates: the Counting
- You're the Boss with UBOS
- The Usability of GNOME
- Multitenant Sites
- Linux for Astronomers