Привет, дружище!
Сегодня я отступлюсь от своего обыкновения писать о чисто практических вещах и займусь теоретизированием на одну из наиболее волнующих меня тем в области сетевой безопасности.
В наши дни, термины hijacking и MITM (man in the middle) не знаком разве что самому ленивому... :)) Впрочем, сделаем для этого самого ленивого небольшое лирическое отступление. Hijacking, грубо говоря, можно понимать как "перехват траффика, получение контроля над траффиком". "Man in the middle" переводится с английского как "человек посередине". В области хакерства этот термин объединяет в себе целый ряд атак сетевого уровня взаимодействия, осуществляющих спуфинг TCP-соединений, попросту говоря, hijacking. В частности, атаку на
асимметричные криптоалгоритмы в защищённых сетевых соединениях... Собственно, сюда можно отнести любую атаку, где взломщик (или подконтрольный взломщику хост) находится топологически "посередине" между двумя связанными элементами: обладание места "посередине" обеспечивает хакеру возможность беспрепятственного спуфинга соединений любого рода.
Атаку, о которой я буду рассуждать сегодня, нельзя в полной мере считать MITM-атакой. Условия несколько усложняются: взломщик находится не "посередине", а "рядом", в одном локальном сегменте с одной из связанных TCP-соединением сторон:
Условия: одноранговая локальная сеть на участке <VICTIM>-<HACKER>, отсутствие свитчевания траффика, отсутствие средств шифрования кадров/пакетов данных на участках <ROUTER>-<ANY_LOCAL_HOST>. Иными словами, обычная локальная сеть :)))
Цель: обеспечение возможности "аккуратного" (топологически "анонимного" и эффективного) инфицирования "соседнего" (топологически "однородного") хоста.
Фундаментальная основа: невозможность однозначной идентификации принадлежности кадра данных какому-либо хосту в пределах одноранговой локальной сети.
Иными словами, хакер, как и в случае классической MITM-атаки, не теряет возможности прослушивать траффик <VICTIM>-<SERVER>, но он уже не имеет в полной мере возможности этот траффик контролировать и влиять на него так, как если бы он находился непосредственно "посередине".
Итак, приступим.
1. Преамбула
Хост <VICTIM> с некоторой эпизодичностью совершает IP/TCP-соединения с SERVER'ом. При этом, VICTIM'у вовсе не обязательно обладать реальным IP-адресом. Адрес VICTIM'а может превращаться в реальный либо на хосте <ROUTER>, либо где-то ещё выше, посредством NAT'a (Network Address Translator), или любого иного средства.
2. Sniffing/Analyzing
<VICTIM> с некоторой эпизодичностью пытается скачивать файлы с <SERVER>'a; для пущей определённости будем иметь ввиду протокол HTTP, именно его я и буду приводить в пример. Ситуация такова:
1) Сначала следует трёхфазная установка TCP-соединения VICTIM->SERVER. Рассмотрим пример, где я (10.44.8.5:1294) соединяюсь с проксёй, (192.168.129.254:3128):
Протоколы IP и TCP, hijacking которых необходимо осуществлять, описаны в документах
rfc791 и rfc793, соответственно. И тебе придётся их основательно рюхнуть, если ты соберёшься создать реализацию рассматриваемой атаки. Тебе понадобится изучить все тонкости этих протоколов (в том числе и поля их опций, которые некоторые нерадивые авторы предлагают игнорировать). Здесь же я обращу твоё внимание на некоторые ключевые поля заголовков этих протоколов, необходимые для понимания сути TCP-hijacking'а.
EtherNet Level
0x00-0x06 - Source MAC Address, здесь идёт обмен кадрами данных между адресами 00-50-22-86-1E-5D и
00-50-22-97-A5-09, это, соответственно, адреса <VICTIM>'а и <ROUTER>'а.
0x07-0x0C - Destination MAC Address, аналогично.
0x0D-0x0E - содержит значение '08 00', соответствует инкапсуляции протокола IPv4
IPv4 Level
0x10-0x11 - Total Length, размер IP-пакета (не EtherNet-кадра!)
0x12-0x13 - Identification, двухбайтовое поле идентификации пакета уровня IP, по
rfc791 должен увеличиваться на единицу с каждым вновь отправляемым пакетом.
0x17 - Protocol, соответствует инкапсуляции протокола TCPv4
0x18-0x19 - Header Checksum, 16-битная контрольная сумма пакета уровня IP (CRC-16)
0x1A-0x1D - Source IP Address, здесь идёт обмен пакетами данных между адресами 0A-2C-08-05 и C0-A8-81-FE (соответственно, 10.44.8.5 и 192.168.129.254, <VICTIM> и <SERVER>).
0x1E-0x21 - Destination MAC Address, аналогично.
TCPv4 Level
0x22-0x23 - Source Port, идёт обмен между портами 05-0E и 0C-38, т.е. 10.44.8.5:1294 и 192.168.129.254:3128
0x24-0x25 - Destination Port, аналогично.
0x26-0x29 - Sequence Number.
0x2A-0x2D - Acknowledgment Number.
0x2E - Первый полубайт по этому смещению принадлежит полю Data Offset, это косвенный указатель на размер заголовка TCP. У нас это, соответственно, 7, 7 и 5, т.е. 28, 28 и 20 байт соответственно.
0x2F - Последние шесть бит по этому смещению принадлежат флаговому полю заголовка TCP, в следующей последовательности (от старшего к младшему): URG, ACK, PSH, RST, SYN, FIN. У нас это, соответственно, взведённые биты SYN, SYN+ACK и ACK.
Далее следуют непринципиальные для нас поля Window, Checksum и неиспользуемое здесь поле Urgent Pointer.
Уделю особое внимание полям Sequence и Acknowledgment Number, ведь именно на них протокол TCP возлагает особые функции обеспечения пресловутой целостности и безопасности, которыми столь (печально :))) славен этот замечательный протокол. Итак, Sequence и Acknowledgment Number -- это четырёхбайтные числа (обрати внимание, дружище, насколько это "дорого" для траффика, ведь каждый пакет "оснащён" этими числами!), особый механизм конфигурирования которых при трансмиссии потоков TCP сохраняет целостность соединения.
При отправке SYN-запроса <VICTIM>-<SERVER>, <VICTIM> взводит бит SYN и устанавливает произвольное число в поле Sequence Number, в нашем случае это 3D 33 B2 08. Поле Acknowledgment Number <VICTIM> оставляет пустым. <SERVER>, получив такой запрос, формирует ответ, взводя бит ACK (SYN+ACK) и заполняет поле Sequence Number своим произвольным числом, в нашем случае это A1 CF F9 D5. Полученный Sequence Number <SERVER> увеличивает на единицу и помещает в Acknowledgment Number. <VICTIM> получает SYN+ACK-пакет и отправляет следующий, ACK-пакет, уже третий по счёту, в котором он производит аналогичную операцию (инкремент полученного Sequence и помещение его в Acknowledgment и копирование полученного Acknowledgment в Sequence). Такая "игра" идёт вплоть до завершения TCP-соединения. Несовпадение Acknowledgment Number'а приведёт к отказу данной TCP-трансмиссии и игнорированию любого (с точки зрения "потерявшей" соединение стороны) внеполосного траффика.
2) Итак, TCP-соединение произведено. Проследим дальнейшее сообщение между портами 10.44.8.5:1294 и 192.168.129.254:3128.
Не вдаваясь в технические подробности протокола HTTP и особенностей его заголовков (дамп, кстати, всё это наглядно иллюстрирует), отмечу лишь, что с порта 10.44.8.5:1294 идёт запрос к порту 192.168.129.254:3128 на получение файла http://www.kernel.org/pub/linux/kernel/v2.4/patch-2.4.19.gz
Прокся отвечает мне соответствующими реквизитами (такими, например, как "200 OK" -- успех запроса), в числе которых сообщается длина файла. Во втором дампе, со смещения 0x01F1 ты можешь наблюдать начало самого файла. Дальше, сокетные стороны настраивают поля Window и занимаются передачей файла, попутно оптимизируя параметры TCP-трансмиссии. <SERVER> высылает файл в рамках плавно конфигурируемого TCP-потока, а <VICTIM> шлёт ACK-подтверждения принятия очередной порции потока. Но эти дампы, за отсутствием их принципиальной необходимости, я включать в статью не стал.
Как видишь, дружище, всё до безобразия просто :)) В случае же с протоколом FTP, дела обстоят чуток сложнее (технически, но не технологически), заказ файла клиентом, открытие вторичного сокета и начало получения файла отнимет у обоих сторон время на отправление пары десятков минорных пакетиков туда-обратно, но, принципиально, протокол FTP (как в анализе, так и в спуфинге) едва труднее HTTP.
3. Hijacking
Мы достаточно глубоко проследили установку соединения <VICTIM>-<SERVER>. Но вернёмся к нашей схеме. Очевидно, <HACKER> прослушивает соединение <VICTIM>-<SERVER> и держит наготове программу-хайджекер, реализующую логику, речь о которой пойдёт дальше.
Уверен, что в твоей буйной кулхацкерской головушке уже вихрем пронёсся целый ураган мыслей по поводу того, как можно эту трансмиссию перехватить, обрести над ней контроль и впарить <VICTIM>'у вместо реальной последней версии ядра Linux свою версию, заблаговременно пропатченную руткитами :))) Но не торопись. Всему своё время. Обсудим требования к грамотному хайджекингу последовательно и обстоятельно. Я не стану нагружать мои рассуждения дампами, реализующими мои утверждения :))) Во-первых, это чисто теоретическая статья (хоть и малёк без практики тут не обошлось). Во-вторых (и в-главных :))), я ещё не проводил испытания этой атаки, так как начал заниматься её обдумыванием лишь дней пять назад.
Итак:
0. Я безапелляционно допускаю тот факт, что оба сетевых интерфейса (и <ROUTER>'а, и <VICTIM>'а) находятся в нормальном (не promiscuous) режиме работы. Иными словами, <ROUTER> не будет реагировать на кадры данных, испускаемые кем угодно с его Source MAC Address'а. <VICTIM> (и вообще, кто угодно в нормальном режиме работы) будет вести себя аналогично. Следовательно, мы можем совершенно спокойно спуфить Source MAC Address'а (чтобы добиться от ядер машин, которые мы спуфим, получения и принятия испускаемых нами кадров данных). Я не исключаю возможности имения места anti-hijack-активности в сети, но рассмотрение этой проблемы выходит за рамки моей статьи.
1. Прежде всего, необходимо дождаться возникновения благоприятной для хайджекинга ситуации. Например, передача к <SERVER>'у HTTP-GET-запроса на получение определённого (ожидаемого <HACKER>'ом) файла или чего-то ещё, что <HACKER> собирается прохайджекнуть, это не столь принципиально. Принципиален сам факт TCP-трансмиссии с соответствующей конфигурацией полей EtherNet/IP/TCP/TCP options/Application Level Protocol.
2. Далее, необходимо грамотно, не утратив контроль (и/или голову от радости :))) обрубить TCP-соединение <VICTIM>-<SERVER>. Для этого нужно отправить корректный RST(FIN)-запрос к <SERVER>'у с абсолютной репликацией ожидаемых сервером значений полей заголовков IP и TCP и, в частности, с верной конфигурацией полей Sequence и Acknowledgment Number заголовка TCP.
Гарантией успеха пункта 2, да и других пунктов может являться, например, грамотная организация хакерской программы-хайджекера, которая должна получать управление от ядра СРАЗУ ЖЕ после того, как интересующий пакет (по тем или иным признакам -- по сигнатуре -- например) будет ядром схвачено. Кстати, я считаю, что эффект будет положительный практически в любом случае, ведь сообщение от <HACKER>'а к <VICTIM>'у (и наоборот) будет проходить всяко много быстрее, чем между <VICTIM>'ом и <SERVER>'ом.
3. <SERVER>, получив наш RST, откажется от данного TCP-соединения. Ядро <SERVER>'а выбросит из своей очереди соответствующий сокет и все проассоциированные с ним буферы. От одной проблемы мы таким образом легко освобождаемся, но обретаем другую: ведь <VICTIM>-то, не зная о потере <SERVER>'ом TCP-соединения, будет продолжать сдать ему TCP-пакеты. И помешать этому процессу мы обозримыми способами никак не можем.
Поведение <SERVER>'а предсказать невозможно. Это зависит от настроек поведения ядра <SERVER>'а в подобных ситуациях:
3.1. В идеале, <SERVER> будет просто игнорировать входящие не-SYN TCP-соединения, для которых нет соотвествующих (выделенных, использующихся) сокетных ассоциаций. В таком случае, hijacking превращается в сущую скачку: <HACKER>'у достаточно лишь "делать вид", будто бы он -- <SERVER>, общаться с <VICTIM>'ом, спуфя Source MAC Address <ROUTER>'а и производя технически идеальную репликацию TCP-соединения.
3.2. <SERVER>-таки будет реагировать на "бессмысленные" (с его точки зрения) сообщения различными способами. В лучшем случае -- левейшими ICMP-дейтаграммами. В худшем -- корректными по rfc793 TCP FIN-пакетами.
<HACKER>'у нужно собирать статистику по тем или иным серверам, ядрам и настройкам конкретных сторон... Но это не самый лучший и, в любом случае, не самый эффективный способ :))) Стало быть, необходимо продумать приёмы повышения эффективности хайджекинга в тех случаях, когда <SERVER> слишком умён...
ПРИЁМ №1
--------
Приём этот я придумал, пока писал несколько последних абзацев. Он весьма омерзителен, грязен, но, с другой стороны, я не могу придумать ничего более эффективного и кондового, чем ЭТО. Я крайне не рекомендую тем, кто заинтересуется hijacking'ом, когда-нибудь использовать данный приём и рассказываю здесь о нём лишь для увеличения фундаментальной массы моего изложения :)))
Да-да, я говорю о флуде. О DoS-атаке сетевого (в нашем случае, канального) уровня взаимодействия.
<HACKER>'у нужно предпринять любую активность ради того, чтобы воспрепятствовать возможности связи между <VICTIM>'ом и <SERVER>'ом на уровне IP (для них это самый низкий топологический уровень). Единственная, приходящая на ум мысль -- это флуд <ROUTER>'а. Какой именно -- решай сам, мой смелый друг. Либо это будет особенно изощрённый ARP-флуд с целью проведения особо жестокой корриды (со смертельным исходом :))) с ARP-resolution'ом на <ROUTER>'е, либо это будет просто сверхскоростной флуд маленькими пакетами.
Кстати, можно поступать чуть более элегантно (если, конечно, элегантность хоть сколько-нибудь вяжется с флудом :)))) Можно обходиться микроDoS'иками, лишь для того, чтобы "подавлять" сообщения от <VICTIM>'а к <SERVER>'у, не особенно сильно нарушая при этом общее функционирование <ROUTER>'а. Но эта работа слишком филигранна и трудоёмка. Лучше прибегнуть к другим приёмам.
ПРИЁМ №2
--------
Обессмысливание, если можно так выразиться, RST/FIN-пакетов, идущих от <SERVER>'а. Мысль весьма дельная, особенно учитывая высказанное ранее утверждение о том, что скорость обмена данными между <HACKER>'ом и <VICTIM>'ом всяко быстрее, чем между <VICTIM>'ом и <SERVER>'ом. Иными словами, необходимо добиваться, чтобы <VICTIM> "прокручивал" Sequence и Acknowledgment Number'ы быстрее, чем на это сможет реагировать <SERVER>.
Этот приём тоже весьма непрост (ведь мы не можем допустить прохождения в локальный сегмент TCP RST-пакета от <SERVER>'а с "правильными" номерами!), и, плюс ко всему, <VICTIM> "скачает" файл изрядно быстрее, чем если бы он это делал на самом деле... Таким образом, репликация TCP-соединения получится лишь формальной, но не фактической...
Но мысль, повторяю, весьма солидная. Советую тебе солидно проштудировать rfc793 и тщательно её обдумать.
ПРИЁМ №3
--------
Последний приём весьма элегантен, но он открывает возможность идентификации <HACKER>'а. Возможность идентификации, конечно же, весьма умозрительна, но, тем не менее, она присутствует. Ведь всё сказанное выше предусматривает абсолютную топологическую анонимность! (Если тебе не взбредёт вдруг обнажить свой MAC- или IP-адрес :)))
Можно воспользоваться свойствами редиректа протокола HTTP:
1. <VICTIM> спрашивает у <SERVER>'а файл;
2. <HACKER> рубит TCP-cоединение <VICTIM>-<SERVER>;
3. <HACKER> отправляет <VICTIM>'у HTTP-сообщение о том, что интересующий <VICTIM>'а файл находится в другом, заранее подготовленном <HACKER>'ом месте;
4. Едва захайджекнутое соединение теряет смысл: <VICTIM> благополучно начинает принимать заранее приготовленный файл с другого сервера, и уже нормальным TCP-соединением :)))
Этот метод крайне прост (относительно предыдущих двух), однако, прибегая к нему, ты пожертвуешь собственной анонимностью и станешь теоретически вычислимым.
P.S.
----
Мне (да и многим другим) было бы очень неприятно, если бы хакерская программа-хайджекер появилась в свободном распространении. И я очень надеюсь, что этого не случится... Впрочем, я в этом уверен. Ведь, например, распределённые DDoS-атаки с умножением траффика были опубликованы много лет назад, но ни одной публичной реализации этих атак не было 🙂
Дружище, надеюсь, и ты будешь блюсти эту негласную хакерскую мораль.