1. Overview
Often associated with malicious activity, IP spoofing can also be a valuable tool for legitimate testing scenarios. It allows us to simulate requests from different IP addresses, helping us to evaluate server responses to different sources. This is critical for testing security measures, geo-IP functionality, and specific server configurations.
In this tutorial, we’ll see how to perform IP spoofing for testing purposes on Linux using cURL, a versatile command line tool for transferring data using various protocols. We’ll assume that we have full control over both the client and the server to ensure that all activities remain within legal and ethical boundaries.
2. Setting up the Environment
Before we get into the practical aspects of IP spoofing for testing, it’s important to set up our environment correctly. This includes installing the necessary tools on our Linux system and preparing a server where we can perform our tests safely and effectively.
2.1. Installing cURL
To install cURL, the process is slightly different depending on the distribution we’re using. On Debian-based systems, such as Ubuntu and Linux Mint, we can use apt:
$ sudo apt update
$ sudo apt install curl
Instead, on Fedora-based systems such as Red Hat Enterprise Linux, we can use dnf:
$ sudo dnf install curl
In general, even in other distributions that use different package managers, installing cURL is very easy and is often already installed.
2.2. cURL Protocols
Once installed, we can take a look at what protocols are supported by our cURL installation:
$ curl --version # Linux Mint
[...]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
[...]
$ curl --version # Fedora
Protocols: file ftp ftps http https
The list of protocols supported by cURL depends on how it was compiled in the distribution we’re using. We’ll be using a non-SSL web server as our target, so the http protocol is sufficient for our tests.
However, if we need to test with a protocol that our precompiled version of cURL doesn’t support, manual compilation allows us to make customizations, including enabling or disabling specific protocols.
2.3. Preparing the Server
For our tests, we’ll use an Ubuntu Server 22.04 LTS installed on a VPS, with access via SSH and the public IP address 78.141.223.169.
First, let’s install the Apache web server, a popular choice for its simplicity and robustness:
$ sudo apt update
$ sudo apt install apache2
Next, let’s verify that Apache is running properly:
$ sudo service apache2 status
[...]
Active: active (running) [...]
[...]
Let’s also check if Apache is reachable in a web browser at the public IP of the server, in this case, http://78.141.223.169/. If we don’t see the default Ubuntu Apache web page, the connection may be blocked by a firewall. This is indeed our case, as the VPS provider preinstalled UFW and configured it to block all connections except SSH:
$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
Then let’s add a rule to allow http connections:
$ sudo ufw allow http
Rule added
Rule added (v6)
$ sudo ufw reload
Firewall reloaded
$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
80/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
After this modification to the firewall, Apache is reachable. If this isn’t sufficient or applicable in our case, we need to consult our provider’s documentation.
2.4. Configuring the Server to Trust Headers
In this step, we’ll focus on configuring our Apache server to trust the X-Forwarded-For header. This configuration is critical for accurately simulating IP addresses via cURL for testing purposes.
The X-Forwarded-For header is a standard header used by proxies and load balancers to forward the original IP address of a client connecting to a web server. In such scenarios, the server sees the intermediary’s IP address instead of the client’s, but the X-Forwarded-For header helps preserve the original client’s IP address for further processing or logging.
The proxy can be placed close to the web server, or close to the client, or in much more complex configurations than the one shown here:
In practice, networks can have multiple layers of proxies and load balancers, each potentially adding their own information to the X-Forwarded-For header.
By default, however, Apache doesn’t consider the X-Forwarded-For header because it has serious security implications. For example, fraudulent X-Forwarded-For header values can result in rate-limiting bypass, access control evasion, memory exhaustion, or other negative security or availability impacts.
That said, let’s open the Apache configuration file for editing:
$ sudo nano /etc/apache2/apache2.conf
Let’s add the RemoteIPHeader directive to the end of the file to tell Apache to trust and use the IP address specified in the X-Forwarded-For header:
RemoteIPHeader X-Forwarded-For
After saving and closing the file, let’s enable the mod_remoteip module and restart Apache:
$ sudo a2enmod remoteip
Enabling module remoteip.
[...]
$ sudo service apache2 restart
$ sudo service apache2 status
[...]
Active: active (running) [...]
[...]
With these changes, Apache now trusts and uses the IP address of the X-Forwarded-For header.
3. Testing With Modified Headers
Having configured our Apache server on Ubuntu Server 22.04 to trust the X-Forwarded-For header, we’re now ready to test how our server handles requests with modified IP addresses. This phase is critical for validating the server’s response to different sources, which is especially important for security and geo-based configurations.
3.1. Real-Time View of Apache Access Logs
In the server terminal, let’s monitor Apache logs in real-time with tail to instantly see the IP of requesting clients:
$ sudo tail -f /var/log/apache2/access.log
[...]
In the client terminal, let’s first check what our public IP is. We can get it from ifconfig.me and print it to the terminal, adding a line break at the end for better formatting:
$ curl -w "\n" ifconfig.me
1.47.75.222
Then, let’s make a request to the server, ignoring any output or error messages:
$ curl http://78.141.223.169/ > /dev/null 2>&1
In the server terminal, we see this new log appear immediately:
1.47.75.222 - - [30/Nov/2023:11:58:45 +0000] "GET / HTTP/1.1" 200 10926 "-" "curl/7.81.0"
The result is as expected since the server logged our client IP. Let’s move on to IP spoofing.
3.2. Sending a Request With a Modified Header
Our goal here is to send a request to our server 78.141.223.169 while pretending to come from a different IP than our client, 1.47.75.222.
So let’s simulate fake requests from clients 34.80.50.101 and 1.2.3.4:
$ curl -H "X-Forwarded-For: 34.80.50.101" http://78.141.223.169 > /dev/null 2>&1
$ curl -H "X-Forwarded-For: 1.2.3.4" http://78.141.223.169 > /dev/null 2>&1
As a result, we have these two server logs:
34.80.50.101 - - [30/Nov/2023:14:14:48 +0000] "GET / HTTP/1.1" 200 10926 "-" "curl/7.81.0"
1.2.3.4 - - [30/Nov/2023:14:14:58 +0000] "GET / HTTP/1.1" 200 10926 "-" "curl/7.81.0"
So, we’ve successfully spoofed the IP.
3.3. A Real World Example
To provide a practical context for our IP spoofing tests, let’s extend our server setup to support PHP and create a script that responds differently depending on the IP address. This example illustrates how IP spoofing can be useful in testing server behavior under different user scenarios.
First, we need to install PHP on our Ubuntu Server:
$ sudo apt update
$ sudo apt install php libapache2-mod-php
$ sudo service apache2 restart
Now, let’s create a PHP script that changes its response based on the IP address:
- It displays a special message if the IP is 34.12.3.211 (simulating an administrator’s IP)
- For other IP addresses, it identifies the country associated with the IP and displays a generic user message
We’ll use an external service like ip-api.com to determine the country for the IP address. In real-world contexts, we may use this country information to provide different content based on country or to allow access only from certain countries.
So, let’s create the file /var/www/html/ipcheck.php:
<?php
$ip = $_SERVER['REMOTE_ADDR'];
if ($ip == '34.12.3.211') {
echo "You are the administrator, welcome.\n";
} else {
$json = file_get_contents("http://ip-api.com/json/{$ip}");
$data = json_decode($json, true);
$country = $data['country'] ?? 'unknown';
echo "You are a normal user, for you I serve the content intended for {$country}.\n";
}
To test this setup, we use cURL to send requests with different IPs:
$ curl -H "X-Forwarded-For: 34.12.3.211" http://78.141.223.169/ipcheck.php
You are the administrator, welcome.
$ curl -H "X-Forwarded-For: 203.0.113.5" http://78.141.223.169/ipcheck.php
You are a normal user, for you I serve the content intended for United States.
$ curl -H "X-Forwarded-For: 65.9.95.99" http://78.141.223.169/ipcheck.php
You are a normal user, for you I serve the content intended for Ireland.
$ curl -H "X-Forwarded-For: 149.28.149.191" http://78.141.223.169/ipcheck.php
You are a normal user, for you I serve the content intended for Singapore.
This example demonstrates the usefulness of IP spoofing in testing, as we can validate how our server handles various IP-based content delivery and restrictions.
4. Conclusion
In this article, we discussed the use of cURL for IP spoofing on a Linux server running Apache. After installing and configuring the necessary tools, we prepared the server environment and integrated PHP support. Our setup demonstrated the practical applications of IP spoofing in testing scenarios.
Our journey included learning how to simulate different IP addresses using cURL and the X-Forwarded-For header. We also looked at the proper server configuration to trust and use these headers effectively.
IP spoofing allows us to evaluate a server’s response to different types of users, from administrators to geographically diverse users. Often misunderstood as a tool for malicious purposes only, IP spoofing is a valuable resource in server management and security testing.