August 19, 2026
Recruit — TryHackMe Walkthrough: From Local File Inclusion to Administrator
Introduction
By Yussif Selim
10 min read
Introduction
The Recruit room on TryHackMe is a great beginner-friendly machine that demonstrates how multiple vulnerabilities can be chained together to achieve complete access to an application.
What I particularly liked about this room is that the first vulnerability does not immediately give us administrator access.
Instead, we have to:
- Discover the exposed services.
- Enumerate the web application.
- Identify an API endpoint.
- Exploit a Local File Inclusion vulnerability.
- Extract HR credentials from a configuration file.
- Use those credentials to access the application.
- Discover a second vulnerability: SQL Injection.
- Enumerate the database.
- Extract administrator credentials.
- Log in as the administrator and obtain the second CTF flag.
This makes the room a great example of why penetration testing is not always about finding one critical vulnerability.
Sometimes, several smaller findings can be chained together to reach the final objective.
This walkthrough was performed against the intentionally vulnerable TryHackMe lab environment for educational purposes.
Step 1 — Discovering the Target
After starting the room, TryHackMe provided me with the target machine IP:
10.81.185.23010.81.185.230The first thing I wanted to know was:
What services are exposed on this machine?
I started with Nmap:
nmap -sV -sC 10.81.185.230nmap -sV -sC 10.81.185.230Why Nmap?
Nmap is one of the most important tools in a penetration tester's toolkit.
It allows us to discover:
- Open ports
- Running services
- Service versions
- Additional information through default scripts
What do -sV and -sC do?
-sV performs service version detection.
Instead of simply telling us that port 80 is open, it attempts to identify the software and version running behind it.
-sC runs Nmap's default scripts to gather additional information about the discovered services.
The scan revealed three interesting ports:
22/tcp
53/tcp
80/tcp22/tcp
53/tcp
80/tcpThe most interesting one at this point was obviously:
80/tcp80/tcpbecause an HTTP service means there is a web application to investigate.
Step 2 — Exploring the Web Application
Since port 80 was open, I opened the website in my browser:
http://10.81.185.230/http://10.81.185.230/I was presented with a login page for the recruitment application.
The application appeared to be related to a recruitment system, and the login page immediately became one of the main attack surfaces.
At first, I considered whether the login form might be vulnerable to SQL Injection.
I tested the input, but I couldn't find a useful SQL Injection vulnerability at this stage.
Instead of spending too much time attacking the wrong endpoint, I continued enumerating the application.
This is an important lesson:
If one attack vector does not produce useful results, don't force it. Go back to enumeration.
Step 3 — Discovering the Access API
While exploring the application, I discovered an Access API page.
The page contained documentation titled:
Recruit API - Frequently Asked QuestionsRecruit API - Frequently Asked QuestionsOne of the questions immediately caught my attention:
How can I fetch a candidate CV using the API?
The documentation provided the following endpoint:
/file.php?cv=<URL>/file.php?cv=<URL>This was interesting because the application was accepting a user-controlled value through the cv parameter.
Step 4 — Investigating the cv Parameter
I tried accessing the endpoint without providing a value for cv.
The application complained that the CV location could not be empty.
So I needed to understand what the application expected.
I then tried:
/file.php?cv=config.php/file.php?cv=config.phpThe application responded:
Only local files are allowedOnly local files are allowed
This message was extremely useful.
It told me something about the application's security logic:
The application is checking whether the requested resource is local.
At this point, I started thinking about whether this file-reading functionality could potentially be abused to access other local files.
Step 5 — Local File Inclusion Using file://
The endpoint accepted a URL-like value, so I tested the file:// protocol:
/file.php?cv=file://config.php/file.php?cv=file://config.phpThe application processed the request and returned the contents of the internal configuration file.
This confirmed that I had found a Local File Inclusion / Local File Read vulnerability.
What Is Local File Inclusion?
Local File Inclusion, commonly abbreviated as LFI, occurs when an application allows a user to control which local file is loaded or read.
For example, an insecure application might do something conceptually similar to:
file.php?cv=<user-controlled-file>file.php?cv=<user-controlled-file>If the application does not properly validate the requested file, an attacker may be able to access files that were never intended to be exposed.
The important point here is that the vulnerability isn't necessarily about executing code.
Sometimes simply being able to read sensitive files is enough to continue the attack.
And that is exactly what happened here.
Step 6 — Finding HR Credentials
The configuration file contained sensitive information.
Among the information exposed by the file inclusion vulnerability were credentials used by the HR account.
The important discovery was the HR username and password.
At this point, I had solved the first major part of the attack:
LFI
↓
config.php
↓
HR CredentialsLFI
↓
config.php
↓
HR Credentials
This demonstrates why configuration files should never contain sensitive credentials in a location that can be exposed to users.
Step 7 — Discovering the Hostname
Before continuing with web enumeration, I wanted to properly map the application's hostname.
The application was using:
recruit.thmrecruit.thmSo I added the hostname to my local /etc/hosts file.
I opened:
sudo nano /etc/hostssudo nano /etc/hostsand added:
10.81.185.230 recruit.thm10.81.185.230 recruit.thm
Why do we need this?
Our computer needs to know that:
recruit.thmrecruit.thmshould resolve to:
10.81.185.23010.81.185.230Without this local mapping, the hostname may not resolve correctly in our lab environment.
Step 8 — Directory Enumeration with Gobuster
Now that the hostname was configured, I performed directory enumeration:
gobuster dir -u http://recruit.thm -w /usr/share/wordlists/dirb/common.txtgobuster dir -u http://recruit.thm -w /usr/share/wordlists/dirb/common.txtWhy Gobuster?
Gobuster is used to discover hidden directories and files on web servers.
This is important because a website may contain endpoints that are not linked from the homepage.
The scan revealed several interesting paths.
One of them was: /mail
Step 9 — Discovering the Mail Log
I opened:
http://recruit.thm/mailhttp://recruit.thm/mailThe page led me to a mail log.
Inside the log, I found an internal email from the HR team.
The email contained a very important piece of information.
It stated that:
- The HR login username was
hr. - HR credentials were stored inside
config.php. - Administrator credentials were not stored in the application files.
- Administrator credentials were stored in the backend database.
This was a major turning point.
Step 10 — Connecting the Findings
At this point, I had two important pieces of information.
First
The LFI vulnerability allowed me to read:
config.phpconfig.phpand obtain the HR password.
Second
The mail log told me:
Username: hrUsername: hrand also revealed that:
Administrator credentials → Backend DatabaseAdministrator credentials → Backend DatabaseSo the attack path became:
LFI
↓
config.php
↓
HR Password
↓
HR Account
↓
Application Search
↓
SQL Injection
↓
Database
↓
Administrator CredentialsLFI
↓
config.php
↓
HR Password
↓
HR Account
↓
Application Search
↓
SQL Injection
↓
Database
↓
Administrator CredentialsThis is exactly why enumeration and information correlation are so important.
A single finding might not be enough.
But several findings together can create a complete attack path.
Step 11 — Logging in as HR
Using the username discovered in the email and the password obtained from the configuration file, I logged into the application.
The login was successful.
🎯 The first CTF flag was obtained.
After authentication, I was redirected to a page containing a Search Candidate functionality.
And this immediately caught my attention.
Step 12 — Testing the Candidate Search for SQL Injection
Remember the email?
It told us that administrator credentials were stored in the backend database.
Now we had a search function that almost certainly interacted with a database.
That made it worth testing for SQL Injection again.
I entered a single quote:
''The application responded with:
SQL Error:
You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version
for the right syntax to use near 'b%" at line 1SQL Error:
You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version
for the right syntax to use near 'b%" at line 1
This was a strong indication that the search parameter was being inserted into a database query without proper sanitization.
The SQL Injection hypothesis was confirme
Step 13 — Capturing the Request with Burp Suite
Instead of manually constructing requests, I used Burp Suite to capture the HTTP request generated by the search functionality.
I sent the request to Repeater so I could inspect and reproduce it.
I then saved the HTTP request to a text file:
newvuln.txtnewvuln.txtThe filename itself doesn't matter.
You can call it anything you want.
The important thing is that SQLMap can read the complete HTTP request from the file.
Why Use Burp Suite Here?
Burp Suite is extremely useful when testing web applications because it allows us to intercept and manipulate HTTP requests.
In this case, I wanted SQLMap to reproduce the exact request generated by the application.
Instead of manually reconstructing:
- HTTP method
- URL
- Parameters
- Headers
- Cookies
- Request body
I could simply give SQLMap the captured request.
Step 14 — Enumerating Databases with SQLMap
Now that I had the vulnerable request saved, I used SQLMap:
sqlmap -r newvuln.txt -p search --dbssqlmap -r newvuln.txt -p search --dbsLet's break this command down.
-r
Tells SQLMap to load the HTTP request from a file.
-r newvuln.txt-r newvuln.txt-p search
Tells SQLMap which parameter to test.
In our case:
searchsearch--dbs
Tells SQLMap to enumerate the available databases.
The result showed:
information_schema
mysql
performance_schema
phpmyadmin
recruit_db
sysinformation_schema
mysql
performance_schema
phpmyadmin
recruit_db
sys
The database that immediately interested me was:
recruit_dbrecruit_dbStep 15 — Enumerating Tables
Next, I wanted to know what tables existed inside recruit_db.
I used:
sqlmap -r newvuln.txt -p search -D recruit_db --tablessqlmap -r newvuln.txt -p search -D recruit_db --tablesThe result showed:
candidates
userscandidates
users
The users table immediately stood out.
Why?
Because our objective was to discover administrator credentials.
A table called users is therefore one of the first places I would investigate.
Step 16 — Enumerating the Users Table
Before dumping the table, I wanted to understand its structure.
I used:
sqlmap -r newvuln.txt -p search -D recruit_db -T users --columnssqlmap -r newvuln.txt -p search -D recruit_db -T users --columnsSQLMap identified three available columns.
At this point, I had enough information to proceed with database extraction.
Step 17 — Dumping the Database
Instead of manually extracting individual records, I used SQLMap to dump the available database contents:
sqlmap -r newvuln.txt -D recruit_db --dump-allsqlmap -r newvuln.txt -D recruit_db --dump-allWhy use --dump-all?
This tells SQLMap to extract all available data from the selected database.
The output revealed the information I was looking for:
Administrator credentials.
And here we go.
We now had valid administrator credentials.
Step 18 — Administrator Access
I returned to the application login page and used the administrator credentials obtained from the database.
The login was successful.
🎯 The second CTF flag was obtained.
At this point, the Recruit room was successfully completed.
Complete Attack Chain
The entire attack can be summarized as:
Target Discovery
↓
Nmap Enumeration
↓
Web Application
↓
Access API
↓
LFI / Local File Read
↓
config.php
↓
HR Password
↓
Gobuster
↓
Mail Log
↓
HR Username
↓
HR Login
↓
Candidate Search
↓
SQL Injection
↓
Burp Suite
↓
SQLMap
↓
recruit_db
↓
users
↓
Administrator Credentials
↓
Administrator Login
↓
Second CTFTarget Discovery
↓
Nmap Enumeration
↓
Web Application
↓
Access API
↓
LFI / Local File Read
↓
config.php
↓
HR Password
↓
Gobuster
↓
Mail Log
↓
HR Username
↓
HR Login
↓
Candidate Search
↓
SQL Injection
↓
Burp Suite
↓
SQLMap
↓
recruit_db
↓
users
↓
Administrator Credentials
↓
Administrator Login
↓
Second CTFWhat Did I Learn From This Room?
1. Enumeration Should Never Stop After the First Finding
At the beginning, the login page did not immediately give me anything useful.
Instead of spending all my time trying random payloads, I continued enumerating.
That eventually led me to the API and then to the LFI vulnerability.
Enumeration creates options.
2. Error Messages Can Reveal a Lot
The message:
Only local files are allowedOnly local files are allowedlooked like a security control.
But it also told me exactly what the application was trying to restrict.
Likewise, the SQL error revealed that user input was reaching the database.
Error messages can therefore become valuable reconnaissance information.
3. Information Disclosure Can Be More Dangerous Than It Looks
The configuration file did not directly give administrator credentials.
It gave me HR credentials.
But those credentials allowed me to access the application and continue the attack.
This is an important concept:
A vulnerability does not need to give you the final objective directly to be valuable.
4. Internal Files Can Reveal the Application's Architecture
The mail log was especially useful.
It told me:
- The HR username.
- Where HR credentials were stored.
- That administrator credentials were stored in the database.
An attacker can sometimes learn a tremendous amount from information that developers consider harmless.
5. Burp Suite and SQLMap Work Very Well Together
Burp Suite allowed me to capture the exact vulnerable HTTP request.
SQLMap then used that request to automate SQL Injection testing and database enumeration.
The workflow was:
Burp Suite
↓
Capture Request
↓
Save Request
↓
SQLMap
↓
Enumerate DatabaseBurp Suite
↓
Capture Request
↓
Save Request
↓
SQLMap
↓
Enumerate DatabaseThis is a very useful workflow to understand as a beginner.
6. Different Vulnerabilities Can Be Chained Together
This was probably my favorite lesson from the room.
The final compromise did not come from one vulnerability.
Instead:
LFI
+
Information Disclosure
+
Weak/Exposed Credentials
+
SQL Injection
=
Administrator AccessLFI
+
Information Disclosure
+
Weak/Exposed Credentials
+
SQL Injection
=
Administrator AccessEach finding helped unlock the next stage.
That is often how real-world attacks work.
Final Thoughts
The Recruit room was a great exercise in understanding how a penetration tester should think.
The machine initially looked simple:
A login page, an API and a few exposed services.
But after proper enumeration, the attack path started revealing itself.
The most important lesson I took from this room is:
Don't just look for vulnerabilities. Look for relationships between vulnerabilities.
A Local File Inclusion vulnerability gave me access to a configuration file.
The configuration file gave me the HR password.
The mail log gave me the HR username and revealed where administrator credentials were stored.
The HR account gave me access to the candidate search functionality.
The search functionality was vulnerable to SQL Injection.
SQL Injection gave me access to the database.
And the database finally gave me administrator credentials.
That chain of reasoning is much more important than memorizing any individual command.
Tools Used
Throughout the room, I used:
- Nmap — Network and service enumeration
- Gobuster — Directory enumeration
- Burp Suite — HTTP request interception and analysis
- SQLMap — SQL Injection testing and database enumeration
- Browser — Manual web application exploration
Each tool had a specific purpose.
The real skill is not knowing dozens of tools.
It's knowing when to use each tool and why.
Conclusion
Recruit may be a beginner-friendly TryHackMe room, but it teaches a very realistic penetration testing workflow:
Enumerate
↓
Investigate
↓
Find a vulnerability
↓
Extract information
↓
Use that information
↓
Discover another vulnerability
↓
Chain the findings
↓
Reach the objectiveEnumerate
↓
Investigate
↓
Find a vulnerability
↓
Extract information
↓
Use that information
↓
Discover another vulnerability
↓
Chain the findings
↓
Reach the objectiveAnd that's one of the biggest lessons in penetration testing:
The first vulnerability you find may not be the one that wins the machine — it may simply be the key that opens the next door.