# A problem in DreamHack

## Understanding IP Trust and the Dangers of `X-Forwarded-For`

While practicing some web challenges on **DreamHack**, I came across a beginner-level challenge called `whoami` – Level 1.  
Although the difficulty is low, this challenge highlights a **very common and dangerous mistake in real-world web applications**: blindly trusting client-controlled headers.

---

## Challenge Overview

The challenge provides:

* A **simple single-page web application**
    
* Two backend API endpoints:
    
    * `/whoami`
        
    * `/admin`
        
* The **backend source code**, written in **Express (Node.js)**
    

The objective is straightforward:

> **Gain admin privileges and retrieve the flag.**

At first glance, this looks trivial. However, the interesting part lies in **how the backend determines whether a user is an admin or not**.

---

## Backend Code Analysis

After reviewing the Express backend source code, one thing immediately stood out:

> **Admin access is determined based on the client's IP address.**

More specifically, the application relies on the value of the `X-Forwarded-For` HTTP header to identify the requester.

This is a classic red flag in web security.

---

## What Is `X-Forwarded-For`?

`X-Forwarded-For` is a **non-standard HTTP header** commonly used by:

* Reverse proxies (Nginx, HAProxy)
    
* Load balancers
    
* CDNs (Cloudflare, AWS ALB, etc.)
    

Its original purpose is to preserve the **original client IP address** when requests pass through one or more proxies.

Example:

```http
X-Forwarded-For: 203.0.113.42
```

With multiple proxies involved:

```plaintext
X-Forwarded-For: 203.0.113.42, 10.0.0.1, 172.16.0.5
```

By convention:

* The **first IP** is the original client
    
* The remaining IPs are intermediate proxies
    

---

## The Core Issue: Client-Controlled Headers

Here is the critical mistake made by the application:

> `X-Forwarded-For` can be fully controlled by the client.

Any user can manually set this header using tools such as:

* `curl`
    
* Burp Suite
    
* Postman
    

For example:

```plaintext
curl -H "X-Forwarded-For: 127.0.0.1" https://target/admin
```

If the backend blindly trusts this header **without verifying that the request actually came through a trusted proxy**, the access control logic is completely broken.

This type of mistake is frequently exploited to bypass:

* IP-based access control
    
* Rate limiting
    
* Geo-restrictions
    
* Anti-bot mechanisms
    

---

## Exploitation

In the *whoami* challenge, exploitation is extremely simple:

1. Send a request to the `/admin` endpoint
    
2. Manually set the `X-Forwarded-For` header to a trusted IP (e.g., `127.0.0.1`)
    
3. The backend assumes the request is from an internal or admin user
    
4. Admin access is granted
    
5. The flag is returned
    

No brute force.  
No race condition.  
Just a **logic flaw caused by misplaced trust**.

---

## Retrieved Flag

```plaintext
DH{5c36de0d635aef1f7f3002163e7d9cca005b7fb470c93d68188d48d9f317a017}
```

---

## Lessons Learned

This challenge reinforces several important security lessons:

### 1\. Never Trust Client-Supplied Headers

Headers such as `X-Forwarded-For`, `X-Real-IP`, or custom headers **should never be trusted by default**.

### 2\. Proxy Awareness Is Essential

`X-Forwarded-For` should only be used if:

* Requests come from **trusted proxy IPs**
    
* The backend explicitly validates the request source
    

### 3\. Simple Bugs Can Have Serious Impact

Even though this is a **Level 1 challenge**, the same vulnerability appears frequently in production systems.

---

## Final Thoughts

The *whoami* challenge is a great reminder that **security is often about correct assumptions rather than complex exploits**.

If you are developing or auditing web applications, always ask yourself:

> *“Who controls this data?”*

Because if the user controls it — **you should never trust it**.
