Тридцать по одному или один по тридцать?




How it works

Прежде чем переходить к нестандартным способам применения, расскажу, как работает keep-alive. Процесс на самом деле прост донельзя — вместо одного запроса в соединении посылается несколько, а от сервера приходит несколько ответов. Плюсы очевидны: тратится меньше времени на установку соединения, меньше нагрузка на CPU и память. Количество запросов в одном соединении, как правило, ограничено настройками сервера (в большинстве случаев их не менее нескольких десятков). Схема установки соединения универсальна:

1. В случае с протоколом HTTP/1.0 первый запрос должен содержать заголовок Connection: keep-alive.
Если используется HTTP/1.1, то такого заголовка может не быть вовсе, но некоторые серверы будут автоматически закрывать соединения, не объявленные постоянными. Также, к примеру, может помешать заголовок Expect: 100-continue. Так что рекомендуется принудительно добавлять keep-alive к каждому запросу — это поможет избежать ошибок.

Expect принудительно закрывает соединение

2. Когда указано соединение keep-alive, сервер будет искать конец первого запроса. Если в запросе не содержится данных, то концом считается удвоенный CRLF (это управляющие символы \r\n, но зачастую срабатывает просто два \n). Запрос считается пустым, если у него нет заголовков Content-Length,Transfer-Encoding, а также в том случае, если у этих заголовков нулевое или некорректное содержание. Если они есть и имеют корректное значение, то конец запроса — это последний байт контента объявленной длины.

За последним байтом объявленного контента может сразу идти следующий запрос

3. Если после первого запроса присутствуют дополнительные данные, то для них повторяются соответствующие шаги 1 и 2, и так до тех пор, пока не закончатся правильно сформированные запросы.

Иногда даже после корректного завершения запроса схема keep-alive не отрабатывает из-за неопределенных магических особенностей сервера и сценария, к которому обращен запрос. В таком случае может помочь принудительная инициализация соединения путем передачи в первом запросе HEAD.

Запрос HEAD запускает последовательность keep-alive

Тридцать по одному или один по тридцать?

Как бы забавно это ни звучало, но первый и самый очевидный профит — это возможность ускориться при некоторых видах сканирования веб-приложений. Разберем простой пример: нам нужно проверить определенный XSS-вектор в приложении, состоящем из десяти сценариев. Каждый сценарий принимает по три параметра.

Я накодил небольшой скрипт на Python, который пробежится по всем страницам и проверит все параметры по одному, а после выведет уязвимые сценарии или параметры (сделаем четыре уязвимые точки) и время, затраченное на сканирование.

import socket, time, re

print("\n\nScan is started...\n")

 

s_time = time.time()

 

for pg_n in range(0,10):

for prm_n in range(0,3):

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect(("host.test", 80))

req = "GET /page"+str(pg_n)+".php?param"+str(prm_n)+"=<script>alert('xzxzx:page"+str(pg_n)+":param"+str(prm_n)+":yzyzy')</script> HTTP/1.1\r\nHost: host.test\r\nConnection: close\r\n\r\n"

 

s.send(req)

res = s.recv(64000)

pattern = "<script>alert('xzxzx"

if res.find(pattern)!=-1:

print("Vulnerable page"+str(pg_n)+":param"+str(prm_n))

s.close()

 

print("\nTime: %s" % (time.time() - s_time))

Пробуем. В результате время исполнения составило 0,690999984741.

Локальный тест без keep-alive

А теперь пробуем то же самое, но уже с удаленным ресурсом, результат — 3,0490000248.

Неплохо, но попробуем использовать keep-alive — перепишем наш скрипт так, что он будет посылать все тридцать запросов в одном соединении, а затем распарсит ответ для вытаскивания нужных значений.

import socket, time, re

print("\n\nScan is started...\n")

 

s_time = time.time()

req = ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect(("host.test", 80))

 

for pg_n in range(0,10):

for prm_n in range(0,3):

req += "GET /page"+str(pg_n)+".php?param"+str(prm_n)+"=<script>alert('xzxzx:page"+str(pg_n)+":param"+str(prm_n)+":yzyzy')</script> HTTP/1.1\r\nHost: host.test\r\nConnection: keep-alive\r\n\r\n"

 

req += "HEAD /page0.php HTTP/1.1\r\nHost: host.test\r\nConnection: close\r\n\r\n"

s.send(req)

# Timeout for correct keep-alive

time.sleep(0.15)

res = s.recv(640000000)

pattern = "<script>alert('xzxzx"

strpos = 0

if res.find(pattern)!=-1:

for z in range(0,res.count(pattern)):

strpos = res.find(pattern, strpos+1)

print("Vulnerable "+res[strpos+21:strpos+33])

s.close()

 

print("\nTime: %s" % (time.time() - s_time))

Пробуем запустить локально: результат — 0,167000055313. Запускаем keep-alive для удаленного ресурса, выходит 0,393999814987.

И это при том, что пришлось добавить 0,15 с, чтобы не возникло проблем с передачей запроса в Python. Весьма ощутимая разница, не правда ли? А когда таких страниц тысячи?

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

Расстрел инъекциями

Пожалуй, к одной из таких частых рутинных задач можно причислить посимвольную раскрутку слепых SQL-инъекций. Если нам не страшно за сервер — а ему вряд ли будет хуже, чем если крутить посимвольно или бинарным поиском в несколько потоков, — то можно применить keep-alive и здесь — для получения максимальных результатов с минимального количества соединений.

Принцип прост: собираем запросы со всеми символами в одном пакете и отправляем. Если в ответе обнаружено совпадение с условием true, то останется только верно его распарсить для получения номера нужного символа по номеру успешного ответа.

Собираем один пакет со всеми символами и ищем в ответе выполненное условие

Это снова может оказаться полезным, если число потоков ограничено или невозможно использовать другие методы, ускоряющие процесс перебора символов.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2019-04-28 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: