** Description changed:

  Short description: local privilege escalation from membership of the
  netdev group to root can be achieved by using the wpa_supplicant's D-Bus
  interface. wpa_supplicant reads and writes to a user-controlled path.
  
- Original report by Vivek Parikh <[email protected]>:
+ Original report by Vivek Parikh <[email protected]> on 21 July
+ 2026:
  
  Tooling and validation
  ----------------------
  This issue was found with AI-assisted source review. Every stated fact was
  validated by hand before sending: the source paths/line numbers were read
  directly, the reachability was confirmed against the shipped D-Bus policy and
  running process on a stock system, and the end-to-end privilege escalation was
  reproduced at runtime on Ubuntu 24.04.4 LTS (details below). Where the impact 
is
  conditional, that is stated explicitly rather than overclaimed.
  
  Summary
  -------
  wpa_supplicant's wpa_config_write() (wpa_supplicant/config_file.c) writes the
  configuration by opening "<confname>.tmp" with fopen(name, "w") and no
  O_NOFOLLOW / O_EXCL, then renaming it over <confname>. Because the open 
follows
  symlinks, a caller who can (a) choose the config path and (b) trigger a config
  save can pre-plant "<confname>.tmp" as a symlink to any file and have
  wpa_supplicant (running as root) truncate and overwrite that file with
  config-formatted content.
  
  An attacker with control over one job-template-style string field can write a
  line of their choosing into the target. Overwriting /etc/passwd with an 
injected
  UID-0 account yields root (demonstrated end-to-end, see PoC).
  
  This is a sibling of CVE-2024-5290. That issue used the same
  netdev-reachable D-Bus CreateInterface(ConfigFile=...) surface, but the sink 
was
  loading an attacker .so via opensc_engine_path; it was fixed by restricting
  loaded module paths to /usr/lib. That fix does NOT cover wpa_config_write(), 
so
  the SaveConfig -> wpa_config_write() symlink-follow sink remains open on 
current
  hostap (HEAD 2026-07-20 still uses fopen(name, "w") with no O_NOFOLLOW).
  
  Affected code
  -------------
  wpa_supplicant/config_file.c, wpa_config_write():
      tmp_name = "<name>.tmp";
      ...
      f = fopen(name, "w");         /* <- follows symlinks; no
  O_NOFOLLOW/O_EXCL */
  Reachable sinks that call wpa_config_write(wpa_s->confname, ...):
    - D-Bus: Interface.SaveConfig -> wpas_dbus_handler_save_config()
        (wpa_supplicant/dbus/dbus_new_handlers.c). The confname is set from the
        client-supplied ConfigFile in CreateInterface()
        (dbus_new_handlers.c, "ConfigFile" key).
    - Control interface: SAVE_CONFIG on an interface added via INTERFACE_ADD 
with
        an attacker-chosen confname (wpa_supplicant/ctrl_iface.c), where a 
global
        control socket (-g) is group-accessible.
  
  Reachability / who can do this
  ------------------------------
  The D-Bus path is reachable by any member of the "netdev" group on
  Debian/Ubuntu: the shipped /usr/share/dbus-1/system.d/wpa_supplicant.conf 
grants
     <policy group="netdev"> <allow send_destination="fi.w1.wpa_supplicant1"/> 
...
  (On Fedora/RHEL the D-Bus policy is root-only and there is no -g
  socket, so those
  are not affected by default.)
  
  Scope, stated honestly:
    - This is a netdev-group -> root escalation, not any-local-user -> root. A
      non-netdev user is denied by the D-Bus policy ("Access denied"), and on a
      default Ubuntu desktop no human user is in netdev (NetworkManager
  uses polkit,
      not netdev membership).
    - It matters where an administrator has placed a user in netdev (e.g. direct
      wpa_cli/wpa_gui users, appliance/kiosk images, some legacy 
configurations),
      and anywhere a group-accessible global control socket (-g) is configured.
    - netdev is intended for network configuration, not for arbitrary root file
      overwrite; that is the privilege boundary being crossed.
  
  Proof of concept (reproduced end-to-end, Ubuntu 24.04.4 LTS, wpasupplicant 
2.10)
  
--------------------------------------------------------------------------------
  As an unprivileged user "lowpriv" whose only extra group is "netdev" (no 
sudo):
    1. Pre-plant an executable at a path ending in a double-quote, e.g. /tmp/x" 
:
         printf '#!/bin/sh\nid\n' > '/tmp/x"'; chmod 755 '/tmp/x"'
    2. Write evil.conf (update_config=1) with a network whose EAP
  identity encodes a
       passwd UID-0 line; wpa appends a closing quote which the passwd shell 
field
       absorbs, so the shell becomes /tmp/x":
         identity="x:<openssl passwd -1 output>:0:0::/root:/tmp/x"
    3. Symlink evil.conf.tmp -> /etc/passwd
    4. Over D-Bus (as netdev):
         CreateInterface({Ifname: lo, Driver: wired, ConfigFile:
  /home/lowpriv/evil.conf})
         Interface.SaveConfig()      # root wpa_supplicant writes
  through the symlink
       -> /etc/passwd is overwritten and now contains the UID-0 line.
    5. su 'identity="x'  (password from step 2) -> uid=0(...) gid=0(root): root.
  The su/auth step was verified in an isolated mount namespace (unshare
  -m, bind of
  the wpa-written file over /etc/passwd) so the live system was not modified.
  Note: a live overwrite truncates /etc/passwd (fopen "w"), which is itself a 
full
  authentication-lockout DoS.
  
  Suggested fix
  -------------
  Open the temp file without following symlinks and without reusing an existing
  file, e.g.:
      int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600);
      f = (fd >= 0) ? fdopen(fd, "w") : NULL;
  (Consider O_EXCL after unlinking a stale <name>.tmp, and fstat()-verifying the
  result is a regular file owned as expected.) A patch is attached
  (wpa-fix-O_NOFOLLOW.patch). Optionally, gate the config-writing control paths
  (SaveConfig / SAVE_CONFIG with a caller-supplied ConfigFile) more tightly than
  plain netdev access.
  
  A working reproducer is available on request.

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2163513

Title:
  wpa_config_write() follows symlinks (no O_NOFOLLOW) -> arbitrary root
  file overwrite by a netdev-group user

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/wpa/+bug/2163513/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to