Часто компании имеют свою внутреннюю сеть, которая подключена к интернету через маршрутизатор (или роутер, router). Обычно на таком маршрутизаторе работает firewall, который может фильтровать сетевой трафик. Бывает, что компания не хочет, чтобы компьютеры (и прочие устройства) из внутренней сети имели доступ к интернету. Это может уменьшить вероятность просачивания важной, секретной и не очень информации в интернет. Или начальство просто не хочет, чтобы работники сидели в их любимых социальных сетях в рабочее время. В таком случает firewall может быть настроен на блокирование большинства TCP/UDP соединений с интернетом. “DNS tunneling” может помочь при обходе такого firewall’а при условии, что он пропускает запросы к DNS серверам в интернете.

Вообще существует множество инструментов, которые позволяют реализовать такой DNS-туннель. Но здесь речь пойдет о том, как это сделать с одной лишь Java без использования каких-либо дополнительных библиотек.

(English version - DNS tunneling with Java)

Что такое DNS туннель

Задачей DNS (Domain Name System) является преобразование доменного имени в IP адрес. Когда кто-то хочет узнать IP адрес для какого-то доменного имени, он посылает запрос к DNS серверу. Но этот сервер может не знать ответы на все вопросы. Поэтому DNS запросы часто бывают рекурсивными. Это значит, что DNS сервер может обратиться к другому DNS серверу, если он не знает IP адреса для какого-то имени.

Представим на минутку, что злобному злоумышленнику удалось уговорить, заставить или соблазнить сотрудника банка загрузить Java applet на свой рабочий компьютер во внутренней сети банка. Еще допустим, что этому applet’y удалось убежать из песочницы Java Plugin и получить доступ ко всем операциям, которые только можно совершить будучи Java applet’ом (к сожалению, такие случаи медицине известны). Теперь злобному злоумышленнику необходимо установить соединение с этим applet’ом, чтобы получить доступ к компьютеру несчастного сотрудника банка. Но пресловутый firewall блокирует обычные TCP/UDP соединения, которые идут к чему-то или от чего-то, что находится вне внутренней сети компании. В таком случае может помочь DNS tunneling, если противный firewall пропускает DNS запросы к внешним серверам.

Для удобства будем называть Java applet клиентом. И пусть коварный злоумышленник располагает своим сервером в интернете. Пусть на сервере злоумышленника работает его собственный DNS сервис, который отвечает за поддомены на ‘attacker.com’. Злоумышленник хочет передавать данные между этим клиентом и сервером. Как мы помним, клиент (Java applet) находится во внутренней сети компании. Пусть в этой сети имеется свой внутренний DNS сервер, который знает IP адреса для внутренних имен в этой сети (обычное дело). Чтобы передать какие-то данные на сервер, клиент кодирует их с помощью BASE32 кодировки и полученную строку использует как поддомен на attacker.com. Например, BASE32 кодировка превратит строку ‘hello’ в ‘NBSWY3DP’, и мы получим поддомен ‘NBSWY3DP.attacker.com’. Дальше клиент пытается получить IP адрес для этого доменного имени. Для этого он отправляет DNS запрос ко внутреннему DNS серверу компании. Это сервер ничего не знает о поддоменах на attacker.com, но он может выяснить, какой DNS сервер отвечает за это домен и отправить ему запрос о ‘NBSWY3DP.attacker.com’. Этим сервером является DNS сервер хитрого злоумышленника. Если корпоративный firewall не блокирует DNS запросы к внешним серверам, то внутренний сервер успешно отправит такой запрос к серверу злоумышленника. Дальше, DNS сервер злоумышленника раскодирует строку ‘NBSWY3DP’, и получит заветное ‘hello’. Таким образом клиент передает данные серверу. Сервер же может передать данные клиенту вместе с DNS ответом, например, используя TXT поле в DNS ответе. В результате между клиентом и сервером возникает двунаправленный канал для обмена сообщениями, который и называется DNS туннелем.

Как сделать DNS туннель из Java

Java умеет работать с DNS, и это не требует каких-либо дополнительных библиотек. За это отвечает JNDI (Java Naming and Directory Interface). Если коварному злоумышленнику удалось заставить несчастного пользователя запустить вредоносный Java applet, то шанс установить DNS туннель может быть довольно большим (хотя заставить пользователя запустить этот Java applet может быть не так просто с новыми версиями Java, хотя такие случаи тоже медицине известны).

Здесь можно посмотреть на реализацию DNS tunneling на Java, хотя это вряд ли готово для использования в быту:

https://github.com/artem-smotrakov/java-dns-tunneling

  1. В “src” лежит код на Java:
  2. DNSTunnelServer.java это простенький DNS сервер, который запускается на attacker.com и который отвечает за одноименный домен. Этот сервер также принимает команды, которые необходимо отправить клиенту.
  3. DNSTunnelClient.java это клиент, который должен быть запущен на компьютере бедной жертвы злоумышленника. В состав DNSTunnelClient входит DNS клиент, который работает через JNDI. Это клиент отсылает DNS запросы к DNSTunnelServer через внутренний DNS сервер компании. В DNS ответах клиент получает команды он злоумышленника, которые он тут же выполняет на компьютере несчастной жертвы.
  4. Payload.java это Java applet. Злобный злоумышленник должен всеми правдами и неправдами уговорить свою жертву запустить этот applet.
  5. CrockfordBase32.java просто реализует BASE32 кодирование и декодирование.
  6. Command.java запускает команды с помощью ProcessBuilder API.
  7. Server.java это простенький telnet-сервер, который слушает порт, принимает команды и выполняет их. Payload.java может запускать этот telnet-сервер. Вообще говоря, Server.java не используется для DNS tunneling, а просто был написан для экспериментов с ProcessBuilder API.
  8. SimpleHttpServer.java это простой HTTP сервер, который я использовал для тестирования. На нем можно разместить Payload applet.
  9. В “scripts” лежат некоторые полезные скрипты:
  10. Всем скриптам нужна переменная JAVA_HOME, которая должна содержать путь к JDK 8
  11. compile.sh компилирует Java код
  12. gen.sh упаковывает классы в jar-файл, генерирует самоподписанный (self-signed) сертификат и мгновенно подписывает им свеженький jar-файл.
  13. run_http.sh запускает SimpleHttpServer
  14. manifest.mf это манифест-файл для Java applet, который содержит атрибут “Permissions”, который требуют современные версии Java Plugin.

Как запустить DNS туннель

Для тестирования я использовал две виртуальные машины на Virtual Box:

  1. Для начала надо запустить обыкновенный DNS сервер (не DNSTunnelServer), который будет выполнять роль внутреннего DNS сервера компании. Этот DNS сервер должен перенаправлять DNS запросы о поддоменах attacker.com туда, где запущен DNSTunnelServer.
  2. Дальше надо в VM #1 запустить DNSTunnelServer, который отвечает за поддомены attacker.com. Это будет компьютер злобного злоумышленника.
  3. Потом на этой же машине хитрого злоумышленника надо запустить SimpleHttpServer, который будет содержать Payload applet, например, на http://attacker.com/index.html
  4. И наконец надо в другой VM #2 запустить web-browser и открыть http://attacker.com/index.html. Это будет компьютер ничего не подозревающей жертвы. Если используются последние версии Java (на что очень хочется надеяться), то появятся много сообщений с вопросами о том, действительно ли вы хотите запустить этот applet. Возможно даже придется нажать пару педалей в настройках Java Plugin, чтобы можно было запустить этот applet. Все зависит от используемой версии Java.

В результате на VM #1 можно отдавать команды DNSTunnelServer’у, которые он передаст Payload applet’y на VM #2. В свою очередь, Payload applet эти команды запустит и отправит результаты обратно DNSTunnelServer’у. Все это будет происходить лишь с использованием DNS протокола.

Этот проект работает только с Java 8 и выше (кое-где используются лямбды, а также прочие свистелки и перделки), но его можно адаптировать и к более старым версиям Java.