ForwardSlash is a Hard Linux box created by InfoSecJack and chivato. It was released on April 4th, 2020 and retired on July 4th, 2020. The users rated the difficulty 6.3/10 and gave an appreciation score of 3.8/5.
We access a website defaced by a hacker group. Checking for VHOSTs, we find a backup website with a login page. We can register and log in. The vulnerable feature has been poorly disabled as we can still call it to access a developer page that is protected by IP filtering. The feature is vulnerable to LFI and we can retrieve the pages source code with a PHP wrapper. The user
chiv password is hardcoded in one of them. Once connected through SSH, we find multiples notes left by
chiv that lead us to a backup config file that should contain the old database credentials. We exploit a SUID binary
backup (owned by
pain) to read that config file and retrieve
pain password and therefore, the user flag. In
pain home folder we find an encrypted file and the script used to encrypt it. We retrieve the encryption key with a dictionary attack. It message leaks the password of a LUKS image.
pain is a sudoer and can run the commands to decrypt the image and mount it as
root. The image contains
root SSH private key that we use to get the root flag.
Reconnaissance & Enumeration
An NMAP scan shows the following (partial) output:
$ sudo nmap -sS -sV -p- 10.10.10.183
|22/tcp||open||ssh||OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)|
|80/tcp||open||http||Apache httpd 2.4.29 ((Ubuntu))|
We discover the usual SSH server and HTTP ports opened.
Browsing the IP address redirects to
http://forwardslash.htb. We add the domain to the
/etc/hosts file. We then access a website defaced by a hacker group called The Backslash Gang:
They give some hints on the vulnerabilities they exploited:
A file/folder discovery does not show much. We continue with a VHOST scan:
backup.forwardslash.htb that we add as well to the
hosts file. The backup page shows a login page:
We can sign up to access a dashboard:
There is a nice Quick Message from Chivato:
The Change Your Profile Picture feature shows a disabled input:
The vulnerability should be there and we can easily modify the HTTP code to enable the input and the button.
A new file/folder discovery shows:
/api.php (Status: 200)
/config.php (Status: 200)
/dev (Status: 301)
/environment.php (Status: 302)
/index.php (Status: 302)
/login.php (Status: 200)
/logout.php (Status: 302)
/register.php (Status: 200)
/welcome.php (Status: 302)
/dev folder shows the following message:
Access Denied From 10.10.14.94
It is probably only accessible from the localhost. We tried some well-known HTTP headers to bypass this kind of filter, but no success.
We can easily edit the input and the button HTML code to remove the
disabled attribute and then try to call
/dev/index.php that will bypass the filter. This will include the
We access an
XML API Test feature which is probably what the hacker group was referring to in its message. Let’s see what else we can do through this Local File Inclusion (LFI) vulnerability. We can read local system files:
And we can even read a page source code with PHP wrappers as follows:
We get the source code encoded in base64. Once decoded, we can read the user
chiv FTP password:
On top of that, we see as well that XML External Entities (XXE) can be processed, which is another vulnerability that can be used to read local files or, in certain cases (not here), get Remote Code Execution (RCE).
If we have a look at the test done to filter access to
/dev, we see that the IP filtering can be bypassed if we use the
admin account does not exist. We can create it and access the
/dev/index.php page without bypass. From there, we can exploit the XXE to read files as well with this payload:
<!ENTITY xxe SYSTEM “file:///etc/passwd” >]>
The FTP code leads to an RFI that we can use to trig XSS. We can query a remote FTP server for a file called
debug.txt. If we start an FTP server on our box, configure the
chiv user/password and serve a
" is important here to pass the regex filter.
Anyway…the FTP credentials are re-used for the system user. We can log in through SSH.
Local Reconnaissance & Enumeration
Now that we have a shell as
chiv we can explore the box. The user flag is in
pain home directory. We can read some more files in there. First, a
chiv that contains:
Pain, even though they got into our server, I made sure to encrypt any important files and then did some crypto magic on the key… I gave you the key in person the other day, so unless these hackers are some crypto experts we should be good to go.
Then there is a
encryptorinator folder that contains an encrypted file
ciphertext as well as the Python script used to encrypt it:
chiv mentions that he encrypted some ‘important’ files. By looking around we find another message in the backup config file
The backup config file is found in
/var/backup/config.php.bak and can only be read by
pain. We find another
note.txt along with it:
Chiv, this is the backup of the old config, the one with the password we need to actually keep safe. Please DO NOT TOUCH.
By checking for SUID binaries, we find
/usr/bin/backup owned by
pain. This looks like the way to pivot. We can execute it:
This is a backup viewer so we can probably read the
config.php.bak file with it. It seems to check for a file that does not exist and that seems to be an MD5 hash. The filename changes each time we launch the tool. Actually, it changes every second.
We find yet another
note.txt that we missed during the enumeration phase at the root of
Pain, we were hacked by some skids that call themselves the “Backslash Gang”… I know… That name…
Anyway I am just leaving this note here to say that we still have that backup site so we should be fine.
We can copy the
backup binary locally with
scp and open it with Ghidra. The main function is quite self-explanatory:
The filename is the MD5 hash of the local time with format
HH:MM:SS. That’s why it changes each second. What we can do here is to create a symlink to
/var/backup/config.php.bak with the name being the MD5 hash of the current time. We need to do that in less than a second. The following one-liner is all we need:
And we get
pain password (it is not a hash) that he re-used as well for his system account:
We log in through SSH and get the user flag.
Once logged in with
pain, we see that he can run some commands as
LUKS is a disk encryption tool, so the first guess is that there is an encrypted drive/image somewhere that we can decrypt and mount. To do that we would need a password that we don’t have yet.
We found previously an encrypted file with the script used to encrypt it. Let’s analyze the script:
Quite a basic encryption. We can easily re-use the
decrypt function to perform a dictionary attack:
We output the decryption string once we find the word
the. The output is:
We have the location of the encrypted image and the password to decrypt it. With that, we execute the following commands to decrypt and mount the image
pain is member of the group
backupoperator so he can read the image):
$ mkdir mnt
$ sudo /sbin/cryptsetup luksOpen encrypted_backup.img backup
Enter passphrase for encrypted_backup.img: cB!6%sdH8Lj^@Y*$C2cf
$ sudo /bin/mount /dev/mapper/backup ./mnt/
$ cd mnt
The image contains
root SSH private key
id_rsa. We retrieve it, log in through SSH and get the root flag!
This was quite a straightforward box, more on the Medium difficulty I would say. No insane enumeration to do so I completed it quite easily :) Except for the LUKS part, the concepts seen can be found in many other boxes.
 XML External Entity (XXE) Processing