Examples of using HTTP headers for “hidden” data transfer

How to view HTTP headers

How to see HTTP headers in a web browser

This is the easiest method available on any operating system.

Press F12 in your web browser and open the page of interest. Go to the Network tab and select the connection you are interested in.

Google Chrome/Chromium:


The Response Headers come first, and then the Request Headers, although of course the request and its headers are sent first, and then the response comes.

This is a convenient method, and you do not need to worry about the HTTPS protocol – since the web browser is the final destination, it can show the already decrypted data.

How to view HTTP headers in cURL

CURL has the -I, -v, and -i options that make the utility display HTTP headers.

The difference is that the -I option means to use the HEAD method, that is, in reality, apart from the HTTP headers, nothing will be sent back. And the -v option makes the output more verbal, so the headers are included as a result. But if you send a request via HTTPS protocol, then with the -v option, the data related to the TLS handshake will also be shown – they have nothing to do with the HTTP headers. You also need to know that the -I option shows only the response headers, and the -v option shows both the Request Headers and the Response Headers.

The -i option also shows only the response headers, does not show the TLS handshake, but shows the entire response body.

An example of using the HEAD method:

curl -I https://suip.biz/ru/ -A 'Chrome'

Here “HTTP/1.1 200 OK” is the status line and everything else is the HTTP header fields.

An example of verbal output:

curl -v https://suip.biz/ru/ -A 'Chrome' > /dev/null

Headers sent to the web server have a > at the beginning, and lines received from the web server start with <.

Start lines (request line and status line) are highlighted in blue, and HTTP headers are highlighted in red.

An example of outputting headers along with the message body:

curl -i https://suip.biz/ru/ -A 'Chrome'

The -i option prints HTTP headers to standard output, and the -v option prints the headers to error output.

HTTP headers in Wireshark (only for HTTP protocol, no HTTPS)

So far we are a program that shows HTTP headers and that sends requests and receives responses were the same, so even when using the HTTPS protocol, we saw the decrypted data. However, Wireshark cannot decrypt HTTPS, so only headers for unencrypted traffic can be viewed.

Use the filter to search for HTTP messages


See the Hypertext Transfer Protocol section for the request and response headers:

The advantage of Wireshark is that in addition to looking at HTTP headers, you can use a flexible and powerful filtering system to search across header fields. See the Wireshark Filters reference article for details.

HTTP Headers in Burp Suite

Burp Suite contains proxies specifically for viewing headers. Moreover, the program has functions to modify headers and other content on the fly. But Burp Suite is a professional program that needs to be studied.

Burp Suite can handle HTTPS requests, but this requires setting up SSL certificates in a web browser.

How to send an HTTP request using the OPTIONS method and other methods

The cURL program allows you to send an HTTP request by any method, including OPTIONS, HEAD, POST, PUT, DELETE, CONNECT, TRACE, PATCH, and even any other arbitrary name.

To do this, cURL uses the -X option. This option in various protocols allows you to set the command to be executed instead of the standard one, and in the HTTP protocol allows you to specify the request method.


With cURL, you can send an OPTIONS request like this:

curl -i -X OPTIONS http://example.org/path

You can also use -v instead of -i to see more output.

An example with the -v option, in which headers are sent to the error output, while you can kill the standard output so that it does not clutter the screen:

curl -v -s -X OPTIONS > /dev/null

In the screenshot, you can see a line with a list of supported options:


This means that the request was completed correctly.


To send a simple * (instead of a path, see RFC 7231) with the OPTIONS method, you can run a command like this:

curl -v -s --request-target "*" -X OPTIONS > /dev/null

How to send an HTTP request with an arbitrary method

Using the -X option, you can send a request with any name, for example:

curl -v -s -X HACKWARE > /dev/null

The line that says “Not implemented” and the status code 501 is exactly what was expected:

< HTTP/1.1 501 Not Implemented

The -X option to cURL

The -X option, or the long version --request <COMMAND> in cURL works differently depending on the protocol it is used with.

With HTTP protocol

Sets a custom request method to use when communicating with an HTTP server. The specified request method will be used instead of the method that was otherwise used (by default, GET). Read the HTTP 1.1 specification for details and explanation. Common additional HTTP requests include PUT and DELETE, but related technologies such as WebDAV offer PROPFIND, COPY, MOVE, and others.

You usually don't need this option. All kinds of GET, HEAD, POST and PUT requests are rather invoked with special command line parameters.

This option only changes the actual word used in the HTTP request, it does not affect curl's behavior. So, for example, if you want to make a correct HEAD request, using -X HEAD will not be enough. You need to use the -I, --head option.

The method line you set with -X, --request, will be used for all requests, which if you use -L for example --location can cause unintended side effects when curl doesn't change the request method to match with HTTP 30x, response codes – and the like.

With FTP

Specifies a custom FTP command to be used instead of LIST when listing files using FTP.

With POP3 protocol

Specifies a custom POP3 command to use in place of LIST or RETR.

With IMAP protocol

Specifies a custom IMAP command to use instead of LIST.

With SMTP protocol

Specifies a custom SMTP command to use in place of HELP or VRFY.

If this option is used multiple times, the latter will be used.

Playing with HTTP headers

One of the examples of the application of the knowledge about HTTP you can find in the article “How to use User Agent to attack websites”. This article also contains interesting examples of how we can usefully modify the transmitted elements of HTTP messages.

The following examples are not to be regarded as a panacea for covert data transmission – rather, they are unusual use cases that help to better “feel” the HTTP protocol.

Why transfer data in HTTP headers

Usually, predictable technical information is conveyed in HTTP headers, so not all programs for logging and traffic analysis have the function of saving the content of HTTP headers. For example, Apache usually (it depends on the configuration of the log format) stores such HTTP header fields as Referer and User-Agent. If you want, you can configure Apache to save the data submitted by the POST method, but this is usually not done, since the log files begin to take up too much space.

As for storing other HTTP header fields, this is possible, but this requires enabling and configuring the mod_log_forensic module, this also happens infrequently, plus storing a large amount of practically unnecessary data.

Therefore, there are certain reasons to use HTTP headers for data transfer, since GET requests are saved almost always, POST requests are rarely saved, and HTTP headers are almost never saved.

Of the popular applications that use the HTTP header field to transfer data, you might recall PhpSploit – “a hidden framework for further exploitation”, in short, a PHP Trojan, backdoor for web servers.

How to transfer data in HTTP headers

The HTTP headers can be manipulated with the cURL program which has the -H 'HEADER:VALUE' option.

For example, if we want to pass to the localhost/headers.php page a header named “Hackware” with the value “Hello! How are you?”, Then just run the following command:

curl -H 'Hackware: Hello! How are you?' localhost/headers.php

I'll show you an example of exchanging data with a local web server.

If you run Kali Linux (and any Debian derivatives in general), then to start the web server run:

sudo systemctl start apache2.service

If you run Arch Linux/BlackArch, then to start the web server run:

sudo systemctl start httpd.service

Now create a headers.php file. To do this in Kali Linux:

sudo gedit /var/www/html/headers.php

On Arch Linux/BlackArch:

sudo gedit /srv/http/headers.php

And copy the following into it:


$headers = apache_request_headers();
if (isset($headers["Hackware"])) {
	echo $headers["Hackware"];

That is, the script simply outputs the value of the Hackware header (if received).

If you open http://localhost/headers.php in a web browser, a blank page is displayed – nothing was received and therefore nothing was displayed.

Let's run the command already discussed above, in which we pass the Hackware header:

curl -H 'Hackware: Hello! How are you?' localhost/headers.php

Pay attention to the line “Hello! How are you?” – this is the sent header value.

Let's improve our script so that it sends a response not in the body of the message, but in the header:


$headers = apache_request_headers();
if (isset($headers["Hackware"])) {
	header ('HackWare: I got your message: ' . $headers["Hackware"]);

We execute our command again:

curl -H 'Hackware: Hello! How are you?' localhost/headers.php

And in response we get emptiness:

In fact, everything worked as it should and a response message was sent, it just can be seen only if you enable the display of headers. Add the -v option:

curl -v -H 'Hackware: Hello! How are you?' localhost/headers.php

Now we can see both the header we sent and the header we received in response.

Using arbitrary HTTP request methods

In fact, you can specify anything as a method. The method is specified after the -X option.

Not all servers react the same to arbitrary methods, for example, the command:

curl -X 'HACK' -A 'Chrome' https://hackware.ru

will cause a “403 Forbidden” error.


curl -X 'HACK' -A 'Chrome'

will cause a “501 Not Implemented” error.

Command for the same server, but on port 443 instead of 80:

curl -X 'HACK' -A 'Chrome' -k

will cause the web server error “502 Bad Gateway”.

But modern Apache 2.4 web servers with default settings just treat unfamiliar methods as if it were GET.

Let's check on our local server:

curl -v -H 'Hackware: Hello! How are you?' -X 'MIAL' localhost/headers.php

As you can see, even though the query string is now:

MIAL /headers.php HTTP/1.1

The web server and script correctly processed this request and sent the expected data.

It seems that everything is as usual, but such a request can no longer be found in Wireshark by filter


Let's demonstrate this with screenshots.

Search using the “http” filter after executing a command with a GET request:

curl -H 'Hackware: Hello! How are you?' localhost/headers.php

Everything is as expected: HTTP request and response are present.

Search by filter “http” after executing a command with a request using the MIAL method:

curl -H 'Hackware: Hello! How are you?' -X 'MIAL' localhost/headers.php

That is, the response was found (because it is normal), but the request is no longer there.

How to change response status code and status comment

In the examples above, the response status was 200, and the comment was “OK”.

We can specify absolutely any response status in the range 100-599. If you specify the 5xx status, then web browsers, search engines and everyone else will think that an error has occurred on the server – although in fact, there is no error and our message was successfully delivered and a response was successfully received.

To demonstrate, let's try the following code in our headers.php file:


header("HTTP/1.1 599 Damn, dude, you broke everything!");

$headers = apache_request_headers();
if (isset($headers["Hackware"])) {
	header ('HackWare: I got your message: ' . $headers["Hackware"]);

Let's open this page in a web browser: http://localhost/headers.php

It looks like as if everything is broken and the server has problems.

But let's see on the command line:

curl -v -H 'Hackware: Hello! How are you?' localhost/headers.php

As you can see, our message has been delivered and quoted in the response.

The response status line has three elements:

  • HTTP version number (for example, HTTP/1.1)
  • response status number (any digits from 100 to 599 – if you use other digits, you can get the “real” 5xx status)
  • comment (for example, for code 200, the comment is “OK”) – anything can be here

Again, we change our small script – now we want the message delivered via HTTP header to be displayed directly in the response status line:


$headers = apache_request_headers();
if (isset($headers["Hackware"])) {
	header('HTTP/1.1 599 ' . 'I got your message: ' . $headers["Hackware"]);

We send an arbitrary line in the header:

curl -v -H 'Hackware: Hello! How are you?' localhost/headers.php

And we get it in the status line:

I also wanted to change the line with the “HTTP/1.1” version, but it seems impossible to do this using cURL/PHP. Basically, you can connect to Ncat and send back any response status line to see how the HTTP client reacts to it (but most likely, it will just write something like “incorrect response received”).

How to change headers and HTTP request method in PHP

In this article, we have used the cURL utility. Consider the case when you are working with cURL through PHP – a typical case for web servers.

PHP cURL options are set using curl_setopt. Detailed documentation can be found at the link: https://www.php.net/manual/function.curl-setopt.php

Many headers have their own special options names, for example, CURLOPT_USERAGENT for User Agent, CURLOPT_REFERER for Referer, etc. But arbitrary headers can be set using the CURLOPT_HTTPHEADER parameter (see the documentation at the link above).

As for using methods other than GET, there is a special parameter CURLOPT_POST for the POST method, and CURLOPT_PUT for the PUT method.

For DELETE, CONNECT, HEAD and others more rare or just arbitrary request methods use CURLOPT_CUSTOMREQUEST as follows (replace “METHOD” with the one you want):


Let's create the methods.php file now:

sudo gedit /var/www/html/methods.php

and copy to it:


$target_url = "localhost/headers.php";
$agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36';
//$referer = 'REFERER HERE';
$cookies = '';

$ch = curl_init($target_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "MIAL");
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
//curl_setopt($ch, CURLOPT_REFERER, $referer);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookies);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookies);
//curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 'true');

$response_data = curl_exec($ch);

if (curl_errno($ch) > 0) {
	die(PHP_EOL . PHP_EOL . 'Ошибка curl: ' . curl_error($ch) . PHP_EOL . PHP_EOL . print_r(curl_getinfo($ch)) . PHP_EOL . PHP_EOL);
} elseif (empty($response_data)) {
	die(PHP_EOL . PHP_EOL . 'Returned empty result: ' . print_r(curl_getinfo($ch)) . PHP_EOL . PHP_EOL);


print_r (headers_list()) . PHP_EOL;
echo $response_data . PHP_EOL;

This script makes an HTTP request with the specified method and displays all received HTTP response headers.

We make the headers.php file like this:


header('HTTP/1.1 599 ' . 'Just because we can!');
header ('HackWare: I am here!');

Let's run methods.php right on the command line:

php /var/www/html/methods.php

In the last example, we achieved:

  • cURL in PHP script uses custom MIAL request method – can be used to check which methods the server supports; yet such requests are not detected by the “http” filter in Wireshark.
  • we got the answer with an arbitrary comment in the status line and with a title with an arbitrary name and content.


First, this is not an instruction on stealth, but rather exercises on the HTTP protocol and the practice of working with it to consolidate the studied HTTP protocol reference material. Remember that data transmitted in this way is not encrypted and, if desired, can be found and filtered in traffic.

Recommended for you:

Leave a Reply

Your email address will not be published.