Как скачиваются файлы по http
Время от времени я обнаруживаю в Internet то одну, то другую полезную утилиту. Поработав с ней некоторое время, я начинаю искать самую новую версию программы. Однако не всегда есть возможность регулярно посещать соответствующие Web-узлы в поисках новых версий. Я часто пользуюсь автономным инструментом поиска вирусов Stinger компании McAfee. Единственный недостаток этого инструмента заключается в том, что компания редко обновляет Stinger и невозможно предугадать, когда появится новая версия.
downloader.exe -download
source destination
где source указывает путь к файлу, который нужно загрузить, а destination — каталог, в который следует скопировать файл. Например, команда для Stinger выглядит следующим образом:
Сравнение версий
Используемая в сценарии базовая команда Filever выглядит следующим образом:
filever.exe /A D:stinger.exe
В этой команде ключ /A указывает, что утилита не должна выводить на экран атрибуты файла. Как видно из фрагмента исходного текста в листинге 2, для извлечения информации о номере версии и числе байтов в сценарии используется команда For. Я просто объединил информацию о версии (token 4) и размере (token 6). Может возникнуть вопрос, зачем вместе с номером версии проверять и число байтов? Во-первых, разработчик мог изменить содержимое файла, но не номер версии. Во-вторых, встречаются файлы без номера версии, и не исключено, что может измениться номер версии, но не размер файла. Функция сравнения показана под меткой A в листинге 2. Предполагается, что если файл на сайте-источнике изменился, то он представляет собой новую версию.
Для пересылки почтовых вложений используется простая и гибкая утилита Blat. Во время подготовки данной статьи Blat была представлена версией 1.9.4, но данный сценарий успешно работает и с предыдущими версиями. Однако необходимо помнить о некоторых особенностях утилиты Blat. Одна из них заключается в том, что если обратиться к оперативной подсказке с помощью команды
blat /?
или
blat /help
Иногда требуется скачивать файл порциями. Причины бывают разные, например слишком “большой” объем файла, ширина канала не достаточна или сервер ограничивает объем данных для скачивания.
Спецификация определяет следующие форматы указания значений заголовка:
first-byte-pos — начальное смещение байта с которого необходимо начать (продолжить) скачивание, оно должно быть больше либо равно 0, и меньше либо равно last-byte-pos;
last-byte-pos — конечное смещение байта до которого необходимо скачать файл, оно должно быть больше либо равно first-byte-pos и при этом меньше либо равно скачиваемому размеру файла минус один (потому что это смещение, то есть индекс в массиве байтов).
Примеры
Исключительно по указанному диапазону
На подобный запрос сервер в ответ пришлёт два возможных статуса
- 206 Partial Content — файл успешно скачан частично;
- 416 Range Not Satisfiable — неудовлетворительный диапазон для скачивания.
И заголовок Content-Range в котором указан запрошенный диапазон и общий размер.
Этот заголовок сообщает что пришёл ответ на запрос с 256-512 позиции в массиве байтов из 1024 байтов.
Реализация на Java 14
Опишем интерфейс этого класса
- byte[] download(String uri, int chunkSize) — скачивает файл по указанным порциям байтов;
- Response download(String uri, int firstBytePos, int lastBytePos) — скачивает файл по указанному диапазону.
Классы WebClient и Response
Метод Response download(final String uri, int firstBytePos, int lastBytePos)
Этот метод скачивает указанный диапазон данных. Но прежде чем начать нам нужно знать сколько всего данных нам надо ожидать. Для этого необходимо сделать запрос без получения контента. Воспользуемся методом HEAD .
Метод long contentLength(final String uri)
Теперь у нас есть ожидаемая длина файла в байтах.
Метод byte[] download(final String uri, int chunkSize)
Можем приступить к написанию метода контролирующего скачивание файла по порциям. Для удобства, договоримся что размер порций будет передаваться вторым аргументом в этот метод. Хотя можно было бы придумать умный способ определения размера порций.
Определим размер файла
Начальное смещение
Конечное смещение
Скачанные данные за каждую итерацию необходимо накапливать, создадим для этого массив, размер массива нам уже известен.
Размер скачанных данных
Дополнительно к самому массиву необходимо определять суммарно сколько данных скачано.
Поэтому эту длину будем считать отдельно.
Цикл скачивания
Условие цикла простое: продолжаем скачивать пока не достигнем ожидаемого размера. После того как успешно скачали очередную порцию данных, необходимо его прочитать и сохранить в результирующий массив, воспользуемся системным методом копирования массива System.arraycopy() . Затем нужно увеличить количество прочитанных данных и следующий диапазон скачиваемых данных. При увеличении диапазона нужно быть осторожнее, нельзя выходить за пределы. Поэтому будем брать минимальное значение из Math.min(lastBytePos + chunkSize, expectedLength - 1) .
На вид всё хорошо. Что не так?
Когда при скачивании или чтении что-то пойдет не так, броситься I/O исключение и скачивание прекратиться. Отсутствуют fallback. Давайте напишем простой fallback ввиде количества совершенных попыток.
Определим поле для веб-клиента содержащий максимальное количество допустимых попыток скачивания файла.
Будем ловить отдельно каждое исключение и инкрементировать локальный счетчик попыток. Цикл скачивания должен остановиться если количество совершенных попыток превышает допустимое. Поэтому дополним условие цикла.
Дополним метод еще логами. Окончательный вариант выглядит так:
Тестирование
Сохраним файл во временную директорию. И проверим размер файла.
Заключение
В этой статье было рассмотрено каким образом реализовать скачивание файла заранее заданными порциями. Для большей гибкости можно подумать о динамическом размере порций, который расширяется и сужается в зависимости от поведения сервера. Также до конца не покрыты возможные исключения, которые можно обработать иначе. Например ошибка 401 Unauthorized или 500 Internal Server Error .
В качестве домашнего задания код можно доработать так, чтобы не выполнять первый запрос на получение размера файла. Также можно реализовать приостановку и возобновление.
Этичный хакинг и тестирование на проникновение, информационная безопасность
Это небольшая шпаргалка, как скопировать файлы с уже скомпрометированной системы. Типичные ситуации:
- на веб сайте найдена уязвимость Удалённое выполнение кода
- получены учётные данные пользователя, позволяющие подключиться по SSH (например, с помощью брут-форса)
Я перечислю несколько способов, как скопировать файл с сервера, я не сомневаюсь, что вы сможете придумать ещё столько же или больше (кстати, делитесь ими в комментариях), выбор конкретного способа зависит от условий и от личных предпочтений.
Условия могут быть разные:
1. cat + копирование с экрана/браузера
Простейший способ, с помощью команды cat выводится содержимое файла. Он подходит только для текстовых файлов. При выполнении команды по SSH, содержимое файла выводится в консоли, при выполнении через уязвимое веб-приложение, содержимое файла выводится на странице сайта:
Если делаете через выполнение команд в веб-браузере, то для нормального отображения откройте исходный код веб-страницы:
2. base64 + копирование с экрана/браузера
Этот способ похож на предыдущий, его можно применять для скачивания бинарных файлов, если другой возможности нет.
Для понимания сути, изучите следующие команды:
Содержимое исполнимого файла /usr/bin/ls (команда ls) кодируется в Base64 и сохраняется в файл ls.txt:
Можно посмотреть, что в файле ls.txt размещён текст, который можно скопировать/вставить:
Теперь этот текст декодируем и сохраняем в файл ls.bin:
С помощью команды chmod делаем файл ls.bin исполнимым:
Проверяем работоспособность этого файла:
Суть в том, что с помощью base64 можно копированием-вставкой передавать бинарные файлы без возможности выгрузить их с сервера другим способом.
3. Помещение файла в директорию сайта и скачивание с веб-сервера
Допустим, папка сайта это /var/www/html/, тогда копируем нужный нам файл в неё следующей командой:
Чтобы узнать текущую папку, где выполняется уязвимый скрипт, выполните команду pwd:
Типичные папки с сайтами:
/etc/apache2/ — директория с настройками веб-сервера (когда служба называется apache2 — то есть в таких системах как Debian и производных)
Если неизвестно где папки сайтов, то нужно смотреть конфигурационные файлы Apache, там же можно узнать адрес сайта, если вдруг вы его не знаете (такое может быть, если сервер скомпрометирован по SSH):
Чтобы посмотреть, запущен ли вообще веб-сервер:
Если файлов много, то их можно заархивировать:
Если программа zip недоступна, то используйте tar:
Или другие программы для архивации, для этого смотрите также «Работа с архивами в Linux».
4. cURL + POST
Этот способ не требует наличия веб-сервера и, по идее, должен работать также и на Windows, поскольку там cURL предустановлена по умолчанию.
Суть очень проста. Каждый из нас множество раз выгружал файлы с компьютера на сайт, например, фотографию для профиля или файл в файлообменник. Мы используем веб-браузер, который методом POST отправляет файл. Вместо браузера можно отправлять файл с помощью команды curl, которая также умеет использовать метод POST.
На сервере создайте файл uploader.php:
С компьютера, с которого нужно выгрузить файл, запустите команду вида:
Обратите внимание на символ @ - он нужен для того, чтобы параметру file было присвоено не значение строки «/путь/до/файла», а содержимое того самого файла, который находится по пути /путь/до/файла.
Если у вас серый IP адрес (к которому невозможно подключиться из Интернета), то в этой ситуации поможет программа ngrok. То есть в предыдущей команды вместо СЕРВЕР/uploader.php можно указать домен третьего уровня ngrok, от которого идёт туннель к вашему локальному веб-серверу.
5. ngrok
Программа ngrok отсутствует по умолчанию, поэтому нужно начать с установки:
Не забудьте заменить ВАШ_AUTHTOKEN на настоящее значение.
Эта долгая установка точно стоит своих усилий, дело в том, что теперь можно сделать сетевой абсолютно ЛЮБУЮ папку на компьютере Linux! Например:
6. Встроенный сервер PHP
У PHP есть встроенный веб сервер. Сам PHP довольно часто присутствует на компьютерах Linux, а если это веб-сервер, то присутствует практически всегда.
Нужно запускать командой вида:
В качестве IP нужно указать IP адрес удалённого компьютера, узнать его можно командой:
PORT можно указать любой, но для использования портов ниже 1024 нужны привилегии суперпользователя.
7. SSH и перенаправление вывода на текущую систему
SSH можно использовать для копирования текстовых файлов:
А также и для копирования бинарных файлов:
8. scp
Программа scp является частью SSH и предназначена специально для копирования файлов в любом направлении. То есть если у вас есть возможность подключиться по SSH, то намного удобнее воспользоваться scp.
Вид команды для копирования с удалённого компьютера на локальный компьютер:
9. Сетевая файловая система SSHFS
Если у вас есть возможность подключиться по SSH, то вы можете смонтировать удалённую файловую систему как свою локальную командой вида:
10. Ncat, Netcat, nc
На HOST1 выполните:
На HOST1 запустите:
И на HOST2 выполните:
11. Бэкдоры
Самый распространённый вариант для веб-серверов. Можно скачать бэкдор с веб-интерфейсом:
А можно использовать более привычные шеллы с обфускацией и сокрытием передаваемых запросов от логов веб-сервера.
Больше подробностей смотрите по ссылкам:
Заключение
Конечно, способов скачать файл с удалённого компьютера через шелл или уязвимость веб сайта намного больше. Пишите в комментариях свои любимые способы!
когда я отправляю такую простую форму с прикрепленным файлом:
давайте посмотрим, что происходит, когда вы выбираете файл и отправляете свою форму (я усек заголовки для краткости):
вместо URL-адреса, кодирующего параметры формы, параметры формы (включая данные файла) отправляются в виде разделов в составном документе в теле запроса.
В приведенном выше примере, вы можете увидеть вход MAX_FILE_SIZE со значением, установленным в форме, а также раздел, содержащий данные файла. Имя файла является частью the Content-Disposition заголовок.
как он отправляет файл внутри?
- добавить еще несколько ссылок HTML5
- объяснить почему он прав с формой представить пример
в HTML5 ссылки
как генерировать примеры
как только вы видите пример каждого метода, становится очевидным, как они работают, и когда вы должны использовать каждый из них.
вы можете привести примеры, используя:
сохранить форму до минимума :
создание файлов для загрузки:
запустите наш маленький эхо-сервер:
nc печатает полученный запрос.
протестировано на: Ubuntu 14.04.3, nc BSD 1.105, Firefox 40.
multipart/form-data
в Firefox отправлено:
для бинарных файл и текстовое поле, байты 61 CF 89 62 ( aωb в UTF-8) отправляются буквально. Вы можете проверить это с помощью nc -l localhost 8000 | hd , в котором говорится, что байты:
были направлены ( 61 = = 'a' и 62 = = 'b').
поэтому ясно, что:
Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266 задает тип содержимого multipart/form-data и говорит, что поля разделены с учетом boundary строку.
каждое поле получает некоторые подзаголовки перед его данными: Content-Disposition: form-data; , поле name , the filename , а затем данные.
сервер считывает данные до следующей граничной строки. Браузер должен выбрать границу, которая не будет отображаться ни в одном из полей, поэтому граница может варьироваться между запросами.
поскольку у нас есть уникальная граница, кодирование данных не требуется: двоичные данные отправляются как есть.
Content-Type автоматически определяется браузером.
как именно определяется был задан вопрос:как тип MIME файла определяется браузер?
application / x-www-form-urlencoded
изменить enctype to application/x-www-form-urlencoded , перезагрузить браузер, и повторите.
в Firefox отправлено:
очевидно, что данные файла не были отправлены, только базовые имена. Таким образом, это не может быть использовано для файлов.
как для текстового поля, мы видим, что обычные печатные символы, такие как a и b были отправлены в одном байте, в то время как непечатаемые, такие как 0xCF и до 3 байт каждая: %CF%89 !
сравнение
загрузка файлов часто содержит много непечатаемых символов (например, изображений), в то время как текстовые формы почти никогда не делают.
из примеров мы видели, что:
application/x-www-form-urlencoded : имеет границу одного байта на поле ( & ), но добавляет линейный коэффициент накладных расходов 3x для каждого непечатаемого символа.
поэтому, даже если бы мы могли отправлять файлы с application/x-www-form-urlencoded , мы бы не хотели, потому что это так неэффективно.
но для печатаемых символов для текстовых полей, это не имеет значения и генерирует меньше накладных расходов, поэтому мы просто используем он.
в приведенных ответах / примерах файл (скорее всего) загружается с помощью HTML-формы или с помощью FormData API. Файл является только частью данных, отправленных в запросе, следовательно, multipart/form-data Content-Type заголовок.
если вы не (хотите) использовать формы, и вас интересует только загрузка одного файла, это самый простой способ включить ваш файл в запрос.
у меня есть этот пример кода Java:
и у меня есть этот тест.HTML-файл:
и, наконец, файл я буду использовать для тестирования, с именем а.дат имеет следующее содержание:
если вы интерпретируете байты выше как символы ASCII или UTF-8, они фактически будут представлять:
Итак, давайте запустим наш Java-код, откройте
39) Выгрузка файлов по HTTP описана в RFC-1867. Этот механизм позволяет выгружать большие файлы, используя бинарное кодирование передаваемых данных. Для этой цели используется тип кодировки "multipart/form-data".
Простая HTML-форма с возможностью выгрузки файлов показана в примере кода ниже. Бинарный тип кодирования устанавливается заданием атрибута enctype формы со значением "multipart/form-data":
В строке 1 мы явно задаем кодирование "multipart/form-data" (атрибут `enctype) для использования эффективного бинарного кодирования передачи данных формы.
В строке 2 мы определяем поле ввода с типом "file" и именем "myfile". Это поле позволит посетителям сайта выбирать файл для выгрузки.
Если вы сохраните представленную выше разметку в файл .html и откроете его в своем браузере, вы увидите страницу как на рисунке 10.1.
Рисунок 10.1. Простая HTML-форма с возможностью выгрузки файлов
Строка 5 устанавливает заголовок Content-Type" со значением "multipart/form-data". Форма собирается из полей, отмеченных "границами" -- уникальными случайно сгенерированными последовательностями символов, отделяющими поля формы друг от друга.
По умолчанию, настройки PHP-движка не позволяют выгружать большие файлы (больше 2МБ). Для выгрузки таких файлов нужно изменить файл конфигурации php.ini, а также параметры post_max_size и upload_max_filesize . О том, как это сделать, можете прочитать в Приложение А. Организация среды веб-разработки.. Установив эти настройки на 100M позволит выгружать на сервер файлы размером до 100 Мб, и этого, как правило, будет достаточно. Если вы планируете выгрузку очень больших файлов вплоть до 1 ГБ, лучше задайте в настройках 1024М. Не забудьте перезапустить веб-сервер Apache после изменения файла конфигурации.
10.1.2. Суперглобальный массив $_FILES в PHP
При выгрузке посетителем сайта файлов на ваш веб-сервер Apache, эти файлы помещаются во временное хранилище (обычно в системный временный каталог - /tmp в Linux и C:\Windows\Temp в Windows). PHP-скрипт принимает информацию о файле в специальный суперглобальный массив $_FILES .
Массив $_FILES аналогичен суперглобальным $_GET и $_POST . Два последних используются для хранения переменных GET и POST соответственно, в то время как первый используется для хранения информации о выгружаемых на сервер файлах.
Например, для вышеупомянутой формы выгрузки суперглобальный массив $_FILES будет выглядеть следующим образом (выходные данные генерируются с помощью PHP-функции var_dump() ):
Как видите из этого примера, массив $_FILES содержит запись для каждого выгружаемого на сервер файла. Для каждого файла он содержит следующую информацию:
- name -- исходное имя файла (строка 4).
- type -- MIME-тип 41 файла (строка 5).
- tmp_name -- временное имя для выгружаемого файла (строка 6).
- error -- код ошибки, сигнализирующий о статусе выгрузки (строка 7); нулевой код ошибки означает, что файл был корректно выгружен на сервер.
- size -- размер файла в байтах (строка 8).
41) MIME-тип (Multipurpose Internet Mail Extension - Многоцелевое расширение почты Интернета), также известный как "тип содержимого" - стандартный идентификатор, используемый в Интернете для указания типа данных, которые содержит файл. Например, MIME-тип "text/plain" присваивается текстовому файлу, а MIME-тип "application/octet-stream" - бинарному.
PHP-движок хранит выгруженные файлы во временном хранилище, которое очищается, как только завершается выполнение PHP-скрипта. Таким образом, если вы хотите сохранить выгруженные на сервер файлы в какой-нибудь каталог для дальнейшего использования, нужно воспользоваться PHP-функцией move_uploaded_file() . Она принимает два аргумента: первый - это имя временного файла, а второй - имя файла назначения.
Вы, наверное, не понимаете, почему нельзя использовать обычную PHP-функцию rename() , чтобы переместить временный выгруженный файл в его путь назначения. Специальная функция для перемещения выгруженных на сервер файлов существует в PHP из соображений безопасности. Функция move_uploaded_file() аналогична функции rename() , за исключением того, что она делает дополнительные проверки для гарантии того, что файл на самом деле был передан через метод запроса POST и что процесс выгрузки на сервер завершился без ошибок.
Следующий фрагмент кода показывает, как перемещать файл, выгруженный на сервер с помощью простой формы, которую мы рассмотрели выше:
В строке 1 этого примера мы задаем $destPath - имя каталога, куда нужно сохранить выгруженный файл.
В строке 2 мы вызываем функцию move_uploaded_file() и передаем ей два аргумента: путь к временному файлу и путь назначения.
Передача имени каталога в качестве второго аргумента функции move_uploaded_file() подходит для тех случаев, когда вы не хотите переименовывать файл. Если вам нужно сохранить выгруженный файл под другим именем, можете вместо имени директории указать полный путь к файлу.
В строке 3 мы проверяем возвращаемое значение функции. При успешной операции функция вернет true . Если произошли какие-либо ошибки (например, если прав доступа к каталогу недостаточно для сохранения файла), вернется булевое false .
Читайте также: