-
Notifications
You must be signed in to change notification settings - Fork 0
Client Disruption
Qwavey edited this page Aug 23, 2026
·
1 revision
Deauth, Bluetooth disruption, and wired-LAN ARP/IPv6 kill.
Every command block below is that script's own --help output on the real device, pulled straight from its header comment - not retyped.
-
deauth.sh- Deauthenticate WiFi clients via PineAP (outside attacker or LAN-side). -
bluetooth.sh- Bluetooth recon + disruption over the Pager's internal radio. -
deadnet.sh- Disconnect wired-LAN devices via ARP-cache poisoning + IPv6 dead-router spoofing.
Deauthenticate WiFi clients via PineAP (outside attacker or LAN-side).
deauth.sh - Deauthenticate WiFi clients via PineAP. For clients you're NOT
connected to (an outside attacker knocking clients off a WiFi network).
Wraps PINEAPPLE_DEAUTH_CLIENT. For LAN-side disconnection when you ARE on
the network, use deadnet.sh instead - different tool, different trust model.
Only works on 2.4GHz/non-DFS 5GHz; PMF/WPA3/6GHz networks are resistant to
this by design.
Per Hak5's own docs: "Networks which utilize Protected Management Frames
(PMF) or the 802.11w standard will not be susceptible to injected
disconnection packets. All networks utilizing WPA3 also enable Protected
Management Frames... Some clients ignore disconnection attempts
deliberately regardless of the network type or channel." That's a
protocol-level ceiling, not a bug in this script - no deauth tool can
beat it. What this script CAN do is maximize pressure within that ceiling
(see --burst).
A single DEAUTH_CLIENT call only sends one round of disconnect packets -
real clients reassociate within a second or two, so this now REPEATS the
attack continuously (like a real deauth flood) until you stop it, instead
of firing once and exiting. Foreground: Ctrl+C stops it. Launched with
--background (what the wifi_deauth payload does): use --stop.
"Works sometimes" against a client that mostly stays connected (confirmed
via a real ping -t transcript showing occasional timeouts among mostly-
successful replies) is the EXPECTED signature of a client that reconnects
fast, not evidence the attack is broken - see --burst below, which raises
disruption pressure per window, and Hak5's own docs (quoted further down)
on PMF/802.11w and clients that deliberately ignore disconnects.
BUG FOUND AND FIXED (live-diagnosed): recon hops radio channels FAST -
confirmed by sampling `iw dev wlan1mon info` once a second, it showed a
DIFFERENT channel on almost every sample. Hak5's own docs say
DEAUTH_CLIENT "returns immediately... in the background, the PineAP
system will transmit" the packets - it's fire-and-forget, not
synchronous, and does not itself guarantee the radio is actually parked
on the target's channel the instant it transmits. If hopping had already
moved on by then, the deauth frame went out on the WRONG channel and did
nothing - the command still "succeeded" with no error, so this looked
exactly like "deauth just doesn't work" from the outside. Every attack
loop below now locks the radio to the target's channel (via the
official PINEAPPLE_EXAMINE_CHANNEL, confirmed live it reliably holds)
immediately before each transmission, and resets to normal hopping when
stopped.
Target defaults to FF:FF:FF:FF:FF:FF (every client of the AP) without
asking - picking one specific client isn't the normal case, so --pick no
longer prompts for it. Pass --target explicitly if you want just one.
BUG FOUND AND FIXED (live-diagnosed - the real explanation for reports
that "the whole network only gets deauthed sometimes"): --all used to
source its target list from recon's hostap_client table (which AP each
specific client MAC is associated to). Checked that table directly on a
real device mid-investigation and found it completely EMPTY - recon had
never recorded a single client association, so every round of the old
--all found zero targets and sent NOTHING, not "spread thin across many
devices". Hak5's own docs say the target argument accepts
"FF:FF:FF:FF:FF:FF for all clients" - broadcast target already
disconnects every client of a BSSID with no per-client MAC needed at
all. --all now attacks every AP recon has beaconed from (the `ssid`
table - reliably populated, --scan/--ssid/--pick already depend on it)
with a broadcast target instead - the same proven mechanism --ssid/
--bssid already use, just applied to every nearby AP instead of one.
IMPORTANT: only use this against networks/clients you are authorized to
test. Deauthenticating devices you don't own or don't have permission to
test may be illegal in your jurisdiction.
Usage:
deauth.sh --bssid AA:BB:CC:DD:EE:FF [--target MAC] --channel 6
deauth.sh --ssid "SSID name" [--target MAC]
deauth.sh --all
deauth.sh --scan
deauth.sh --pick
deauth.sh --stop
deauth.sh --status
deauth.sh interactive mode
Options:
--bssid MAC BSSID (MAC) of one specific access point
--ssid NAME Attack EVERY AP recon has seen broadcasting this exact
SSID, not just one BSSID - the normal case when
several access points share one name (a mesh
network, or just unrelated routers using the same
default name). --scan/--pick group by SSID for
exactly this reason.
--target MAC MAC of the client to disconnect (default: FF:FF:FF:FF:FF:FF, every client - you don't normally need to set this)
--channel N Channel to send disconnect packets on (only with --bssid - --ssid looks channels up per-AP itself)
--interval SECONDS Delay between repeat rounds while attacking (default: 2)
--burst N Deauth calls sent back-to-back within each
channel-locked window before sleeping
(default: 3). More packets per window = more
disruption pressure on clients that reconnect
fast - raise this if a target seems to only
partially disconnect. Doesn't help at all
against PMF/WPA3 (see above) - that's a wall,
not a density problem.
(--second-radio / raw injection on the internal radio: REMOVED. Caused
repeated hard hangs on real hardware - the kernel went silent with no
panic/oops trace, meaning a genuine USB/firmware-level lockup needing
a manual power cycle, not a soft crash. Also, "internal only" was
never a real choice via official commands either way - confirmed
live that DEAUTH_CLIENT/PINEAPPLE_EXAMINE_CHANNEL take no radio-
select parameter and always drive whichever radio PineAP itself
designates.)
CHASE MODE (automatic, no flag needed): with --ssid (a mesh/multi-AP
group) AND a specific --target (not the FF:FF:FF:FF:FF:FF broadcast
default), each round briefly re-checks which BSSID the target MAC
is actually transmitting from and prioritizes attacking THAT one -
instead of blind round-robin across every AP on a fixed schedule
regardless of where the target actually is. Built specifically for
mesh networks with roaming (802.11k/v/r): kicking a client off one
AP just bounces it to a sibling AP near-invisibly, so the real fix
isn't more attack surface, it's tracking where the client actually
went and following it there. See find_target_bssid() below. Falls
back to normal round-robin whenever the target hasn't been sighted
yet (unknown location - attack broadly until found).
REACTIVE MODE (--reactive flag, needs a specific --target): a
different strategy from chase mode above, and mutually exclusive
with it - chase mode still polls on a schedule (just prioritizing
smartly), reactive mode replaces the schedule entirely with an
event trigger. Live testing found that once a target IS located,
escalating burst pressure (3->5 packets/round) against it still had
ZERO observed effect - the target was reassociating within 1-2
seconds, faster than a full multi-AP attack round can even
complete once. That means the bottleneck isn't packets-per-round,
it's LATENCY: our reaction time to "the target is reconnecting
right now" versus theirs. Reactive mode closes that gap directly -
see run_reactive_strike() below for the mechanism.
--all Continuously deauth EVERY AP recon has seen a
beacon from (broadcast target = every client
of it, no per-client tracking needed), using
the Pineapple's own recon database
(/root/recon/recon.db - the same data the
physical Recon screen shows). Re-scans recon
each round, so newly-seen APs get picked up
too. Needs recon to have beaconed at least one
AP - normally just seconds, not the long wait
per-client tracking needed (see the file
header for why this changed).
--scan List nearby networks seen by recon, grouped by
SSID with an AP count (e.g. "Hotspot (3)") -
several BSSIDs sharing one name show as ONE
entry, not N separate ones. Read-only, no attack.
--pick Smart guided mode: if not connected to a WiFi
network, scan and let you pick one of the
nearby SSIDs seen by recon (grouped the same
way as --scan - picking one attacks every AP
broadcasting that name); if connected, uses
that specific network directly. Targets ALL
clients by default - pass --target yourself
first if you want one specific client.
--no-discover Skip real client-MAC discovery (see below) -
broadcast target only, starts attacking
immediately instead of a brief listen first.
--reactive EVENT-TRIGGERED STRIKE MODE (needs a specific
--target, not the broadcast default - see
REACTIVE MODE below). Instead of a fixed-
interval polling loop, continuously watches
for the target's own auth/(re)association
frames and fires an immediate priority
burst the instant one is seen, instead of
waiting out a scheduled round. Built
because live testing showed burst
escalation (more packets per round) had
zero effect against a target that
reassociates in 1-2s - the real gap is
LATENCY between our attack cadence and
theirs, not attack strength. Detection
watches plain decoded tcpdump text (grep
on decoded output, deliberately NOT a
`wlan type mgt subtype ...` BPF filter
primitive - see run_reactive_strike()'s
own header comment for why) for
"Authentication"/"Assoc Request"/
"ReAssoc Request" - keyword list
LIVE-VERIFIED against this exact tcpdump
binary via a synthetic pcap (see
run_reactive_strike()'s header comment):
the decoder abbreviates (re)association
frames as "Assoc Request"/"ReAssoc
Request", NOT the full spec names this
originally grepped for - that mismatch
would have silently caught Authentication
frames only and missed every real
(re)association attempt. Fixed and
re-verified. A SECOND, more fundamental
bug found the same way: tcpdump's default
summary line carries NO MAC address at
all for these frame types unless run with
"-e" - meaning the target-MAC match that
runs after the keyword match would have
matched nothing, ever, even with the
keyword fix above. Both tcpdump calls now
pass "-e".
--background Run the attack detached - use --stop to end it.
--stop Stop a background attack.
--status Is an attack currently running?
-y, --yes Skip the authorization confirmation
-h, --help This help
Client-MAC discovery (on by default, --bssid/--ssid/--pick, when TARGET
is left at the default broadcast): before attacking, briefly listens on
the target's (locked) channel for real client MAC addresses actually
active there, and - if any are found - targets each of them directly
with a unicast deauth every round, ALONGSIDE the normal broadcast
target. WHY: Hak5's docs confirm FF:FF:FF:FF:FF:FF is meant to hit every
client, but real-world WiFi driver behavior around broadcast-addressed
management frames varies - some are pickier about them than about a
frame addressed to their own exact MAC. This closes that gap without
depending on recon's own client tracking (confirmed elsewhere in this
file to be empty/unreliable on this device). One-time cost per attack
start (~2s), not repeated every round. Not used by --all (would mean
re-discovering on every AP, every round - too expensive to be worth it
there; --all stays broadcast-only).
Bluetooth recon + disruption over the Pager's internal radio.
bluetooth.sh - Bluetooth recon + disruption using the Pager's internal
radio (hci0, a MediaTek combo chip - confirmed live via `hciconfig -a`
and `lsusb`) and the standard BlueZ userspace tools that ship on this
device (bluez-utils/bluez-utils-extra - confirmed installed: hcitool,
l2ping, btmgmt, bluetoothctl).
IMPORTANT: unlike WiFi/PineAP, Hak5 does NOT document a dedicated
Bluetooth DuckyScript command family for the Pager (checked the full
docs - no BT_* commands exist). There is nothing to fabricate here - this
script just drives the real, standard Linux BlueZ stack directly, the
same tools you'd use on any Linux box with a Bluetooth adapter.
Four real disruption techniques:
--flood l2ping -f flood against ONE known/discoverable target MAC.
Real L2CAP echo flood, works against classic BT devices
(headphones/earbuds/speakers) that accept a connection.
Runs continuously until stopped (Ctrl+C, or --stop when
backgrounded) unless you set --duration.
--jam-area Scans first (classic AND BLE), then L2CAP-floods EVERY
device it found, on rotation, continuously - no target
to pick, jams whatever's discoverable nearby. Same stop
behavior as --flood.
--advspam Registers several rotating BLE advertising instances
(Bluetooth SIG's own reserved test company ID 0xFFFF,
not spoofing any real vendor/product) to disrupt nearby
BLE scanners/pairing UIs. Doesn't need a target either.
Unlike the other two, this hands the whole run off to
BlueZ itself (via btmgmt's own --duration) instead of
polling in a loop - btmgmt was found to hang
indefinitely if it's ever NOT the shell's direct
foreground process, so nothing here backgrounds it.
Runs for --duration (default 3600s) or until --stop.
--disrupt Real-world testing showed --flood/--jam-area don't touch
a device that's ALREADY connected+streaming to its real
owner (most peripherals refuse new connections outright
while busy - confirmed live, nothing to flood at all in
that case). This is different: no scan, no target, no
connection attempt of any kind. It puts the radio into
Direct Test Mode - a real, standard part of the
Bluetooth Core Spec every controller implements for RF
certification (HCI LE Transmitter Test / LE Test End,
confirmed live: accepted with status 0x00, i.e. the
controller genuinely entered continuous-TX mode) - and
cycles it across all 40 BLE channels (2402-2480MHz,
which is the ENTIRE 2.4GHz ISM band classic Bluetooth's
own frequency-hopping also lives in) continuously. This
doesn't care whether a device is connected, idle,
discoverable, or hidden - it just occupies the shared
spectrum directly. Still the Pager's own low-power BT
radio at its normal operating power (same hardware
--flood/--advspam already use) - not an external
amplifier or dedicated jamming device - so range is
short (close proximity), and it's genuinely not
guaranteed against every device. But it's the most
direct, real technique available that doesn't depend on
the target accepting a connection at all.
HONEST SCOPE NOTE: this specifically drives LE
(Bluetooth Low Energy) Direct Test Mode. Many audio
earbuds/headphones actually stream audio over CLASSIC
Bluetooth (BR/EDR, e.g. A2DP), which hops using its own
scheme across the same 2.4GHz band rather than BLE's -
the RF energy this produces still physically occupies
that same shared spectrum (there's only one 2.4GHz ISM
band, regardless of protocol label), but it isn't a
protocol-aware attack on the classic link specifically.
If disrupt still doesn't visibly affect a given device,
that's the most likely honest reason why - not
something a bigger --dwell alone can fully solve.
IMPORTANT: only use this against your own devices or ones you are
explicitly authorized to test. Disrupting other people's Bluetooth
devices may be illegal in your jurisdiction. --disrupt in particular
occupies shared spectrum other devices (yours and anyone else's in range)
rely on - keep it pointed at your own testing, not a shared/public space.
Usage:
bluetooth.sh --scan [--ble] [--duration SECONDS]
bluetooth.sh --flood MAC [--duration SECONDS] [--size BYTES]
bluetooth.sh --jam-area [--scan-time SECONDS] [--duration SECONDS]
bluetooth.sh --advspam [--duration SECONDS]
bluetooth.sh --disrupt [--duration SECONDS] [--dwell SECONDS] [--focus]
bluetooth.sh --stop
bluetooth.sh --status
bluetooth.sh interactive mode
Options:
--scan Discover nearby Bluetooth devices (classic).
--ble With --scan, also do a BLE (Low Energy) scan.
--flood MAC L2CAP echo flood against one target (DoS).
--jam-area Scan, then L2CAP-flood every device found,
on rotation, no target needed.
--advspam Flood the area with generic BLE adverts.
--disrupt Direct Test Mode spectrum occupation across
all 40 BLE channels - no scan, no target,
works on connected devices too. See above.
--dwell SECONDS With --disrupt: how long to hold each
channel before moving to the next
(default: 0.3). See the real-world
fix note on run_disrupt() - this is
the knob that actually matters.
--focus With --disrupt: only occupy the 3
FIXED BLE advertising channels
(37/38/39) instead of sweeping
all 40 - these are never hopped,
so this guarantees overlap with
any BLE scan/advertise/reconnect
activity instead of chasing a
moving target across 37 data
channels that Bluetooth's own
Adaptive Frequency Hopping will
actively route away from noise.
--scan-time SECONDS How long to scan (classic + BLE) before --jam-area starts (default: 15).
--burst SECONDS How long to flood EACH device per rotation in --jam-area
(default: 8 - a handful of packets barely dents an
active connection, this needs to be sustained).
--duration SECONDS How long to run (default: 15 for --scan; until stopped
for --flood/--jam-area/--disrupt; 3600s for --advspam).
--size BYTES l2ping payload size for --flood (default: 600).
--background Run detached; use --stop to end.
--stop Stop a background run.
--status Is a background run active?
-y, --yes Skip the authorization confirmation.
-h, --help This help.
Disconnect wired-LAN devices via ARP-cache poisoning + IPv6 dead-router spoofing.
deadnet.sh - Disconnect devices on the wired LAN via ARP-cache poisoning +
IPv6 dead-router spoofing (powered by deadnet, trimmed down from
https://github.com/flashnuke/deadnet - just the ~30KB core tool, not its
unrelated 71MB bundled Android app). For when you're ALREADY ON the
network - different tool/trust model than deauth.sh, which is for WiFi
clients you're NOT connected to.
This is the ONE place that actually runs deadnet - the deadnet_lan_kill
payload and the GUI both call this same script with the same arguments,
so behavior is identical no matter how you launch it.
Runs continuously until you press Ctrl+C - it does not stop on its own.
If started in the background (GUI/PayloadRunner --background), use
`deadnet.sh --stop` instead.
IMPORTANT: only run this against a network you are authorized to test.
Usage:
deadnet.sh [--iface eth1] [--gateway IP] [--gateway-mac MAC] [--sleep SECONDS]
deadnet.sh --discover [--iface eth1] just scan and list live hosts, don't attack
deadnet.sh --background run detached - use --stop to end it
deadnet.sh --stop
deadnet.sh --status
deadnet.sh interactive mode
Options:
--iface IFACE Wired interface to attack from (default: eth1)
--gateway IP Gateway IPv4 (default: auto-detected, x.x.x.1)
--gateway-mac MAC Gateway MAC (default: auto-detected via ARP)
--sleep SECONDS Re-poison interval (default: 5)
--cidr N Subnet size to attack (default: 24)
--disable-ipv6 Skip the IPv6 dead-router-advertisement attack
--no-discover Skip the pre-attack host discovery scan
--discover Only discover live hosts, don't attack
--background Run detached - see --stop/--status.
Output still goes to /tmp/pager-deadnet.log.
--stop Stop a run that was started in the background
--status Is a LAN kill currently running?
-y, --yes Skip the authorization confirmation
-h, --help This help
BUG FOUND AND FIXED (this file was previously excluded from bug-hunt/
improve passes as "good enough" - re-scoped in per user request): this
file's own header comment above used to say "If started in the
background (GUI/PayloadRunner --background), use `deadnet.sh --stop`
instead" - but no --background flag existed anywhere in the argument
parser. The deadnet_lan_kill payload worked around this by backgrounding
externally with a plain `&`, with no PIDFILE, no liveness check, and no
single-instance protection - the exact "black box, no feedback,
possible-double-launch" class of gap this toolkit's every OTHER
background-capable script (deauth.sh/sniff.sh/bluetooth.sh/tracer.sh/
EvilTwin.sh) already fixed for itself. Brought in line with that same
established PIDFILE + pid_running() + liveness-check pattern.
Host discovery: before attacking, this scans the subnet with nmap (a
quick ping sweep) and shows you exactly which real, live hosts are on
the LAN and about to be affected - not just "the whole subnet" as an
abstraction. The underlying deadnet attack still covers the full
subnet (that's how ARP poisoning works - you can't be selective about
who receives poisoned ARP replies without a different attack entirely),
but you now get told upfront who's actually there before you commit,
and the discovered host list is saved to loot alongside the run.