Всем привет, меня зовут Сяолинь.
Вчера читатель задал мне этот вопрос:
Это, вероятно, означает, что установленное TCP-соединение, клиент не работает посередине, и сервер не имеет данных для отправки в это время, и он был в состоянии установления.После восстановления клиента он устанавливает соединение с сервером. В это время сервер будет Как с этим бороться?
Читатели, которые видели мою иллюстрированную сеть, знают, что TCP-соединение однозначно подтверждается «четверкой».
Затем в этом сценарии IP-адрес клиента, IP-адрес сервера и порт назначения не изменились, поэтому ключ к этой проблеме зависит от того, совпадает ли исходный порт в пакете SYN, отправленном клиентом, с исходным портом последнего соединения. .
1. Номер порта в SYN-сообщении клиента отличается от исторического соединения.
Если номер порта источника в сообщении SYN, отправленном клиентом после восстановления, отличается от номера порта источника предыдущего соединения, сервер будет считать, что должно быть установлено новое соединение, поэтому он установит новое соединение через три рукопожатие. .
Что произойдет с сервером в состоянии установления при старом соединении?
Если сервер отправляет пакет данных клиенту, поскольку соединение клиента было закрыто, ядро клиента вернет сообщение RST, и сервер разорвет соединение после его получения.
Если сервер не отправил пакеты данных клиенту, через некоторое время будет активирован механизм TCP keep-alive, после обнаружения того, что клиент неактивен, сервер разорвет соединение.
2. Номер порта в сообщении SYN клиента совпадает с историческим соединением.
Если номер порта источника в сообщении SYN, отправленном клиентом, совпадает с номером порта источника последнего соединения после восстановления клиента, то есть сервер в состоянии установления получает сообщение SYN.
Как вы думаете, что сервер будет делать в это время?
- Отбрасывать пакеты SYN?
- Ответить на сообщение RST?
- Ответить на сообщение ACK?
Когда я впервые увидел этот вопрос, я понятия не имел, потому что раньше не обращал на него внимания, и этот вопрос нельзя было угадать, поэтому я прочитал спецификацию RFC и исходный код ядра Linux и, наконец, узнал ответ.
Мне плевать, я сначала отвечу прямо.
Если сервер в состоянии «установить» получает сообщение SYN от клиента (обратите внимание, что сообщение SYN в это время фактически не соответствует порядку, поскольку порядковый номер инициализации сообщения SYN на самом деле является случайным числом), он ответит сообщением SYN. сообщение ACK с номером и номером подтверждения, этот ACK называется Challenge ACK.
Затем клиент получает запрос ACK и обнаруживает, что серийный номер не соответствует ожидаемому, поэтому возвращает сообщение RST.После того как сервер его получает, он разрывает соединение.
Объяснение документа RFC
Этот пример упоминается на странице 34 документа rfc793.
Я также разместил оригинальное объяснение для всеобщего обозрения.
- When the SYN arrives at line 3, TCP B, being in a synchronized state,
and the incoming segment outside the window, responds with an acknowledgment indicating what sequence it next expects to hear (ACK 100).
- TCP A sees that this segment does not acknowledge anything it
sent and, being unsynchronized, sends a reset (RST) because it has detected a half-open connection.
- TCP B aborts at line 5.
- TCP A willcontinue to try to establish the connection;
Я не буду переводить вслепую, смысл аналогичен объяснению, которое я объяснял ранее на китайском языке.
Анализ исходного кода
Если сервер в состоянии install получает сообщение SYN от клиента, ядро вызовет следующие функции:
tcp_v4_rcv
-> tcp_v4_do_rcv
-> tcp_rcv_established
-> tcp_validate_incoming
-> tcp_send_ack
Мы сосредоточимся только на том, как функция tcp_validate_incoming обрабатывает SYN-пакеты.Упрощенный код выглядит следующим образом:
Как видно из приведенной выше реализации кода, сервер в состоянии install сначала определит, есть ли серийный номер в окне после получения сообщения, если нет, то проверит, установлен ли флаг RST, если да, то сбросит . Затем, если нет флага RST, он определит, есть ли флаг SYN, если есть флаг SYN, он перейдет к метке syn_challenge, а затем выполнит функцию tcp_send_challenge_ack.
В функции tcp_send_challenge_ack функция tcp_send_ack будет вызываться для ответа на сообщение ACK с правильным серийным номером и номером подтверждения.
Как закрыть TCP-соединение?
Вопрос вот такой вопрос, как закрыть TCP соединение?
Может быть, первая реакция каждого — «убить процесс», верно?
Да, это самый грубый способ, убийство клиентского процесса и серверного процесса по-разному повлияет на область видимости:
- Если клиент завершает процесс, будет отправлено сообщение FIN для отключения всех TCP-соединений, установленных между клиентским процессом и сервером.Этот метод влияет только на соединения, установленные клиентским процессом и другими клиентами.В противном случае процесс не будет затронут .
- Уничтожение процесса на сервере будет иметь большее влияние.В это время все соединения TCP будут закрыты, и сервер не сможет продолжать предоставлять услуги доступа.
Поэтому закрывать процесс не рекомендуется, лучше всего закрыть определенное TCP-соединение.
Некоторые друзья могут сказать, что недостаточно подделать RST-сообщение с той же четверкой?
Эта идея очень хороша, но не забывайте, что есть еще одна проблема с серийным номером, будет ли принят серийный номер вашего поддельного RST-сообщения другой стороной?
Если порядковый номер пакета RST не может попасть в скользящее окно другой стороны, пакет RST будет отброшен другой стороной, и эффект закрытия соединения не будет достигнут.
так,Чтобы подделать RST-сообщение, которое может закрыть TCP-соединение, должны одновременно выполняться два условия: «четверка одинакова» и «порядковый номер попадает в скользящее окно другой стороны».
Трудно напрямую подделать порядковый номер, который соответствует ожиданиям, потому что, если TCP-соединение передает данные, скользящее окно все время меняется, поэтому трудно подделать сообщение RST с порядковым номером, который просто попадает в допустимые пределы. раздвижное окно другой стороны.
Есть еще способ,Мы можем подделать SYN-пакет с той же четверкой, чтобы получить «законный» порядковый номер!
Как мы узнали в начале, если сервер в состоянии install получает SYN-сообщение с той же четверкой,Он ответит вызовом ACK. «Номер подтверждения» в этом сообщении ACK — это именно тот серийный номер, который сервер хочет получить в следующий раз. Грубо говоря, этот шаг можно использовать для получения серийного номера, который ожидает сервер. получать дальше.
Затем используйте этот номер подтверждения в качестве серийного номера сообщения RST и отправьте его на сервер.В это время сервер будет думать, что серийный номер в сообщении RST является допустимым, поэтому он разорвет соединение!
В Linux есть инструмент killcx, основанный на описанном выше методе: он будет активно отправлять пакет SYN для получения номера SEQ/ACK, а затем использовать номер SEQ/ACK для подделки двух сообщений RST для отправки клиенту. и службы соответственно.Таким образом, как активные, так и неактивные TCP-соединения могут быть уничтожены.
Использование также очень простое, просто укажите IP-адрес клиента и номер порта.
./killcx <IP地址>:<端口号>
Принцип работы инструмента killcx показан на следующем рисунке.
Он подделывает клиента для отправки сообщения SYN, и после того, как сервер его получит, он ответит сообщением ACK (Challenge ACK) с правильным «серийным номером и номером подтверждения», а затем он может использовать информацию в сообщении ACK для подделать два сообщения RST:
- Используйте номер подтверждения в запросе ACK, чтобы подделать сообщение RST и отправить его на сервер, и сервер разорвет соединение после получения сообщения RST.
- Используйте серийный номер в запросе ACK, чтобы подделать сообщение RST и отправить его клиенту, и клиент также разорвет соединение, когда получит RST.
Именно таким образом успешно закрывается TCP-соединение!
Вот диаграмма перехвата пакетов с помощью инструмента killcx для закрытия соединения Давайте посмотрим на изменения в серийном номере и номере подтверждения.
Следовательно, в будущем захвате пакетов, если пакет SYN появляется необъяснимым образом, возможно, что другая сторона хочет запустить RST-атаку на вас в следующий раз и напрямую разорвать ваше TCP-соединение!
Как, очень умно!