Предисловие
Проснулся я сегодня с мыслью, что огромное количество инструкций по настройке NAT советуют использовать строку вида:
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Многие понимают проблемы этой конструкции, и советуют добавлять:
iptables -A FORWARD -i ppp0 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT
Но, зачастую, забывают задать таблице FORWARD действие DROP по умолчанию, или добавить правило REJECT в конец таблицы.
На первый взгляд, вроде бы, все кажется нормальным. Однако, это далеко не так. Дело в том, что если не запретить маршрутизировать трафик из WAN-порта в WAN-порт, кто-нибудь из вашей WAN-сети (предположим, что провайдер садит весь подъезд в одну /24) может маршрутизировать трафик через вас, просто прописав ваш IP в качестве шлюза. Все современные SOHO роутеры это учитывают, а вот неопытный администратор, который делает роутер под обычным linux, может не знать или забыть об этом. В подсети моего провайдера таких роутеров не оказалось, и мой план по захвату мира провалился. Однако, статья совсем не об этом.
Магические двоеточия
Как вы, может быть, знаете, многие современные программы и сервисы биндятся на IP :: (два двоеточия), а не на 0.0.0.0, как было раньше. IPv6 адрес :: значит то же самое, что и IPv4 0.0.0.0, т.е. «слушаем все интерфейсы». Многие считают, что если программа слушает ::, то этот сокет может принимать только IPv6-соединения, однако это далеко не так.
В IPv6 есть так называемое отображение IPv4-адресов в IPv6 диапазон. Если программа слушает сокет ::, а к ней обращаются из IPv4-адреса 1.2.3.4, то программа получит соединение с адреса ::ffff:1.2.3.4. Этого можно избежать, сделав:
sysctl -w net.ipv6.bindv6only=1
Но это нужно далеко не всегда, т.к. обычно удобно, что программа слушает один сокет, а получать соединения может по двум протоколам сразу. Практически во всех дистрибутивах, IPv6-сокеты ведут себя именно так, т.е. bindv6only=0.
fe80 и его друг ff02
Если вы не застряли в 90-х, вы гарантированно сталкивались с IPv6, сами того не зная. Абсолютно во всех современных операционных системах по умолчанию включена поддержка IPv6, а это значит, что на каждый (кроме редких исключений) интерфейс автоматически назначается IPv6 Link-Local адрес, который начинается с fe80::. Более того, в некоторых случаях этот адрес получается просто путем кодирования MAC-адреса.
Казалось бы, найти Link-Local адреса должно быть проблематично, они же все-таки длинные и страшные, но тут нам на помощь приходит мультикаст-диапазон ff02::.
Есть такой классный адрес: ff02::1. Если его попинговать (обязательно с указанием интерфейса, т.к. это Link Local адрес), то откликнутся все компьютеры в сети:
% ping6 ff02::1%enp4s0
PING ff02::1%enp4s0(ff02::1) 56 data bytes
64 bytes from fe80::21f:d0ff:fea2:46a3: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from fe80::fe8b:97ff:fe66:9100: icmp_seq=1 ttl=64 time=1.60 ms (DUP!)
64 bytes from fe80::226:9eff:fe6d:22a0: icmp_seq=1 ttl=64 time=1.62 ms (DUP!)
64 bytes from fe80::f2de:f1ff:fe27:3685: icmp_seq=1 ttl=64 time=1.70 ms (DUP!)
64 bytes from fe80::62a4:4cff:fe7b:1c90: icmp_seq=1 ttl=64 time=2.95 ms (DUP!)
64 bytes from fe80::fac0:91ff:fe32:5bbe: icmp_seq=1 ttl=64 time=3.02 ms (DUP!)
64 bytes from fe80::226:18ff:fe9e:4b3a: icmp_seq=1 ttl=64 time=3.09 ms (DUP!)
64 bytes from fe80::ba70:f4ff:fe8b:8dda: icmp_seq=1 ttl=64 time=3.14 ms (DUP!)
64 bytes from fe80::62a4:4cff:fea2:aee0: icmp_seq=1 ttl=64 time=3.27 ms (DUP!)
64 bytes from fe80::224:54ff:fedb:d17d: icmp_seq=1 ttl=64 time=3.93 ms (DUP!)
64 bytes from fe80::2a1:b0ff:fe40:904: icmp_seq=1 ttl=64 time=4.21 ms (DUP!)
64 bytes from fe80::76d0:2bff:fe69:31d8: icmp_seq=1 ttl=64 time=6.09 ms (DUP!)
Как мы видим, откликнулось 11 устройств. Кстати, этот адрес очень удобно использовать, если у вас, например, сервер настроен на получение адреса через DHCP, а DHCP упал, или если вы напрямую подключились к порту сервера, а DHCP поднимать не хочется. Вам остается просто зайти по fe80-адресу по ssh.
Если попинговать адрес ff02::2, то откликнутся все IPv6-роутеры в сети. К сожалению, в моем случае таких не было.
Сканируем роутеры
Я решил просканировать эти адреса через nmap, и вот что вышло:
% nmap -6 -T4 --open -n -iL list.txt
Скрытый текст
Starting Nmap 6.46 ( http://nmap.org ) at 2014-06-07 16:53 MSK
Nmap scan report for fe80::f2de:f1ff:fe27:3685
Host is up (0.0014s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
53/tcp open domain
Nmap scan report for fe80::fe8b:97ff:fe66:9100
Host is up (0.0012s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
53/tcp open domain
80/tcp open http
Nmap scan report for fe80::226:9eff:fe6d:22a0
Host is up (0.0012s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
53/tcp open domain
80/tcp open http
Nmap scan report for fe80::62a4:4cff:fea2:aee0
Host is up (0.00099s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::226:18ff:fe9e:4b3a
Host is up (0.00094s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::62a4:4cff:fe7b:1c90
Host is up (0.00085s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::76d0:2bff:fe69:31d8
Host is up (0.00072s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::fac0:91ff:fe32:5bbe
Host is up (0.00037s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::ba70:f4ff:fe8b:8dda
Host is up (0.00059s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::2a1:b0ff:fe40:904
Host is up (0.00077s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for fe80::224:54ff:fedb:d17d
Host is up (0.0012s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
23/tcp open telnet
Nmap done: 11 IP addresses (11 hosts up) scanned in 4.04 seconds
По IPv4 все эти порты закрыты.
Как мы видим, у многих роутеров открыт Telnet, веб-интерфейс и DNS извне по IPv6.
Что же это значит? Все просто — разработчики прошивки роутера просто-напросто забыли про IPv6.
Роутеры с открытым telnet:
- ASUS RT-N10 (2.0.3.2)
- ASUS RT-G32
- ASUS RT-G32.C1 (2.0.2.6)
- Upvel UR-312N4G
Роутеры с открытым веб-интерфейсом:
- D-Link DIR-615 (E4, 5.11NV)
- D-Link DIR-615 (E4, 5.11RU)
На многих из них были стандартные пароли admin/admin.
На большинстве этих роутеров ip6tables (iptables для IPv6) просто отсутствовал. Разработчики должны были либо вообще отключить поддержку IPv6 в ядре, либо убедиться, что http и telnet демоны слушают 0.0.0.0, а не :: но, по какой-то причине не стали этого делать.
А что, если…?
Если бы на роутере был каким-то образом настроен IPv6, и, соответственно, включена маршрутизация IPv6 пакетов (net.ipv6.conf.all.forwarding=1), а ip6tables либо вообще не настроен, либо настроен неправильно, то можно было бы точно так же, как в случае с IPv4, маршрутизировать пакеты через этот роутер.
Заключение
Некоторым компаниям я уже отправил письма об этих уязвимостях, а некоторым еще не успел. В любом случае, письма будут отправлены всем.
Используйте IPv6, не забывайте о нем.
P.S.
Для меня стало неожиданностью, что браузеры не умеют открывать адреса с указанием интерфейса. У меня никак не получилось открыть ссылку вида http://[fe80::a:b:c:d%enp4s0] во всех браузерах. Говорят, что знак процента нужно экранировать, т.е. http://[fe80::a:b:c:d%25enp4s0], но у меня и так не вышло. Пришлось использовать проброс портов.