- Почему я вижу пакет RST, ACK вместо пакета RST?
- 2 ответа
- Новая запись реестра для управления поведением подтверждения TCP (ACK) в Windows
- Аннотация
- Дополнительные сведения
- The Lowe Down
- Microsoft Windows 2008 R2: Whither the TCP RST ACK ??
- Background
- Next Steps
- TCP Reset (TCP RST ACK) — что это и как искать причину?
- В каком месте общения между устройствами происходит TCP Reset?
- Почему TCP RST отправлен сразу после SYN?
- Кто отправил TCP RST ACK?
- Как работает атака TCP Reset
- Как атака TCP reset используется в Великом файрволе?
- Как работает атака TCP reset?
- Как работает протокол TCP
- Порядковые номера TCP
- Подтверждение получения данных
- Выбор порядкового номера для фальшивого сегмента
- Размер TCP-окна
- Приемлемые порядковые номера для сегментов RST
- Атаки TCP reset вслепую
- Выполняем атаку TCP reset против себя
- 1. Установка TCP-соединения между двумя окнами терминала
- 2. Сниффинг трафика
- 3. Отправка фальшивых пакетов RST
Почему я вижу пакет RST, ACK вместо пакета RST?
В Wireshark я часто вижу, что потоки TCP заканчиваются пакетом RST, ACK вместо пакета RST. Кто-нибудь знает, почему это?
Пример того, что я вижу:
SYN SYN, ACK . данные. RST, ACK
Wireshark не собирает пакет RST до пакета RST, ACK.
2 ответа
A RST /ACK не является подтверждением RST, так же как SYN /ACK не является точно подтверждением SYN. Установление TCP фактически является четырехсторонним процессом: инициирующий узел отправляет SYN принимающему хосту, который отправляет ACK для этого SYN. Принимающий хост отправляет SYN на инициирующий узел, который отправляет ACK обратно. Это устанавливает связь с состоянием.
Чтобы сделать это более эффективным, принимающий хост может ACK SYN и отправить свой собственный SYN в тот же пакет, создав трехсторонний процесс, который мы привыкли видеть.
В случае RST /ACK устройство подтверждает, какие данные были отправлены в предыдущем пакете (-ях) в последовательности с ACK, а затем уведомляет отправителя, что соединение закрыто с RST. Устройство просто объединяет два пакета в один, как SYN /ACK. RST /ACK обычно не является нормальным ответом при закрытии сеанса TCP, но это также не обязательно указывает на проблему.
После установления соединения все пакеты должны иметь ACK и соответствовать порядковому номеру полученных пакетов для надежного транспорта /безопасности. RST без ACK не будет приниматься. Когда одна сторона отправляет RST, сокет немедленно закрывается, и принимающая сторона также закрывает сокет сразу после получения действительного RST. Он не должен быть и не может быть подтвержден.
после рукопожатия TCP
A —> B Syn = x, Ack = y, len = z, флаг ACK
B —> A Syn = y, Ack = x + z, len = o, флаг ACK
A —> B Syn = x + z, Ack = y + o, len = p, ACK Flag
B —> A Syn = y + o, ACK = x + z + p, len = q, RST, ACK Flag
B закрывает сокет после того, как он отправляет последний пакет, и A закрывает сокет после его получения.
(не рассматривая здесь TCP-окно, или может быть больше пакетов с одного конца перед объявлением)
Флаг ACK, номер подтверждения и процедура подтверждения связаны, но не одно и то же.
Номер подтверждения: 32 бит
Во всех состояниях, кроме SYN-SENT, все сегменты сброса (RST) проверяются путем проверки их SEQ-полей. Сброс действителен, если его порядковый номер находится в окне. В состоянии SYN-SENT (RST, полученное в ответ к исходному SYN), RST является приемлемым, если поле ACK подтверждает SYN.
Приемник RST сначала проверяет его, затем изменяет состояние. Если приемник находился в состоянии LISTEN, он игнорирует его. Если приемник был в состоянии SYN-RECEIVED и ранее находилось в состоянии LISTEN, то приемник возвращается в состояние LISTEN, иначе приемник прерывает соединение и переходит в состояние ЗАКРЫТО. Если приемник был в любом другом состоянии, он прерывает соединение и советует пользователю и переходит в состояние ЗАКРЫТО.
Новая запись реестра для управления поведением подтверждения TCP (ACK) в Windows
В этой статье вводится запись реестра TcpAckFrequency, которая определяет количество подтверждений TCP (ACKs).
Исходная версия продукта: Windows 10 — все выпуски, Windows Server 2012 R2
Исходный номер КБ: 328890
Аннотация
TcpAckFrequency — это запись реестра, которая определяет количество подтверждений TCP (ACKs), которые будут невыполнены до игнорирования отложенного времени ACK.
Дополнительные сведения
Как указано в документе RFC 1122, TCP использует отложенные подтверждения, чтобы уменьшить количество пакетов, отложенных на носители. Вместо отправки подтверждения для каждого полученного сегмента TCP TCP в Windows используется общий подход к реализации отложенных подтверждений. Так как данные получаются TCP по конкретному подключению, оно отправляет подтверждение только при условии выполнения одного из следующих условий:
- Подтверждение для предыдущего сегмента не было отправлено.
- Сегмент получен, но никакой другой сегмент не поступает в течение 200 миллисекунд для этого подключения.
Как правило, подтверждение отправляется для каждого другого сегмента TCP, который получается для подключения, если не истекает срок действия отложенного времени ACK (200 миллисекунд). Вы можете настроить отложенный timer ACK, отредактировать следующую запись реестра.
В этот раздел, описание метода или задачи включены действия, содержащие указания по изменению параметров реестра. Однако неправильное изменение параметров реестра может привести к возникновению серьезных проблем. Поэтому следует в точности выполнять приведенные инструкции. Для дополнительной защиты создайте резервную копию реестра, прежде чем редактировать его. Так вы сможете восстановить реестр, если возникнет проблема. Для получения дополнительных сведений о том, как создать и восстановить реестр, щелкните следующий номер статьи, чтобы просмотреть статью в базе знаний Майкрософт:
322756 Создание резервной копии и восстановление реестра Windows
Подмайка: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\
Запись: TcpAckFrequency
Тип значения: REG_DWORD, номер
Допустимый диапазон: 0–255
Значение по умолчанию: 2
Описание: указывает количество acKs, которые будут невыполнены до того, как отложенный ACK-временир будет игнорироваться. Корпорация Майкрософт не рекомендует изменять значение по умолчанию без тщательного изучения среды.
Если вы установите значение 1, каждый пакет будет немедленно подтвержден, так как только что получен только один невыполненный TCP-ACK в качестве сегмента. Значение 0 (ноль) не является допустимым и рассматривается как значение по умолчанию, 2. Единственный раз, когда номер ACK — 0, если сегмент не получен и хост не собирается подтверждать данные.
The Lowe Down
Microsoft Windows 2008 R2: Whither the TCP RST ACK ??
Okay, I have to admit I was concerned. We installed Windows Server 2008 R2, setup our applications, and then proceeded to add the required configuration to have Nagios monitor the host and associated services. But Nagios claimed the host was down! Simple pings returned a response. Now what?
Background
I configure Nagios to use check_tping to monitor hosts, not the standard ICMP ping. Why, you ask? Some network devices do not handle ICMP on their fast-path in silicon, leaving it to be processed by the CPU. During periods when the CPU is busy, ICMP will not be a good measure of host or network responsiveness. In some networks, ICMP may be handled with a different QoS profile. The best gauge of response, over a network, is something close to what applications use. Guess what? The Transmission Control Protocol! How is it leveraged for monitoring? A SYN packet is directly at the host on a port that is closed (it could be an open port — more on that later). A host operating system will typically respond with a TCP reset (RST ACK to be exact) — a simple two-packet exchange without extra overhead — this is a kind of network equivalent to “take pictures, leave [very few] footprints!” If there is an intervening firewall device, the chosen port will have to be opened to allow the SYN packets to reach the destination host.
Next Steps
Windows Server 2008 R2 comes with a host-based firewall and it is enabled by default. Hmmm, well, let’s leave it enabled. How much trouble can it be? Given the decision to leave the firewall enabled, testing proceeded as follows (with packet sniffers on each end and firewall logging enabled on Windows Server 2008 R2):
- Initial test without any modifications. Failure.
- Added an inbound rule for the domain profile and re-tested. Failure.
- Disabled the firewall for the domain profile. Failure.
- Re-enabled the firewall for the domain profile and modified the inbound rule to apply to all network profiles (domain, private, and public). Failure.
- Disabled the firewall for *all* network profiles. Success!
Failure = SYN packets observed leaving the source host, and observed either as dropped (test #1) or arriving but without any response (tests #2-4).
Success = SYN packets observed leaving the source host, arriving at the destination host and RST ACK packets being returned (test #5).
There was a test #0. This involved sending the SYN packet probes to an open port. However, this results in the TCP three-way handshake actually completing, which also means connection termination has to happen. In the usual case, this will involve seven packets, three for connection establishment, and four for connection termination. In addition, a connection slot is held down, and on the client side, the connection may go through a TIME_WAIT (aka 2MSL) state. In this case, it does not. Windows 2008 R2 issues a RST ACK immediately after the active close. After connection establishment the sequence is:
- FIN sent by the client
- ACK from Windows
- An immediate RST ACK from Windows
I have to presume that some heuristic is in play here based on the time the connection was open. For very short connections, Windows may decide to issue the reset rather than close the connection gracefully by sending its own FIN packet and waiting for the final ACK from the client. Under attack, this might help to stave off resource exhaustion. I find this to be an acceptable strategy.
TCP Reset (TCP RST ACK) — что это и как искать причину?
Каждый TCP пакет несёт заголовок и в нем есть биты завершения соединения:
- FIN – все данные переданы успешно, получены все подтверждения и соединение завершается логичным способом;
- RST — обычно этот бит установлен в «0» и ничего не значит. Но иногда он получает значение 1 и это ведет к немедленному прекращению данного соединения.
Хорошо это или плохо, так как красный сигнал не предвещает ничего хорошего? Все, конечно же, зависит от ситуации, когда они происходят.
TCP RST ACK – это нормальный и предусмотренный RFC 793 процесс разрыва соединения, но если их много и это оказывает влияние на производительность приложения и пользователей, то это бесспорно повод задуматься. Как всегда дьявол кроется в деталях и необходимо задать себе несколько вопросов.
В каком месте общения между устройствами происходит TCP Reset?
Нажимаем Analyze – Conversation Filter — IPv4. Если TCP IP Reset отправлен одной из сторон после обмена данными, то надо проверять настройки оборудования. Например, данные отправлены, но соединение держится в открытом состоянии и по прошествии какого-то времени — посылается TCP RST. И это не является проблемой.
Если TCP Reset происходит в начале соединения, то это тоже не проблема для пользователя. На примере ниже мы запрашиваем файл с облака, но его уже там нет. Поэтому клиент дважды попытался его получить и оба раза сервер ответил TCP IP Reset.
Если TCP Reset происходит в середине процесса передачи данных, то потребуется дополнительный анализ, так как это может быть проблема на сервере, в приложении или даже клиенте. Пользователь запросил данные через браузер и затем закрыл его, не дожидаясь ответа. В данном случае будет однозначно отправлен TCP Reset.
Почему TCP RST отправлен сразу после SYN?
Причин может быть также несколько. Обычно это означает, что порт, по которому пытаются открыть соединение, недоступен. Сервер отключен, сервер занят или такой порт закрыт. Поэтому происходит сброс SYN и все.
Кто отправил TCP RST ACK?
Важно также понимать кто инициатор разрыва соединения. Клиент, сервер, сетевое оборудование внутри собственной инфраструктуры или на пути от провайдера (см. TTL, а также IP адрес отправителя). На все эти вопросы мы можем получить ответ, анализируя трафик с помощью анализатора протоколов.
Как работает атака TCP Reset
Атака TCP reset выполняется при помощи одного пакета данных размером не более нескольких байт. Подменённый спуфингом TCP-сегмент, созданный и переданный атакующим, хитростью заставляет двух жертв завершить TCP-соединение, прервав между ними связь, которая могла быть критически важной.
Эта атака имела последствия и в реальном мире. Опасения её использования вызвали внесение изменений в сам протокол TCP. Считается, что атака является важнейшим компонентом Великого китайского файрвола («Золотого щита»), который используется китайским правительством для цензурирования Интернета за пределами Китая. Несмотря на её впечатляющую биографию, для понимания механизмов этой атаки необязательно обладать глубокими знаниями работы TCP. Разумеется, понимание её тонкостей способно многому научить вас об особенностях реализации протокола TCP, и, как мы вскоре убедимся, вы даже сможете провести эту атаку против себя при помощи одного только ноутбука.
В этом посте мы:
- Изучим основы протокола TCP
- Узнаем, как работает атака
- Проведём атаку против себя при помощи простого скрипта на Python.
Прежде чем приступать к анализу механики атаки, давайте сначала посмотрим, как она используется в реальном мире.
Как атака TCP reset используется в Великом файрволе?
Великий файрвол (Great Firewall, GFW) — это комплекс систем и техник, используемых китайским правительством для цензурирования Интернета для внутренних китайских пользователей. GFW активно блокирует и разрывает соединения с серверами внутри и снаружи страны, а также пассивно отслеживает Интернет-трафик запрещённого контента.
Чтобы не позволить пользователям даже подключаться к запрещённым серверам, GFW использует такие техники, как DNS pollution и IP blocking (обе они стоят отдельных статей). Однако иногда файрволу GFW требуется позволить совершить соединение, но затем разорвать его посередине. Например, это необходимо, если требуется выполнить медленный, отложенный анализ подключения, допустим, его корреляцию с другими действиями. Или это используется, если файрволу нужно проанализировать данные, которыми обменивались в процессе соединения, а затем использовать эту информацию, чтобы принять решение о его продолжении или блокировке. Например, может быть разрешён трафик на новостной веб-сайт, но цензурированы видео, содержащие запрещённые ключевые слова.
Для этого GFW необходимы инструменты, способные прерывать уже установленные соединения. Один из таких инструментов — это атака TCP reset.
Как работает атака TCP reset?
При атаке TCP reset нападающий разрывает соединение между двумя жертвами, отправляя одной или обеим фальшивые сообщения, приказывающие им немедленно прервать соединение. Такие сообщения называются сегментом сброса TCP. При обычной работе без участия злоумышленника компьютеры отправляют сегменты сброса TCP, когда они получают неожиданный TCP-трафик и хотят, чтобы отправитель прекратил его передавать.
Атака TCP reset злонамеренно эксплуатирует этот механизм, хитростью заставляя жертв преждевременно завершить TCP-соединения, отправляя им фальшивые сегменты сброса. Если фальшивый сегмент сброса изготовлен правильно, то получатель примет его за настоящий сегмент и закроет соединение со своей стороны, прерывая дальнейшую передачу информации по этому соединению. Чтобы продолжить обмен данными, жертвы могут попытаться создать новое TCP-соединение, но у атакующего может быть возможность сбросить и это новое соединение. К счастью, поскольку для сборки и отправки поддельного пакета атакующему нужно время, атаки сбросом по-настоящему эффективны только против долговременных соединений. Кратковременные соединения. например, используемые для передачи небольших веб-страниц, обычно успевают выполнить своё предназначение к тому времени, когда у атакующего появится возможность их сбросить.
Отправка фальшивых TCP-сегментов в каком-то смысле является лёгким процессом, потому что ни TCP, ни IP не имеют никаких собственных способов проверки личности отправителя. Существует расширение IP под названием IPSec, обеспечивающее аутентификацию, однако оно используется не так широко. Интернет-провайдеры должны отказывать в передаче IP-пакетов, которые поступают с очевидно ложного IP-адреса, но, как утверждается, такая проверка выполняется очень посредственно. Всё, что может получатель — принять исходный IP-адрес и порт внутри пакета или сегмента за чистую монету, и по возможности использовать для идентификации отправителя более высокоуровневые протоколы, например TLS. Однако поскольку пакеты сброса TCP являются частью самого протокола TCP, их невозможно проверить при помощи этих высокоуровневых протоколов.
Несмотря на простоту отправки фальшивых сегментов, изготовление фальшивого сегмента и выполнение успешной атаки TCP reset всё равно может быть сложной задачей. Чтобы понять, почему так происходит, нам нужно разобраться в работе протокола TCP.
Как работает протокол TCP
Задача протокола TCP — отправка получателю точной копии блока данных. Например, если мой сервер передаёт по протоколу TCP вашему компьютеру HTML, то стек TCP вашего компьютера (часть его операционной системы, занимающаяся обработкой TCP) должна вывести мой HTML точно в том же виде и порядке, в котором его отправил мой сервер.
Однако мой HTML не передаётся по Интернету в таком идеально упорядоченном виде. Он разбивается на множество небольших фрагментов (называемых TCP-сегментами), каждый из которых по отдельности передаётся по Интернету и воссоздаётся в переданном порядке стеком TCP вашего компьютера. Этот восстановленный вывод называется потоком TCP. Каждый TCP-сегмент передаётся в собственном IP-пакете, однако для понимания атаки нам не нужно знать никаких подробностей об IP.
Преобразование сегментов в поток требует внимательности, потому что Интернет ненадёжен. TCP-сегменты могут теряться. Они могут приходить не по порядку, отправляться дважды, повреждаться и испытывать множество других злоключений. Поэтому задача протокола TCP заключается в обеспечении надёжной передачи данных по ненадёжной сети. TCP выполняет эту задачу, требуя от обеих сторон соединения сохранения тесного контакта между друг другом и постоянной передачи сведений о том, какие блоки данных были получены. Это позволяет отправителям понять, какие данные получатель ещё не принял, и повторно передавать те данные, которые были утеряны.
Чтобы понять, как работает процесс, нам нужно разобраться, как отправители и получатели используют порядковые номера TCP для разметки и отслеживания данных, переданных по TCP.
Порядковые номера TCP
Каждый байт, переданный по TCP-соединению, имеет порядковый номер, назначаемый ему отправителем. Принимающие машины используют порядковые номера для перемещения получаемых данных в исходный порядок.
Когда две машины договариваются о TCP-соединении, каждая машина отправляет другой случайный начальный порядковый номер. Это порядковый номер, который машина назначит первому отправленному ею байту. Каждому последующему байту назначается порядковый номер предыдущего байта плюс 1. TCP-сегменты содержат TCP-заголовки, которые являются метаданными, прикреплёнными к началу сегмента. Порядковый номер первого в теле сегмента байта включается в TCP-заголовок этого сегмента.
Следует заметить, что TCP-соединения являются двунаправленными, то есть данные могут передаваться в обе стороны и каждая машина в TCP-соединении действует и как отправитель, и как получатель. Из-за этого каждая машина должна назначать и обрабатывать собственный независимый набор порядковых номеров.
Подтверждение получения данных
Когда машина получает TCP-сегмент, она сообщает отправителю сегмента, что он был получен. Получатель делает это при помощи отправления сегмента ACK (сокращение от «acknowledge» — «подтверждение»), содержащего порядковый номер следующего байта, который он ожидает получить от отправителя. Отправитель использует эту информацию, чтобы понять, что получатель успешно получил все остальные байты до этого номера.
Сегмент ACK обозначается наличием флага ACK и соответствующего номера подтверждения в TCP-заголовке сегмента. В протоколе TCP есть всего 6 флагов, в том числе и (как мы вскоре увидим) флаг RST (сокращение от «reset» — «сброс»), обозначающий сегмент сброса.
Примечание: протокол TCP также позволяет использовать выборочные ACK, которые передаются, когда получатель получил некоторые, но не все, сегменты в интервале номеров. Например, «Я получил байты 1000-3000 и 4000-5000, но не 3001-3999». Для упрощения я не буду рассматривать выборочные ACK в нашем обсуждении атак TCP reset.
Если отправитель передаёт данные, но не получает ACK для них в течение определённого интервала времени, то он предполагает, что данные были утеряны, и отправляет их повторно, давая им те же самые порядковые номера. Это означает, что если получатель принимает одни и те же байты дважды, то он тривиальным образом использует порядковые номера для избавления от дубликатов без нарушения потока. Получатель может принимать дублирующиеся данные, потому что исходный сегмент был получен позже, уже после того, как был отправлен повторно, или потому, что исходный сегмент был успешно получен, но соответствующий ACK потерялся на пути к отправителю.
Пока такие дублирующиеся данные встречаются достаточно редко, вызываемые ими избыточные траты ресурсов не приводят к проблемам. Если все данные рано или поздно добираются до получателя, а соответствующие им ACK доходят до отправителя, то TCP-соединение справляется со своей работой.
Выбор порядкового номера для фальшивого сегмента
При создании ложного сегмента RST злоумышленнику нужно дать ему порядковый номер. Получателей вполне устраивает, что нужно принимать сегменты с непоследовательными порядковыми номерами и самостоятельно соединять их в нужном порядке. Однако их возможности ограничены. Если получатель принимает сегмент с порядковым номером, который «слишком» выбивается из порядка, то он отбрасывает такой сегмент.
Следовательно, для успешной атаки TCP reset требуется правдоподобный порядковый номер. Но что считается таким номером? Для большинства сегментов (хотя, как мы увидим позже, не для RST ), ответ определяется размером TCP-окна.
Размер TCP-окна
Представьте древний компьютер начала 1990-х, подключённый к современной гигабитной волоконно-оптической сети. Сверхбыстрая сеть может передавать данные этому престарелому компьютеру с потрясающей скоростью, быстрее, чем машина сможет их обработать. Это будет нам мешать, потому что TCP-сегмент нельзя считать полученным, пока получатель не сможет его обработать.
У компьютеров есть TCP-буфер, в котором новые прибывшие данные ожидают обработки, пока компьютер работает над данными, прибывшими до них. Однако этот буфер имеет ограниченный размер. Если получатель неспособен справиться с объёмом передаваемых ему сетью данных, то буфер переполнится. Когда буфер полностью заполнен, у получателя нет другого выбора, кроме как избавляться от избыточных данных. Получатель не отправляет ACK для отброшенных данных, поэтому отправителю приходится повторно отправлять их, когда в буфере получателя найдётся свободное место. Не важно, с какой скоростью сеть может передавать данные, если получатель не успевает с ними справляться.
Представьте чрезмерно ретивого друга, который отправляет вам на почту целый поток из писем быстрее, чем вы сможете его прочитать. Внутри вашего почтового ящика есть определённое буферное пространство, но после его переполнения все непоместившиеся письма выпадут на землю, где их съедят лисы и другие твари. Другу придётся повторно отправлять сожранные письма, а пока у вас будет время на получение его предыдущих сообщений. Отправка слишком большого количества писем или объёма данных, который получатель неспособен обработать — пустая трата энергии и канала передачи.
«Слишком много» — какой это объём данных? Как отправитель понимает, когда нужно отправлять ещё данные, а когда стоит подождать? Здесь нам пригождается размер TCP-окна. Размер окна получателя — это максимальное количество неподтверждённых байтов, которое отправитель может передать ему в любой момент времени. Допустим, получатель сообщает, что его размер окна равен 100 000 (вскоре мы узнаем, как он передаёт это значение), поэтому отправитель передаёт 100 000 байт. Допустим, что ко времени, когда отправитель передал стотысячный байт, получатель отправил сегменты ACK для первых 10 000 этих байтов. Это означает, что 90 000 байтов до сих пор не подтверждено. Так как размер окна равен 100 000, отправитель может передать ещё 10 000 байт, прежде чем ему придётся ждать новых ACK . Если после отправки этих 10 000 дополнительных байтов дальнейших ACK им получено не было, то отправитель упрётся в свой лимит 100 000 неподтверждённых байтов. Следовательно, отправитель должен будет ждать и прекратит отправлять данные (кроме повторной передачи данных, которые он считает утерянными) до момента, пока не получит новые ACK .
Каждая из сторон TCP-соединения уведомляет другую о размере своего окна в процессе установки связи (handshake), выполняемой при открытии соединения. Кроме того, размеры окон могут динамически изменяться в процессе соединения. Компьютер с большим TCP-буфером может объявить о большом размере окна, чтобы максимизировать пропускную способность. Это позволяет общающейся с ним машине постоянно передавать данные по TCP-соединению, не приостанавливаясь и не ожидая подтверждения. Компьютер с маленьким TCP-буфером может быть вынужден заявить о маленьком размере окна. Иногда отправители полностью заполняют окно и оказываются вынужденными ждать, пока какие-то из сегментов не будут подтверждены. Из-за этого страдает пропускная способность, но это необходимо, чтобы TCP-буферы не переполнялись.
Размер TCP-окна — это жёсткое ограничение на объём передаваемых неподтверждённых данных. Мы можем использовать его для вычисления максимально возможного порядкового номера (который в показанном ниже уравнении я обозначил как max_seq_no ), который отправитель может отправить в текущий момент времени:
max_seq_no = max_acked_seq_no + window_size
max_acked_seq_no — это максимальный порядковый номер, для которого получатель отправил ACK . Это максимальный порядковый номер, о котором отправителю известно, что получатель точно его принял. Так как отправитель может передавать только window_size неподтверждённых байтов, максимальный порядковый номер, который он может отправить, равен max_acked_seq_no + window_size .
Из-за этого спецификация TCP гласит, что получатель должен игнорировать любые получаемые им данные, имеющие порядковые номера вне допустимого окна. Например, если получатель подтвердил все байты до 15 000, а его размер окна равен 30 000, то он будет принимать любые данные с порядковым номером в интервале от 15 000 до (15 000 + 30 000 = 45 000). При этом получатель полностью игнорирует данные с порядковыми номерами вне этого интервала. Если сегмент содержит данные, часть которых находится в пределах этого окна, а часть — за его пределами, то данные внутри окна будут приняты и подтверждены, но данные за его пределами будут отброшены. Заметьте, что мы по-прежнему игнорируем возможность выборочных ACK , которых вкратце коснулись в начале поста.
В случае большинства TCP-сегментов это правило даёт нам интервал приемлемых порядковых номеров. Однако, как было сказано ранее, накладываемые на сегменты RST ограничения ещё строже, чем ограничения для обычных сегментов передачи данных. Как мы вскоре увидим, это сделано для усложнения проведения разновидности атаки TCP reset под названием «атака TCP reset вслепую» (blind TCP reset attack).
Приемлемые порядковые номера для сегментов RST
Обычные сегменты принимаются, если их порядковый номер находится в интервале от следующего ожидаемого порядкового номера и этого номера плюс размер окна. Однако пакеты RST принимаются только тогда, когда их порядковый номер точно равен следующему ожидаемому порядковому номеру. Вернёмся к предыдущему примеру, в котором получатель отправил номер подтверждения 15 000. Чтобы пакет RST был принят, его порядковый номер должен быть точно равен 15 000. Если получатель получает сегмент RST с порядковым номером, не равным 15 000, то он не примет его.
Если порядковый номер вне интервала, то получатель полностью его игнорирует. Однако если он находится в пределах окна ожидаемых порядковых номеров, то получатель отправляет «challenge ACK » («ACK вызова»). Это сегмент, сообщающий отправителю, что сегмент RST имеет неверный порядковый номер. Также он сообщает отправителю порядковый номер, который ожидает получатель. Отправитель может использовать эту информацию из ACK вызова для воссоздания и повторной отправки своего RST .
До 2010 года протокол TCP не накладывал этих дополнительных ограничений на сегменты RST . Сегменты RST принимались или отклонялись в соответствии с теми же правилами, что и любые другие. Однако это слишком упрощало атаки TCP reset вслепую.
Атаки TCP reset вслепую
Если атакующий имеет возможность перехвата трафика, которым обмениваются его жертвы, то может считывать порядковые и подтверждающие номера TCP-пакетов жертв. Он может использовать эту информацию для того, чтобы выбирать, какие порядковые номера давать своим фальшивым сегментам RST . Однако если атакующий не может перехватывать трафик жертв, то не будет знать, какие порядковые номера вставлять. Но он всё равно может передавать любое количество сегментов RST с любым количеством разных порядковых номеров, надеясь, что один из них окажется верным. Такая атака называется атакой TCP reset вслепую.
Как мы уже говорили, в первоначальной версии протокола TCP атакующему достаточно было только подобрать порядковый номер RST в пределах TCP-окна получателя. В статье под названием «Slipping in the Window» («Протискиваемся в окно») показано, что это слишком упрощало успешные атаки вслепую, так как для почти гарантированного успеха атакующему достаточно было просто отправить несколько десятков тысяч сегментов. Чтобы противостоять этому, правило, заставлявшее получателя принимать сегмент RST , заменили на описанный выше более строгий критерий. Благодаря новым правилам для осуществления атак TCP reset вслепую нужно отправлять миллионы сегментов, что делает их практически нереализуемыми. Подробности см. в RFC-5963.
Выполняем атаку TCP reset против себя
Примечание: я тестировал этот процесс на OSX, но получил несколько комментариев, что в Linux он не работает нужным образом.
Теперь мы знаем всё о выполнении атаки TCP reset. Атакующий должен:
- Наблюдать за сетевым трафиком («сниффить» его), передаваемым между двумя жертвами
- Сниффить TCP-сегмент со включенным флагом ACK и считать его подтверждённый номер
- Изготовить ложный TCP-сегмент со включенным флагом RST и порядковым номером, равным подтверждённому номеру перехваченного сегмента (стоит учесть, что это предполагает медленную передачу, иначе выбранный порядковый номер быстро устареет. (Чтобы повысить шансы на успех, можно передать несколько сегментов RST с большим интервалом порядковых номеров.)
- Отправить фальшивые сегменты одной или обеим жертвам, надеясь, что это приведёт к разрыву их TCP-соединения
Чтобы попрактиковаться, давайте проведём TCP-атаку на самих себя на одном компьютере, общаясь сами с собой через localhost . Для этого нам требуется:
- Настроить TCP-соединение между двумя окнами терминала
- Написать атакующую программу, которая будет заниматься сниффингом трафика
- Модифицировать программу так, чтобы она изготавливала и отправляла фальшивые сегменты RST .
Давайте приступим.
1. Установка TCP-соединения между двумя окнами терминала
Мы настроим TCP-соединение при помощи инструмента netcat , который по умолчанию имеется во многих операционных системах. Подойдёт и любой другой TCP-клиент. В первом окне терминала мы выполним следующую команду:
Эта команда запускает на нашей локальной машине TCP-сервер, слушающий порт 8000 . Во втором окне терминала выполним такую команду:
Эта команда пытается создать TCP-соединение с машиной по IP-адресу 127.0.0.1 с портом 8000 . Теперь между двумя окнами терминала должно установиться TCP-соединение. Попробуйте ввести что-нибудь в одном окне — данные должны будут передаться по TCP-соединению и появиться в другом окне.
2. Сниффинг трафика
Мы напишем выполняющую сниффинг трафика атакующую программу при помощи scapy — популярной сетевой библиотеки Python. Эта программа использует scapy для считывания данных, передаваемых между двумя окнами терминала, хотя и не является частью соединения.
Код программы выложен в моём репозитории на GitHub. Программа сниффит трафик соединения и выводит его на терминал. Основным ядром кода является вызов метода sniff из библиотеки scapy , расположенный в конце файла:
Этот фрагмент кода приказывает scapy выполнять сниффинг пакетов в интерфейсе lo0 и фиксировать подробности о всех пакетах как часть нашего TCP-соединения. Вызов имеет следующие параметры:
- iface — приказывает scapy слушать сетевой интерфейс lo0 , или localhost
- lfilter — функция фильтра, приказывающая scapy игнорировать все пакеты, не являющиеся частью соединения двух IP-адресов localhost на порте сервера. Эта фильтрация необходима, потому что на машине есть множество других программ, использующих интерфейс lo0 . Мы хотим игнорировать все пакеты, не являющиеся частью нашего эксперимента.
- prn — функция, которую scapy должна выполнять для каждого пакета, соответствующего требованиям функции lfilter . Функция в показанном выше примере просто выводит пакет на терминал. На следующем этапе мы изменим эту функцию, чтобы она также передавала сегменты RST .
- count — количество пакетов, которое scapy должна сниффить до выхода.
Чтобы протестировать эту программу, настройте TCP-соединение из этапа 1. Клонируйте мой репозиторий GitHub, выполните инструкции по настройке и запустите программу в третьем окне терминала. Введите какой-нибудь текст в один из терминалов TCP-соединения. Вы должны увидеть, что программа начнёт фиксировать информацию о сегментах соединения.
3. Отправка фальшивых пакетов RST
Мы установили соединение, а программа может сниффить все проходящие через неё TCP-сегменты. Единственное, что нам осталось — модифицировать программу, чтобы она выполняла атаку TCP reset передачей фальшивых сегментов RST . Для этого мы изменим функцию prn (см. список параметров выше), вызываемую scapy для пакетов, соответствующих требованиям функции lfilter . В модифицированной версии функции вместо простой фиксации соответствующего пакета мы изучаем его, извлекаем необходимые параметры, и используем эти параметры для сборки и отправки сегмента RST .
Допустим, мы перехватили сегмент, идущий от (src_ip, src_port) к (dst_ip, dst_port) . У него установлен флаг ACK и номер подтверждения равен 100 000. Чтобы изготовить и отправить сегмент, мы:
- Меняем местами IP-адреса отправителя и получатели, а также их порты. Это необходимо, потому что наш пакет будет ответом на перехваченный пакет. Исходная точка нашего пакета должна быть конечной точкой исходного пакета, и наоборот.
- Включаем флаг RST сегмента, потому что именно он сообщает, что сегмент является RST
- Присваиваем порядковому номеру точное значение номера подтверждения перехваченного пакета, так как это следующий порядковый номер, который ожидает получить отправитель
- Вызываем метод send библиотеки scapy для отправки сегмента жертве — источнику перехваченного пакета.
Чтобы модифицировать нужным образом нашу предыдущую программу, раскомментируйте эту строку и закомментируйте строку над ней.
Теперь мы готовы к проведению полномасштабной атаки. Настройте TCP-соединение в соответствии с этапом 1. Запустите атакующую программу из этапа 2 в третьем окне терминала. Затем введите какой-нибудь текст в одном из терминалов TCP-соединения. В терминале, на котором вы вводили текст, TCP-соединение внезапно и загадочно прервётся. Атака выполнена!