Scapy[1] is one mighty python tool to create, receive and manipulate various network packets and it comes with a very handy CLI as well. If you ever had the need to create specific network packets within a program, I suggest you use python together with scapy to do so. Let’s start with a short introduction to the scapy CLI and end with a small example of scapy within python code. With the right kind of WLAN interface it is even possible to create a connection to an unencrypted SSID and I am going to publish the steps to do so in another post.
Pleate note: The following commands were made on a Fedora 23 Linux system with an TP-Link TL-WN727N (v4.1) WLAN USB Stick. The scapy package can be installed as python-scapy (Ubuntu) or just scapy (Fedora), wireshark is also required. Your linux and python skills should be quite solid and include knowledge about the use of ifconfig and iwconfig in linux as well as class definition and inheritance in python.
Scapy CLI
After using a bash to call “scapy”, the CLI should show up and should look like this (Your version might be different):
Welcome to Scapy (2.2.0) >>>
You can take a look at all the predefined protocols via the “ls()” command…
>>> ls() ARP : ARP ASN1_Packet : None BOOTP : BOOTP CookedLinux : cooked linux DHCP : DHCP options [...]
… and get some details about them via “ls(<PROTOCOL>)” e.g. ls(ARP):
>>> ls(ARP) hwtype : XShortField = (1) ptype : XShortEnumField = (2048) hwlen : ByteField = (6) plen : ByteField = (4) op : ShortEnumField = (1) hwsrc : ARPSourceMACField = (None) psrc : SourceIPField = (None) hwdst : MACField = ('00:00:00:00:00:00') pdst : IPField = ('0.0.0.0')
Since we want to send WLAN packets, the following predefined protocols can be used “out of the box”:
Dot11 : 802.11 Dot11ATIM : 802.11 ATIM Dot11AssoReq : 802.11 Association Request Dot11AssoResp : 802.11 Association Response Dot11Auth : 802.11 Authentication Dot11Beacon : 802.11 Beacon Dot11Deauth : 802.11 Deauthentication Dot11Disas : 802.11 Disassociation Dot11Elt : 802.11 Information Element Dot11ProbeReq : 802.11 Probe Request Dot11ProbeResp : 802.11 Probe Response Dot11QoS : 802.11 QoS Dot11ReassoReq : 802.11 Reassociation Request Dot11ReassoResp : 802.11 Reassociation Response Dot11WEP : 802.11 WEP packet [...] RadioTap : RadioTap dummy
A quick example of how to send a Dot11 frame, e.g. a Null Frame, from an AP (e.g. MAC = 00:a0:57:98:76:54) to a Client (STA) (e.g. MAC = 00:a0:57:12:34:56) is:
>>> ls(Dot11) subtype : BitField = (0) type : BitEnumField = (0) proto : BitField = (0) FCfield : FlagsField = (0) ID : ShortField = (0) addr1 : MACField = ('00:00:00:00:00:00') addr2 : Dot11Addr2MACField = ('00:00:00:00:00:00') addr3 : Dot11Addr3MACField = ('00:00:00:00:00:00') SC : Dot11SCField = (0) addr4 : Dot11Addr4MACField = ('00:00:00:00:00:00') >>> packet = Dot11(addr1="00:a0:57:12:34:56", addr2="00:a0:57:98:76:54", addr3="00:a0:57:98:76:54", type=2, subtype=4)
The addr1 field defines the destination/receiver, addr2 the source/transmitter and addr3 the BSSID of the frame. The Null frame is defined as type 2 and subtype 4. One of the most powerful possibilities of the scapy CLI is the direct call of wireshark to inspect a packet. This is as handy as:
>>> wireshark(packet)
A wireshark window should open and display the packet as shown in the following screenshot:
Creating a customized packet
Although there are a lot of predefined protocols/packets, we do need to create certain packets/protocols like e.g. information fields manually. This is where python comes into play and a more elaborate introduction can be found at [2].
We import scapy and create a class that is derived from scapy.Packet. Besides the class member name, the fields_desc is the most important variable. With the help of ByteField from scapy, we can create new information elements like ID and length of the included elements as well as the supported rates themselves by setting up a list of supported rates in hexadecimal notation and insert these values in ByteFields. Since each ByteField is unique, the names of the fields for supported rates need to differ, that’s why we enumerate the values and create them with supported_rate1, supported_rate2 and so on.
from scapy.all import * class Dot11EltRates(Packet): """ Our own definition for the supported rates field """ name = "802.11 Rates Information Element" # Our Test STA supports the rates 6, 9, 12, 18, 24, 36, 48 and 54 Mbps supported_rates = [0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c] fields_desc = [ByteField("ID", 1), ByteField("len", len(supported_rates))] for index, rate in enumerate(supported_rates): fields_desc.append(ByteField("supported_rate{0}".format(index + 1), rate))
You can either enter the values of the defined fields as hexadecimal ones with “0x” in front or as integers like the value of the “ID” ByteField in the example above. It is important that the byte value of the “len” field matches length of the successive byte elements.
Sending a (customized) packet
If we want to send a packet via python/scapy, we first have to set up our monitoring interface, which will be our USB WLAN Stick. We can use the command “iwconfig” in a bash to find the all the installed WLAN interfaces, use “ifconfig” to identify the right one via MAC address if you got more than one WLAN interface. In my case the TP-Link WLAN USB Stick is named “wlp0s29u1u7”. For the following steps, you need to be root or use sudo to configure the stick to the required monitor mode.
1) Turn the interface down via “ifconfig wlp0s29u1u7 down”
2) Set the device to monitor mode via “iwconfig wlp0s29u1u7 mode monitor”
3) Turn the interface back on via “ifconfig wlp0s29u1u7 up”
4) Set the interface to a certain channel via “iwconfig wlp0s29u1u7 chan 6”
5) If the settings were correctly adapted, the output of “iwconfig wlp0s29u1u7” includes “Mode:Monitor” and “Frequency:2.437 GHz” (for channel 6 in this example).
We can now use this interface to send packets via scapy. The following python code builds an association request packet via the predefined Dot11, Dot11AssoReq and Dot11Elt packets and extends the packet with rate information that is defined in the class given above. Afterwards we use the “sendp()” command to send the packet on the defined monitoring interface.
packet = Dot11( addr1="00:a0:57:98:76:54", addr2="00:a0:57:12:34:56", addr3="00:a0:57:98:76:54") / Dot11AssoReq( cap=0x1100, listen_interval=0x00a) / Dot11Elt( ID=0, info="MY_BSSID") packet /= Dot11EltRates() sendp(packet, iface="wlp0s29u1u7") packet.show()
The code has to be executed as root or via sudo due to the control over the network interface. The script will output a warning, that no route for IPv6 destination :: could be found (happens during import of scapy and can be ignored) afterwards a “.” and the message “Sent 1 packets” should be visible, which means that the created packet was sent.
WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6 . Sent 1 packets.
Due to the packet.show() command at the end of our code, scapy will also print the packet to the standard output:
###[ 802.11 ]### subtype = 0 type = Management proto = 0 FCfield = ID = 0 addr1 = 00:a0:57:98:76:54 addr2 = 00:a0:57:12:34:56 addr3 = 00:a0:57:98:76:54 SC = 0 addr4 = 00:00:00:00:00:00 ###[ 802.11 Association Request ]### cap = ESS+privacy listen_interval= 10 ###[ 802.11 Information Element ]### ID = SSID len = None info = 'MY_BSSID' ###[ 802.11 Rates Information Element ]### ID = 1 len = 8 supported_rate1= 12 supported_rate2= 18 supported_rate3= 24 supported_rate4= 36 supported_rate5= 48 supported_rate6= 72 supported_rate7= 96 supported_rate8= 108
You might have noticed that scapy does not print the length of the 802.11 Information Element containing the SSID info. The length is calculated automatically while sending the packet and not while it is printed. See the following screenshot in the Conclusion for proof.
Conclusion
Within the examples given in this post, we are able to create packets based on predefined ones in scapy and are able modify or create certain elements via python. If you are able to sniff the packet on the air, we can take a look at it in wireshark:
Following up is the complete code.
from scapy.all import * class Dot11EltRates(Packet): """ Our own definition for the supported rates field """ name = "802.11 Rates Information Element" # Our Test STA supports the rates 6, 9, 12, 18, 24, 36, 48 and 54 Mbps supported_rates = [0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c] fields_desc = [ByteField("ID", 1), ByteField("len", len(supported_rates))] for index, rate in enumerate(supported_rates): fields_desc.append(ByteField("supported_rate{0}".format(index + 1), rate)) packet = Dot11( addr1="00:a0:57:98:76:54", addr2="00:a0:57:12:34:56", addr3="00:a0:57:98:76:54") / Dot11AssoReq( cap=0x1100, listen_interval=0x00a) / Dot11Elt( ID=0, info="MY_BSSID") packet /= Dot11EltRates() sendp(packet, iface="wlp0s29u1u7") packet.show()
Links
[1] http://www.secdev.org/projects/scapy/
[2] http://www.secdev.org/projects/scapy/doc/build_dissect.html
[…] on my previous post on how to send WLAN frames via Scapy, see Using Scapy to send WLAN frames, I want to demonstrate how to establish a connection to an unencrypted SSID with a WLAN interface […]
LikeLike
Hi, thank you for your detailed post.
I also created a script to send 80211 frames using Scapy some
time ago, but I’m facing a problem:
You’re defining the adapters capabilities and supported rates in the variable “supported_rates”.
But what if I don’t know which wifi adapter I will use or if I want to develop a script that is compatible to a large number of wifi adapters?
Do you know a way how to read the current wifi adapters capabilities with python in order to automatically use those for sending Association frames?
Regards,
Bastian
LikeLike
Hello Bastian,
sorry for this quite late response. I don’t think that there should be a problem with the wifi adapters since they usually support all 11a/g rates. Nonetheless, there might be some WLAN APs with configurations that exclude certain 11a/g rates within the basic rate field for various reasons.
You could sniff the beacons from the WLAN AP you want to attack and adjust the supported rates field accordingly, which can be done either manually or via script. However, I found it rather complicated to modify this field dynamically and did not succeed with my initial attempt to implement that. But I guess it’s still possible to do.
LikeLike
hello ! i find how to send packet due to your post, Thank.
and I’d like to receive packet by using srp function. Do you know how to receive Probe response, Authtification, Association response packet?
I capture packet on wireshark, Probe responses, Auth packetes are sended to LAN card that i forge packet’s MAC address
LikeLike
Hi there,
since I’ve been on vacation the last two weeks, I didn’t have access to my code. Is this still bothering you?
kind regards,
mtroi
LikeLike
Hey there,
thank you for this quick-start – works like a charm and helps a lot in reverse engineering and understanding some protocols.
Btw… is there any good documentation around? I am in search for all available cap flag e.g.
LikeLike
I am unable to send packets using the script above. System says it sent the packet, but when I capture on Wireshark on MacBook Pro, I can’t see the packet I sent but I can see all other packets. What else could be wrong ? Sending the packets on 2019 Kali linux.
LikeLike
Hello,
scary hands the packet over to the adapter and tells you that it sent the packet, but it’s no prove that it actually did. What kind of adapter are you using? Do you operate the adapter on a channel/band that it does not support?
Regards,
mtroi
LikeLike
Hello mtroi,
Thanks for the post. I wonder if scapy would be able to send the WiFi DATA packet? At the receiver end, are we able to capture the ACK packet? I have read several posts and examples but haven’t seen any posts regarding wifi data and ACK packets. Many of the posts talked about the Beacon, probe request, etc.
Thanks.
Justin
LikeLike
After the client successfully connected to an AP, you can send whatever frame you want. However, the ACK packets are usually generated in reply to Unicast packets by the Wi-Fi card itself. So unless you want to irritate a sender by sending fake ACKs, you should not need to create ACK frames in Scapy. See also my other post and the comments below it: https://wlan1nde.wordpress.com/2016/08/24/fake-a-wlan-connection-via-scapy/
LikeLike
Thanks mtroi. Glad to know it is doable.
I want to ask a follow-on question. Say I have two devices, one configured as AP and another one configured as STA. When I use scapy to send DATA packet from AP to STA, after the STA receives the DATA packet successfully, it will reply an ACK packet to the AP. Will the AP be able to capture the ACK packet in Scapy?
The reason that I am asking this is that the STA will reply with the ACK packet after the SIFS, which is in the order of 10 microseconds. Will there be sufficient time for the AP to switch between the transmission mode and the receiving mode?
LikeLike
Why shouldn’t it? Since this is the norm, I would assume you can also see that frame in scapy. Go ahead and try it and give feedback here. 🙂
LikeLike
good
good
good
But I would like to know that I have established a beacon hotspot through scapy. When I try to connect to this hotspot with a device, the device will not actually initiate a connection request. I cannot capture any probe response or Auth/Assoc etc. Response packet. It seems useless. If I want to use python scapy to fully implement a real hotspot similar to airbase or hostapd, can I refer to those examples?
LikeLike
Sorry, I don’t know how to help you here?! Could you clarify this a bit further?
LikeLike
Hi Please see below detail :
1. I have used Scapy to create a beacon frame, and I can search this Wifi hotspot using my cell phone.
2. But when I am tring to connect to this hotspot, there is no response.
3. Then I tried to use wireshark to sniff for the packet but there is nothing and wireshark cannot catch any response.
Based on above detail, I am wondering how can I use scapy to create a hotspot that will have probe and assoc response when a device is connected ?
Best,
LikeLike
Have you tried to follow these steps: https://wordpress.com/post/wlan1nde.wordpress.com/187
LikeLike
The website should not be able to open, I tried many times
LikeLike
My bad, try this link: https://wlan1nde.wordpress.com/2016/08/24/fake-a-wlan-connection-via-scapy/
LikeLike
HI, I tried to run the code, but I didn’t get a successful connection prompt. Should I use scapy to create a fake ssid information?
LikeLike
I don’t understand your question and it’s hard to tell when I don’t know your code or scenario.
LikeLike
When I run, it will report a process error. Is the scapy version mismatched? Or other errors? My scapy version is: Version 2.4.4.dev189
———————————————————————-BUG——————————
Scanning max 5 seconds for Authentication from BSSID 00:13:ef:f2:07:d7
Process Process-2:
Traceback (most recent call last):
File “/usr/lib/python3.6/multiprocessing/process.py”, line 258, in _bootstrap
self.run()
File “/usr/lib/python3.6/multiprocessing/process.py”, line 93, in run
self._target(*self._args, **self._kwargs)
File “/home/helen/Desktop/state/monitor_ifc.py”, line 47, in send_packet
send(packet)
File “/usr/local/lib/python3.6/dist-packages/scapy-2.4.4.dev189-py3.6.egg/scapy/sendrecv.py”, line 366, in send
*args, **kargs
File “/usr/local/lib/python3.6/dist-packages/scapy-2.4.4.dev189-py3.6.egg/scapy/sendrecv.py”, line 339, in _send
realtime=realtime, return_packets=return_packets)
File “/usr/local/lib/python3.6/dist-packages/scapy-2.4.4.dev189-py3.6.egg/scapy/sendrecv.py”, line 313, in __gen_send
s.send(p)
File “/usr/local/lib/python3.6/dist-packages/scapy-2.4.4.dev189-py3.6.egg/scapy/arch/linux.py”, line 558, in send
self.outs.bind(sdto)
TypeError: argument 1 must be str, not NetworkInterface
STA is NOT authenticated to the AP!
Wrong connection state for Association Request: Not Connected – should be Authenticated
STA is NOT connected to the AP!
LikeLike
Sorry, I haven’t run this code in a long time. I can’t guarantee you, that it runs on latest scapy versions. Maybe you can debug it and send an update?
LikeLike
Unfortunately, I tried your code and it is different from what I thought.
What I want to ask you is whether you can use scapy to create a real AP hotspot, just like the hotspot Hostapd that can interact with STA devices. It’s not simply sending a Beacon Frame
LikeLike
Good question, I never tried that as I usually require a client or client functunality to test our Access Points. Therefore, we use scapy for client connections. Sorry, I can’t help you with that.
LikeLike
[…] tried the method suggested in Scapy’s docs here, and also something like what is suggested here. In neither case do I receive the packages at the USRP. It seems like my network card just discards […]
LikeLike
Thanks for this, exactly what I was looking for!
I’ll reference to this post in my own blog 🙂
LikeLike
Thanks for the tutorial. To validate if the packet is successfully transmitted, I tried to use sniffer tools to capture the generated packets. However, for example, I tried the very simple data packet, as mentioned in the article, “packet = Dot11(addr1=”00:a0:57:12:34:56″, addr2=”00:a0:57:98:76:54″, addr3=”00:a0:57:98:76:54″, type=2, subtype=4)”. I do change the MAC address, established the connection, but still cannot capture this packet. Do you have any suggestion upon this issue? Thanks.
LikeLike
Hi Terry,
does your sniffer matches the capabilities of the client regarding number of spatial streams (antennas) and Wi-Fi generation? If you can at least capture the management packets on the air, but just not the data packets, then a mismatch in capabilities is usually the reason.
LikeLike
Hi, it’s a good tutorial but when I use sendp to send the packet It is not sent, on wireshark I see that the mac address source is changed to randomized source address by Windows and I ‘ve an warning: source mac must not be a group address . I’m on windows 10
LikeLike
Hi Heinrich,
since I don’t have any Windows, I can’t help you with this. Sorry and best of luck of getting it to work!
LikeLike
Ok I understand, thanks
LikeLike