`` NETerrorism ''
=================
content:
: 0x00 : gateway bypassing
: 0x01 : IPv4 over IPv4 tunneling
: 0x02 : GRE (Generic Rounting Encapsulation) protocol
: 0x03 : usage in FreeBSD and Linux
: 0x04 : have real phun with routing tables
: 0x05 : how does work routing tables?
: 0x06 : ICMP redirect messages
: 0x07 : scan the net
============================================/ Gateway bypassing /===========
Здесь будут рассмотрены методы проникновения в закрытые сети с помощью
обхода ограничений tcp/ip стека шлюзовой системы.
Итак, поехали. Для начала нада сказать пару слов о работе этого самого
стека. Он основан, если вы не знаете, на модели OSI то есть используется
многоуровневая обработка датаграмм (пакетов). Протоколом транспортного
уровня является IP, далее ядро начинает его разбирать дальше и смотреть
что там за типы и прочее. Но по идее пакет с одним ip заголовком должен
дойти до пункта назначения, разве что какой-нибудь промежуточный роутер
увидит, что контрольная сумма заголовка вышестоящего протокола (которого
у нас нет) является лажовой и порежет его. Значит так, мы пишем в пакет
dest_addr (ip адрес для доставки) и выгружаем его в сеть. Роутеры
принимают и доставляют датаграмму до конечного пункта. Теперь наш пакет
начинает ковырять ip-стек оси той машины и в зависимости от значения в
поле proto, передавать управление обработчику данного вышестоящего
протокола.
В этом разделе я не буду рассказывать подробно о том что и как пашет в
GRE и IPoverIP, просто в кратце объясню саму идею. Назначением оных
является организация и передача данных по виртуальным каналам поверх
публично доступной сети. Во втором всё просто до безобразия: один ip-
пакет оборачивается в другой. Внешний заголовок в поле dest_addr держит
адрес гейта, а внутренний адресует датаграмму конкретному хосту
внутренней сети.
Рассмотрим пример:
адрес нашей машины: 13.6.6.6
адрес шлюза: 65.143.81.93
адрес назначения (во внутренней сети): 192.168.0.5
+------------------------+
I icmp echo пакет I
+------------------------+
I внутренний IP заголовокI
I I
I src_ip: 13.6.6.6 I внутренний пакет = ip заголовок + icmp пакет
I dst_ip: 192.168.0.5 I
I proto: 1 (ipv4 icmp) I
+------------------------+ -------------
I внешний IP заголовок I
I I внешний заголовок
I src_ip: 13.6.6.6 I
I dst_ip: 65.143.81.93 I
I proto: 4 (ip over ip) I
+------------------------+
Отправляем такой пакет, и когда он достигнет шлюза, стек увидит в поле
proto внешнего заголовка стоит 4, то есть это ip over ip протокол. Гейт
передаёт (если, конечно, поддерживает IP over IP) внутренний пакет
своему обработчику, тот снова пробегает на этот раз внутренний ip
заголовок и видит что, во-первых, это icmp сообщение, а во-вторых, оно
адресованно не ему. Поэтому он передаёт его во внутреннюю сеть хосту
(в нашем случае это 192.168.0.5). Ответ к нам должен прийти нормально,
т.к. для пользователя этого LAN'а отправка пакетов совершенно прозрачна
что играет нам на руку.
Теперь про GRE (хотя rfc на эту тему немало). В rfc 1701 вы можете
найти формат его пакетов:
+-----------------------+
I внутренний пакет I
+-----------------------+
I заголовок GRE I
+-----------------------+
I внешний IP заголовок I
+-----------------------+
А вот и формат самого GRE-заголовка:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|C|R|K|S|s|Recur| Flags | Ver | Protocol Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum (optional) | Offset (optional) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Key (optional) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number (optional) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Routing (optional)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C,R,K,S,s - это опции,смотрите их подробное описание в rfc. Вкратце,они
показывают, присутствует ли секция для этих опиций или нет. К примеру
если 2-й бит не сброшен,то в GRE-заголовке должна присутствовать секция
Routing в которой должен быть объявлен маршрут доставки датаграммы. И
так по аналогии:
C - checksum
K - key
R - routing (кстати, если эта опция включена, обязательно должена
присутствовать checksum)
S - sequnce number
s - strict source route
В protocol type мы указываем тип инкапсулированного пакета, вот
небольшой их список:
Protocol Family PTYPE
--------------- -----
Reserved 0000
SNA 0004
OSI network layer 00FE
PUP 0200
XNS 0600
IP 0800
Chaos 0804
RFC 826 ARP 0806
Frame Relay ARP 0808
VINES 0BAD
VINES Echo 0BAE
VINES Loopback 0BAF
DECnet (Phase IV) 6003
Transparent Ethernet Bridging 6558
Raw Frame Relay 6559
Apollo Domain 8019
Ethertalk (Appletalk) 809B
Novell IPX 8137
RFC 1144 TCP/IP compression 876B
IP Autonomous Systems 876C
Secure Data 876D
Reserved FFFF
Offset юзается только когда включена опция routing.
Как видите, протокол достаточно полезный и интересный. Часто с помощью
него линкуют локальные сети поверх инета, в такие сетки вполне реально
проникнуть с помощью gre.
Пример использования GRE в FreeBSD:
1.
# kldload if_gre.ko # загружаем модуль обработчика протокола, если он
# не вкомпилён в ядро
Получим что-то подобное:
# kldstat
Id Refs Address Size Name
1 4 0xc0100000 2c1af8 kernel
3 1 0xc13d4000 6000 ipfw.ko
5 1 0xc14ab000 4000 if_gre.ko
# ifconfig gre0 create
# ifconfig gre0 tunnel this_ip gate_ip
# создаём point-to-point канал между нашей машиной и шлюзом
# ifconfig gre0 inet my_ip/30 gate_ip/30 netmask 255.255.255.252
# конфигурим ip-ranges той сети
# ifconfig gre0 up
или вот так (с помощью утилиты greconfig) логинимся в лан:
10.1.12.37 - my lan ip
10.1.12.38 - internal lan'z gate
212.25.240.34 - my internet ip
217.154.12.2 - lan'z gate inet ip
# ifconfig gre1 inet 10.1.12.37 10.1.12.38 netmask 255.255.255.252 up
# /usr/sbin/greconfig -i gre1 -v -s 212.25.240.34 -d 217.154.12.2
а на шлюзе:
# kldload if_gre.ko
# sysctl -w net.inet.ip.gre_default_mtu=1450
# ifconfig gre1 create
# ifconfig gre1 tunnel 217.154.12.2 212.25.240.34
# ifconfig gre1 mtu 1450
# ifconfig gre1 inet 10.1.12.38 10.1.12.37 netmask 255.255.255.252
# ifconfig gre1 up
==================================/ have a real phun with routnig tables /=====
Теперь пора поговорить про такое веселье как удалённая модификация
таблиц маршрутаризации на вражеском хосте. Это позволяет нам сделать
такой бесценный тип icmp пакетов как redirect. Но обо всём по порядку,
сперва стоит рассказать о том, как собственно, работает маршрутизация на
машине простого смертного.
Итак, как всё это работает. Допустим, мы создаём в проге сокет семейства
AF_INET (2), потом в его sin_addr загоняем ip конечного пункта и шлём, к
примеру UDP пакет. Как хост узнаёт куда доставлять его?? Вот для этого и
нужны таблицы маршрутаризации, которые ядро постоянно хранит в памяти.
Представьте себе таблицу с полями dest_addr, gateway и interface (вообще
всё посложнее там, но для примера сойдёт). Теперь для наглядности,
заполним её:
dest_addr gate interface
+---------------+-----------------+---------------
default 213.65.1.7 ppp0 (point-to-point)
10.0./16 10.0.0.1 eth0 (ethernet adapter)
Эти записи сообщают о том, что все пакеты по умолчанию отправляются на
шлюз с адресом 213.65.1.7, который присоединён каналом точка-точка. Во
второй строке говорится, что пакеты хостам с адресами 10.0.х.х нужно
слать на гейт 10.0.0.1, доступный через ethernet-сеть. Ядро пробегает
сперва записи для частных маршрутов (как вторая строка) а уж потом, если
не находит ничего подходящего, шлёт пакет дефолтовому гейту.
Допустим мы отправляем датаграмму на хост 10.0.13.37. Тогда ядро, после
вызова sendto() начинает искать в роутинговой таблице подходящий гейт
для отправки. Найдя его (10.0.0.1), она генерит ip и udp заголовок к
нашему пакету, причём ip_dest = 10.0.13.37, и упаковывает его в ehternet
фрейм, в котором в качестве адреса назначения ставит mac адрес гейта.
Тот, получив датаграмму, видит, что по dest_addr она адресована не ему,
и перенаправляет её дальше, прогнав ip назначения по своей роутиногвой
таблице. Вот собственно и вся теория касательно самого роутинга.
Пора поговорить о icmp_redirect пакетах. Итак, по rfc 1122 хосты (не
роутеры!!) обязаны обрабатывать такие сообщения, что есть большой плюс.
Формат icmp_redirect датаграммы:
0 7 15 31
+--------+--------+--------+--------+
I type I code I check sum I
+--------+--------+-----------------+
I new router addr I
+-----------------------------------+
I source IP-header + 64 bits of I
I original datagam I
+-----------------------------------+
поле type должно быть равно 5, код - сойдёт 0, на самом деле, роли не
играет код сообщения, он должен быть только в пределах 0..3.
new router addr - IP нового шлюза, на который будут отправляться
пакеты для dest_addr.
А теперь внимание!! После адреса нового шлюза должен присутствовать
заголовок сообщения, которое не удалось доставить данным маршрутом и
64 бита его содержимого (для идентификации). Ядра linux'a (все!),
FreeBSD и NetBSD, как оказалось после изучения исходников сетевого
стека tcp/ip, нихуя не смотрят на то, что ты суёшь после адреса нового
роутера, кроме поля dest_ip из присланного заголовка, и то просто чтоб
узнать к какому dest_addr приписать ip нового роутера. Так что мы
запросто можем состряпать нужный нам ip-заголовок, вставить свой ip
в качестве нового роутера и отправить какому-нибудь хосту своего lan'a,
тем самым поменяв ему таблицу маршрутизации (умные оси типа *nix не
удаляют старые роутинговые записи, а добавляют к данному конкретному
новую) и начать снифать весь его исходящий трафик для ip, который мы
поспуфали. Пример:
### host A (our victim) ###
таблица роутинга:
default 192.168.0.1 eth0 netmask 0.0.0.0
(такая маска соотвествует всем default записям и означает, что всем
адресам пакеты нужно слать через данный гейт)
192.168./16 196.168.0.15 eth0 netmask 255.255.0.0
ip: 192.168.0.15
### host X (our mad box)###
таблица роутинга:
default 192.168.0.1 eth0 netmask 0.0.0.0
192.168./16 196.168.0.15 eth0 netmask 255.255.0.0
ip: 192.168.13.37
Итак, нам необходимо чтобы пакеты шли через нашу машину, а не через
стандартный гейт 192.168.0.1. Для этого мы шлём такой пакет хосту A:
+----------------------------+
| IP header: |
| src_addr = 10.0.0.1 |
| dst_addr = 192.168.0.15 |
| proto = 1 (icmp) |
+----------------------------+
| ICMP header: |
| type = 5 (redirect) |
| code = 0 (net) | headerz
| new_gate: 192.168.13.37 |
+----------------------------+ ---
| fake IP header: |
| src_addr = 192.168.0.15 | payload area
| dst_addr = 13.6.6.6 |
| ... |
| + 64 bits of garbage |
+----------------------------+
Представим как его будет разбирать ядро хоста А: получено IP сообщение
с адресом назначения равным адресу данной машины. Протокол равен 1,
то бишь это ICMP пакет. Далее заголовок icmp + data передаются icmp-
обработчику, который видит, что это icmp_redirect сообщение. Далее он
выдирает из icmp-заголовка адрес нового шлюза, из присланного ip хидера
заимствует dst_addr (который у нас 13.6.6.6) и прогоняет его по таблице
роутинга. Видя, что нету специальных записей, подходящих к нему, он
берётся модифицировать default запись и прописывает гейтом туда наш new-
gate aka 192.168.13.37 leet box )) После этого таблица роутинга у жертвы
будет выглядеть вот так:
default 192.168.13.37 eth0 netmask 0.0.0.0
^^^^^ sp00fed d0ne!
192.168./16 196.168.0.15 eth0 netmask 255.255.0.0
Теперь мы получаем весь исходящий трафик с хоста А, занавес. Если же
система оказалась умна (типа BSD), то в списке появится просто новая
запись:
13.6.6.6 192.168.13.37 eth0
Но, конечно, самое интересное это провернуть данную атаку в инете, а не
в лане. С этим по идее должны возникнуть проблемы, т.к. многие роутеры
по ходу следования пакета могут его просто порезать из соображений
безопасности. Для таких вещей в IP есть такая опция как задание маршрута
когда в конце заголовка мы указываем маршрут, по которому нужно гнать
наш пакет. Подробностей не будет, читайте rfc. Но сама идея очень
полезна, мы можем к примеру обходить файрволы и прочий злой сетевой
шит.
Итак, что же мешает нам провернуть описанную атаку в инете?? Начнём с
того, что ядро перед модификацией роутинговой таблицы должно проверять,
доступен ли шлюз напрямую, тоесть до него должен быть 1 hop (короче он
должен быть доступен напрямую.. теоретически). Это проверяется видимо с
помощью пересчёта TTL,и конечно, установкой предельно малых значений TTL
когда пакет просто не может улететь далеко. Точно сказать не могу, т.к.
не смотрел, как всё это дело реализовано в ядре.
Но вот как-то поднимал pppd на одной из машин под FreeBSD, и при
коннекте увидел довольно интересную вещь: pppd как известно добавляет в
роутинговую таблицу ppp-гейт и при опции defaultroute делаёт данный
маршрут дефолтовым. Дык вот, после коннекта у меня в таблице появились
две записи:
default 217.42.85.3 netmask 0.0.0.0
217.42.85.3 63.75.196.112 ppp0
Причём ppp-линк соединял меня и машину 63.75.196.112. Выходит, что для
отправки пакетов, мне необходимо слать пакеты на неё, а оттуда уже
они уйдут на мой дефолтовый гейт 217.42.85.3. Самое интересное в том,
гейт мне недоступен напрямую, следовательно проверка как-то обходится.
Занчит есть немалая вероятность того, что можно провернуть это и не в
ppp. К примеру, мы находимся в 2х хопах от жертвы:
victim ---> gate ---> hax0r
hop1 hop2
Допустим нам нужно снифать её трафик до узла 3.1.33.7. Тогда мы шлём уже
2 пакета, один из которых ставит дефолтовым шлюзом нашу тачку, а вторым
делаем сслыку на неё через старый гейт. Получится что-то вроде:
default hax0r netmask 0.0.0.0
hax0r gate
Теперь всё должно работать как надо. Вопрос в том, какие дефолтовые
значения TTL ставит жертва, т.к. до нас пакет может просто не успеть
дойти. Вобщем, надо эксперементировать.
Кстати, интересный момент - по rfc роутеры не должны модифицировать свои
таблицы при icmp_redirect'ах. Но если в качестве роутера стоит *nix без
всяких файрволов и адванседных настроек, то мы можем рулить уже трафиком
всей сети!!
Вот какой роутинг настроен у balthost:
$ netstat -r
Routing tables
Internet:
Destination Gateway Flags Refs Use Netif Expire
default 194.204.33.254 UGSc 322 6915257 fxp0
localhost localhost UH 1 2792245 lo0
194.204.33 link#1 UC 2 0 fxp0
vm 00:02:b3:af:de:bf UHLW 1 2953207 lo0
194.204.33.254 00:09:44:2b:75:80 UHLW 320 0 fxp0 1199
$ exit
Вы видите, что по умолчанию все пакеты летят на 194.204.33.254, который
мы можем заменить своим хостом и сами рулить их трафиком, если находимся
не очень далеко от них.
host A
hacker --> gate <
host B
================================================/ Scan the net /===========
Теперь пару слов о поиске машин для данных атак. Для icmp_redirect, если
ты хочешь атаковать хост через lan, будет достаточно присутствия в одном
сегменте с жертвой. Для подобной атаки через интернет нюансов больше -
кпримеру Cisco рекомендует резать проходящие по инету пакеты icmp_redir,
и так далее, поэтому успех зависит от того какое железо стоит на пути до
таргета, какая ось у него стоит и какая используется сетевая топология.
При поиске хостов с поддержкой GRE/IPoIP зачастую достаточно следить за
входящими пакетами icmp error с кодом 2 ("protocol unreachable"). Очень
рекомендуется сканировать сети забугорных универов (особенно MIT, но там
очень много ibm-овских машин со спецефическимим осями типа Aix и не
менее оригинальным железом) в штатах и европе. Умные люди также советуют
сканить бразилию, но это не проверенная инфа ;). Кстати, в инклудах
лежит имага NERDC.gif, на скрине пример коммуниканикационной системы
университета Флориды (University of Florida - ufl.edu), но о подобных
штуках в другой раз..
# eof