Примеры использования HTTP заголовков для скрытой передачи данных

Надеюсь вы изучили большую справочную статью «HTTP протокол». Одним из примеров применения полученных знаний является статья «Как использовать User Agent для атак на сайты». Данная статья также содержит интересные примеры, как мы можем с пользой модифицировать передаваемые элементы HTTP сообщений.

Последующие примеры не нужно расценивать как панацею для скрытой передачи данных — скорее, это необычные примеры использования, которые помогают лучше «прочувствовать» протокол HTTP.

Зачем передавать данные в HTTP заголовках

Обычно в HTTP заголовках передаётся предсказуемая техническая информация, поэтому не все программы для ведения журналов и анализа трафика имеют функцию сохранения содержимого HTTP заголовков. Например, Apache обычно (это зависит от настройки формата логов) сохраняет такие поля HTTP заголовка как Referer и User-Agent. При желании, можно настроить Apache сохранять данные, переданные методом POST, но обычно это не делается, т. к. журналы начинают занимать слишком много места.

Что касается сохранения других полей HTTP заголовка, то это в принципе возможно, но для этого необходимо включение и настройка модуля mod_log_forensic, это тоже бывает нечасто, плюс хранение большого количества практически ненужных данных.

Поэтому определённые резоны использовать HTTP заголовки для передачи данных есть, поскольку GET запросы сохраняются практически всегда, POST запросы сохраняются редко, а HTTP заголовки не сохраняются практически никогда.

Из популярных приложений, которые используют поле HTTP заголовка для передачи данных, на вскидку можно вспомнить PhpSploit — «скрытный фреймворк для последующей эксплуатации», если коротко, то троян, бэкдор на PHP для веб-серверов.

Как передавать данные в HTTP заголовках

HTTP заголовками можно манипулировать с помощью программы cURL, у которой есть опция -H 'ЗАГОЛОВОК: ЗНАЧЕНИЕ'.

К примеру, если мы хотим передать странице localhost/headers.php заголовок с именем «Hackware» и со значением «Hello! How are you?», то достаточно выполнить следующую команду:

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

Я покажу пример обмена данных с локальным веб-сервером.

Если у вас Kali Linux (и вообще любые производные Debian), то для запуска веб-сервера выполните:

sudo systemctl start apache2.service

Если у вас Arch Linux / BlackArch, то для запуска веб-сервера выполните:

sudo systemctl start httpd.service

Теперь создайте файл headers.php. Для этого в Kali Linux:

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

В Arch Linux / BlackArch:

sudo gedit /srv/http/headers.php

И скопируйте в него следующее:

<?php

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

То есть скрипт просто выводит значение заголовка Hackware (если он получен).

Если открыть в веб-браузере адрес http://localhost/headers.php, то будет показана пустая страница — ничего не получено и, следовательно, ничего не выведено.

Давайте выполним уже рассмотренную выше команду, в которой мы передадим заголовок Hackware:

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

Обратите внимание на выведенную скриптом строку «Hello! How are you?» - это и есть отправленное значение заголовка.

Усовершенствуем наш скрипт, чтобы он отправлял ответ не в теле сообщения, а в заголовке:

<?php

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

Вновь выполняем нашу команду:

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

А в ответ получаем пустоту:

На самом деле, всё сработало как надо и ответное сообщение прислано, просто его можно увидеть только если включить показ заголовков. Добавим опцию -v:

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

Теперь мы видим и отправленный нами заголовок и полученный в ответ заголовок.

Использование произвольных методов HTTP запроса

Мы уже рассмотрели (здесь) методы GET, PUT, HEAD, OPTIONS и другие. На самом деле, в качестве метода можно указать что угодно. Метод указывается после опции -X

Не все серверы одинаково реагируют на произвольные методы, например, команда:

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

вызовет ошибку «403 Forbidden».

Команда

curl -X 'HACK' -A 'Chrome' 87.236.16.208

вызовет ошибку «501 Not Implemented».

Команда на этот же сервер, но на 443 порт вместо 80:

curl -X 'HACK' -A 'Chrome' https://87.236.16.208 -k

вызовет ошибку веб-сервера «502 Bad Gateway».

Но современные веб-серверы Apache 2.4 с настройками по умолчанию просто обрабатывают незнакомые методы как если бы это был GET.

Проверим на нашем локальном сервере:

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

Как можно убедиться, несмотря на то, что строка запроса стала такой:

MIAL /headers.php HTTP/1.1

Веб-сервер и скрипт корректно обработали этот запрос и прислали ожидаемые данные.

Кажется, что всё как обычно, но такой запрос уже невозможно найти в Wireshark по фильтру

http

Продемонстрируем это скриншотами.

Поиск по фильтру «http» после выполнения команды с запросом методом GET:


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

Всё как положено: HTTP запрос и ответ присутствуют.

Поиск по фильтру «http» после выполнения команды с запросом методом MIAL:

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

То есть ответ найден (потому что он обычный), а запрос уже нет.

Изменение кода статуса ответа и комментария статуса

В примерах выше статусом ответа был 200, и комментарий «OK».

Мы можем указать абсолютно любой статус ответа в диапазоне 100-599. Если указать статус 5xx, то веб-браузеры, поисковые системы и все остальные будут думать, что на сервере возникла ошибка — хотя на самом деле, никакой ошибки нет и наше сообщение успешно доставлено и успешно получен ответ.

Для демонстрации попробуем следующий код в нашем файле headers.php:

<?php

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"]);
}

Откроем эту страницу в веб-браузере: http://localhost/headers.php

Как будто бы всё сломано и на сервере проблемы.

Но посмотрим в командной строке:

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

Как можно увидеть, наше сообщение доставлено и процитировано в ответе.

Строка со статусом ответа включает три элемента:

  • номер HTTP версии (например, HTTP/1.1)
  • номер статуса ответа (любые цифры от 100 до 599 — если использовать другие цифры, то можно получить «настоящий» статус 5xx)
  • комментарий (например, для кода 200 комментарием является «OK») — здесь может быть что угодно

Опять меняем наш небольшой скрипт — теперь мы хотим, чтобы доставленное через HTTP заголовок сообщение выводилось прямо в строку статуса ответа:

<?php

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

Отправляем в заголовке произвольную строку:

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

И получаем её в строке статуса:

Я хотел ещё поменять строку с версией «HTTP/1.1», но средствами cURL/PHP это, видимо, сделать невозможно. В принципе, можно подключиться к Ncat и отправить какую угодно строку статуса ответа, чтобы посмотреть, как на это прореагирует HTTP клиент (но скорее всего, просто напишет, что-то в духе «получен неверный ответ»).

Как в PHP поменять заголовки и метод HTTP запроса

В этой статье мы использовали утилиту cURL. Рассмотрим вариант, когда вы работаете с cURL через PHP — типичный случай для веб-серверов.

Опции cURL в PHP устанавливаются с помощью curl_setopt. Подробную документацию вы найдёте по ссылке: https://www.php.net/manual/ru/function.curl-setopt.php

Многие заголовки имеют свои специальные названия параметров, например, CURLOPT_USERAGENT для User Agent, CURLOPT_REFERER для Referer и т. д. Но произвольные заголовки можно установить с помощью параметра CURLOPT_HTTPHEADER (смотрите документацию по ссылке выше).

Что касается использования методов, отличных от GET, то для метода POST есть специальный параметр CURLOPT_POST, для метода PUT есть CURLOPT_PUT.

Для DELETE, CONNECT, HEAD и других более редки либо просто произвольных методов запроса используйте CURLOPT_CUSTOMREQUEST следующим образом (замените «МЕТОД» на нужный вам):

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "МЕТОД");

Создадим теперь файл methods.php:

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

и скопируем в него:

<?php

$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);
}

curl_close($ch);

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

Этот скрипт делает HTTP запрос указанным методом и показывает все полученные HTTP заголовки ответа.

Файл headers.php делаем таким:

<?php

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

Запустим methods.php прямо в командной строке:

php /var/www/html/methods.php

В последнем примере мы добились:

  • cURL в скрипте PHP использует пользовательский метод запроса MIAL — можно использовать для проверки, какие методы поддерживает сервер; ещё такие запросы не обнаруживаются фильтром «http» в Wireshark.
  • ответ мы получили с произвольным комментарием в строке состояния и с заголовком с произвольным именем и содержанием.

Заключение

В первую очередь, это не инструкция по скрытности — это скорее упражнения по HTTP протоколу и практика работы с ним для закрепления изученного справочного материала «HTTP протокол». Помните, что передаваемые таким образом данные не зашифрованы и при желании их можно найти и отфильтровать в трафике.

Рекомендуется Вам:

Добавить комментарий

Ваш адрес email не будет опубликован.