Бес­про­вод­ные сети — одна из важ­ней­ших сос­тавля­ющих сетево­го перимет­ра любой ком­пании. В сегод­няшней статье мы раз­берем­ся, как сво­ими силами обе­зопа­сить кор­поратив­ный Wi-Fi от зах­вата WPA handshake, PMKID, про­тиво­дей­ство­вать ата­кам GTC Downgrade, RogueAP, да еще и вывес­ти из строя исполь­зуемые хакером инс­тру­мен­ты.

У любой ком­пании прак­тичес­ки всег­да есть два перимет­ра: тот, что смот­рит в интернет, защищен­ный всем, чем мож­но, и физичес­кий — обра­зован­ный мно­гочис­ленны­ми бес­про­вод­ными устрой­ства­ми, не защищен­ный прак­тичес­ки никак. И это, пожалуй, самое боль­шое сле­пое пят­но в ИБ на сегод­няшний день. Реаль­ность такова, что если что‑то там ока­жет­ся уяз­вимо, то хакер неп­ремен­но возь­мет свое.

В статье «Са­мообо­рона по‑хакер­ски. Монито­рим ата­ки в ради­оэфи­ре» мы попыта­лись испра­вить эту нес­пра­вед­ливость, вос­ста­новить баланс сил свет­лой и тем­ной сто­роны и сде­лать некое подобие бес­про­вод­ной IDS (Intrusion Detection System). И в резуль­тате мы научи­лись детек­тить все акту­аль­ные на сегод­ня ата­ки на Wi-Fi.

info

Эта статья осно­вана на фраг­менте толь­ко что вышед­шей кни­ги «Ха­кер­ская само­обо­рона. При­емы обна­руже­ния и пре­дот­вра­щения хакер­ских атак».

Но мож­но ли как‑то активно мешать про­веде­нию этих атак? В этой статье мы сде­лаем свою бес­про­вод­ную IPS (Intrusion Prevention System), которая смо­жет пре­дот­вра­тить про­веде­ние боль­шинс­тва акту­аль­ных атак на Wi-Fi.

 

Противодействуем захвату WPA handshake

Зах­ват WPA handshake, час­то про­води­мый с исполь­зовани­ем ата­ки деаутен­тифика­ции, дает хакеру воз­можность под­бирать пароль к бес­про­вод­ной сети на очень боль­ших ско­рос­тях. Это одна из самых ста­рых и в то же вре­мя популяр­ных по сей день атак.

Са­ма ата­ка деаутен­тифика­ции дос­таточ­но быс­трая и реали­зует­ся отправ­кой все­го одно­го ради­опа­кета в обе сто­роны — на точ­ку дос­тупа и на стан­цию. Так что пытать­ся успеть как‑то заг­лушить этот пакет прак­тичес­ки невоз­можно.

Но давай пос­мотрим на эту ата­ку с дру­гой сто­роны, к чему она при­водит? А при­водит она к пов­торной отправ­ке и зах­вату хакером handshake. Так почему бы не дать хакеру то, что он хочет? Мы можем закидать его фей­ковыми handshake!

Сле­дующий хит­рый скрипт уме­ет генери­ровать half-handshake-фрей­мы — те самые, за которы­ми охо­тит­ся хакер:

defence/wifi/prevent/m2.py
#!/usr/bin/python3
from scapy.all import *
import hmac,hashlib,binascii
import random,string
from sys import argv
iface = argv[1]
ap = argv[2]
essid = argv[3]
sta = argv[4]
conf.verb = 0
COUNT = 20
WORDLIST = "/usr/share/wordlists/rockyou.txt"
words = open(WORDLIST).readlines(100000)
def get_password_brutable(min_len):
attempts = 10
while attempts:
word = random.choice(words).strip().lower()
if not "'" in word and min_len <= len(word):
return word
attempts -= 1
def get_password_unbrutable(len):
return "".join(map(lambda _:random.choice(string.printable[:95]), range(len)))
def beacon(ap, essid, count):
WPA = 'ESS+privacy'
RATE_1B = b"\x82"
RATE_2B = b"\x84"
RATE_5_5B = b"\x8b"
RATE_11B = b"\x96"
CHANNEL = 1
beacon = RadioTap()/Dot11(type=0, subtype=8, addr1='ff:ff:ff:ff:ff:ff', addr2=ap, addr3=ap)/\
Dot11Beacon(cap=WPA)/\
Dot11Elt(ID='SSID',info=essid, len=len(essid))/\
Dot11Elt(ID='Rates', info=RATE_1B+RATE_2B+RATE_5_5B+RATE_11B)/\
Dot11Elt(ID='ERPinfo', info=b"\x04")/\
Dot11Elt(ID='DSset', info=int(CHANNEL).to_bytes(1,'big'))/\
Dot11Elt(ID=48, len=20, info=b'\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x02\x00\x00')
sendp(beacon, iface=iface, inter=0.01, count=count, verbose=False)
anonce = None
def m1(ap, sta, count):
global anonce
def get_rand(n):
o = b''
for _ in range(n):
o += int(random.random()*255).to_bytes(1, 'big')
return o
anonce = get_rand(32)
eapol_data_4 = bytearray(95)
eapol_data_4[0:1] = b"\x02" # Key Description_type
eapol_data_4[1:3] = b"\x00\x8a" # Key Information
eapol_data_4[3:5] = b"\x00\x10" # Key Length
eapol_data_4[5:13] = b"\x00\x00\x00\x00\x00\x00\x00\x01" # Replay Counter
eapol_data_4[13:45] = anonce
eapol_data_4[45:61] = b"\x00"*16 # Key IV
eapol_data_4[61:69] = b"\x00"*8 # WPA Key RSC
eapol_data_4[69:77] = b"\x00"*8 # WPA Key Id
eapol_data_4[77:93] = b"\x00"*16 # WPA Key Mic
eapol_data_4[93:95] = b"\x00"*2 # WPA Key Data Length
m1 = RadioTap() / Dot11(proto=0, FCfield=2, addr1=sta, addr2=ap, addr3=ap, subtype=8, SC=0, type=2, ID=55808) \
/ Dot11QoS(TID=6, TXOP=0, EOSP=0) \
/ LLC(dsap=0xaa, ssap=0xaa, ctrl=0x3) \
/ SNAP(OUI=0, code=0x888e) \
/ EAPOL(version=1, type=3, len=95) / bytes(eapol_data_4)
sendp(m1, iface=iface, count=count, inter=0.01, verbose=False)
def m2(ap, sta, count):
global anonce
def assemble_EAP_Expanded(self, l):
ret = ''
for i in range(len(l)):
if l[i][0] & 0xFF00 == 0xFF00:
ret += (l[i][1])
else:
ret += pack('!H', l[i][0]) + pack('!H', len(l[i][1])) + l[i][1]
return ret
def PRF_512(key,A,B):
return b''.join(hmac.new(key,A+chr(0).encode()+B+chr(i).encode(),hashlib.sha1).digest() for i in range(4))[:64]
def get_rand(n):
o = b''
for _ in range(n):
o += int(random.random()*255).to_bytes(1, 'big')
return o
def b(mac):
o = b''
for m in mac.split(':'):
o += int(m, 16).to_bytes(1, 'big')
return o
password = get_password_brutable(8)
#password = get_password_unbrutable(8)
print(f"[*] send {password}")
pmk = hashlib.pbkdf2_hmac('sha1', password.encode(), essid.encode(), 4096, 32)
snonce = get_rand(32)
ptk = PRF_512(pmk, b"Pairwise key expansion", min(b(ap),b(sta))+max(b(ap),b(sta))+min(anonce,snonce)+max(anonce,snonce))
kck = ptk[0:16]
rsn_cap = b"\x30\x14\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x02\x00\x00"
eapol_data_4 = bytearray(117)
eapol_data_4[0:1] = b"\x02" # Key Description Type: EAPOL RSN Key
eapol_data_4[1:1+2] = b"\x01\x0a" # Key Information: 0x010a
eapol_data_4[3:3+2] = b"\x00\x00" # Key Length: 0
eapol_data_4[5:5+8] = b"\x00\x00\x00\x00\x00\x00\x00\x01" # Replay Counter: 1
eapol_data_4[13:13+32] = snonce # WPA Key Nonce
eapol_data_4[45:45+16] = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # WPA Key IV
eapol_data_4[61:61+8] = b"\x00\x00\x00\x00\x00\x00\x00\x00" # WPA Key RSC
eapol_data_4[69:69+8] = b"\x00\x00\x00\x00\x00\x00\x00\x00" # WPA Key ID
eapol_data_4[77:77+16] = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # WPA Key MIC
eapol_data_4[93:93+2] = b"\x00\x16" # WPA Key Data Length: 22
eapol_data_4[95:95+26] = bytes(rsn_cap) # WPA Key Data Length
mic = hmac.new(kck, b"\x01\x03\x00\x75" + bytes(eapol_data_4[:77]) + bytes.fromhex("00000000000000000000000000000000") + bytes(eapol_data_4[93:]), hashlib.sha1).digest()[0:16]
eapol_data_4[77:77+16] = mic
m2 = RadioTap() / Dot11(proto=0, FCfield=1, addr1=ap, addr2=sta, addr3=ap, subtype=8, SC=0, type=2, ID=55808) \
/ Dot11QoS(TID=6, TXOP=0, EOSP=0) \
/ LLC(dsap=0xaa, ssap=0xaa, ctrl=0x3) \
/ SNAP(OUI=0, code=0x888e) \
/ EAPOL(version=1, type=3, len=117) / bytes(eapol_data_4)
sendp(m2, iface=iface, count=count, inter=0.01, verbose=False)
for _ in range(COUNT):
beacon(ap, essid, 5)
m1(ap, sta, 5)
m2(ap, sta, 10)

Что­бы хакер­ское ПО сре­аги­рова­ло в момент зах­вата handshake, мы дол­жны отпра­вить в ради­оэфир три пакета: beacon, EAPOL M1 и M2. Добав­ляем стро­ку вызова это­го prevention-при­ема в detect-скрипт ата­ки деаутен­тифика­ции:

defence/wifi/deauth.py
...
def alert(src, dst, signal, essid):
...
system(f"prevent/m2.py {iface} {src} '{essid}' {dst}")
...

www

Пол­ный код всех detect-скрип­тов при­веден в GitHub авто­ра.

В резуль­тате мы получа­ем готовое средс­тво обна­руже­ния зах­вата WPA handshake, ата­ки деаутен­тифика­ции и реаги­рова­ния на нее. В ту же секун­ду, ког­да мы обна­ружи­ваем ата­ку, запус­кает­ся механизм ее пре­дот­вра­щения — в ради­оэфир один за дру­гим начина­ют уле­тать хеши несущес­тву­ющих паролей.

Предотвращаем атаку захвата handshake — отправляем в эфир фейковые хеши
Пре­дот­вра­щаем ата­ку зах­вата handshake — отправ­ляем в эфир фей­ковые хеши

Ха­кер же видит у себя весь­ма радуж­ную, на пер­вый взгляд, кар­тину — ему один за дру­гим начина­ют при­летать жела­емые handshake.

Хакер захватывает фейковые handshake
Ха­кер зах­ватыва­ет фей­ковые handshake

Но он еще не зна­ет, с чем стол­кнул­ся… Зах­ватив handshake, хакер пос­пешит их извлечь в фор­ме хеша, под­ходяще­го для брут­форса. И тут начина­ется самое инте­рес­ное. Если хакер запус­тит стан­дар­тную коман­ду извле­чения хешей, то он получит все­го один из них.

Хакер извлекает из трафика ложный handshake
Ха­кер извле­кает из тра­фика лож­ный handshake

Как пра­вило, при таких ата­ках пред­полага­ется, что по ради­оэфи­ру про­лета­ет вер­ный хеш пароля к бес­про­вод­ной сети и мно­жес­тво раз его зах­ватывать нецеле­сооб­разно. Ведь чем боль­ше хешей, тем доль­ше их под­бор по сло­варю. Это озна­чает, что, даже если в ради­офи­ре и про­летел хеш нас­тояще­го пароля, мы, ско­рее все­го, его переза­писа­ли сво­ими фей­ковыми handshake. Давай пос­мотрим, что сбру­тит хакер.

Хакер подбирает неверный пароль к беспроводной сети
Ха­кер под­бира­ет невер­ный пароль к бес­про­вод­ной сети

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии