Capturing CTS frame with Scapy and python - python

I have my WiFi card in monitoring mode and listening packages from Python with Scapy. I'm also sending RTS request and hoping to pickup CTS reply but it never happens. (I expect it to be type 1, subtype=12.)
Am I sending RTS package the right way? (MAC is just sample). Should I use rt1() instead of sendp() to get response and how? (I only find samples with IP and I have just a MAC)
Doto11 = Dot11(type=1, subtype=11, addr1="ee:11:ee:11:ee:12", ID=0x99)
pkt = RadioTap()/Doto11
sendp(pkt, iface=wlan1mon, realtime=True)

Related

Sending packet with python and scapy to local address doesn't work

I am trying to send a udp packet to a local ip address. This is my example code:
from scapy.all import *
if __name__ == "__main__":
send(IP(dst="127.0.0.1")/UDP(sport=19600,dport=39600)/"abc")
I've started netcat to catch what I am going to send:
nc -ul 39600
Then I am executing the code:
python3 example_scapy_send.py
Nothing is received by the listening netcat.
At the same time I have started wireshark and I can see the packet is sent.
If I send a packet using netcat it is ariving on the listening netcat.
usr#dev:/home/usr# nc -u 127.0.0.1 39600
test
Wireshark:
The only difference I can see is that at layer 2 - destination address is multicast/broadcast when sent with scapy and unicast when sent with netcat. But this is not something I can control.
If I sent the same packet with scapy to another ip on the network (another host) the packet is received (by netcat). So the issue applies only if I am sending to a local address. Tested with any local ip. Not only 127.0.0.1. I've also tested with sendp and sr scapy functions but the result is the same.
Something more: if I've started another scapy script to listen to UDP/39600 (instead of netcat) I can see/I am receiving the packet I've sent.
Any ideas what is wrong?
tests done under ubuntu/scapy 2.5/python 3.8
I couldn't find a way to make it work with send/sendp scapy functions, but instead I tried using standart python socket and it did the job:
someSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
someSocket.sendto(bytes('abc', "utf-8"), (127.0.0.1, 39600))
Acording to Scapy troubleshooting:
The loopback interface is a very special interface. Packets going through it are not really assembled and disassembled. The kernel routes the packet to its destination while it is still stored an internal structure. What you see with tcpdump -i lo is only a fake to make you think everything is normal. The kernel is not aware of what Scapy is doing behind his back, so what you see on the loopback interface is also a fake. Except this one did not come from a local structure. Thus the kernel will never receive it.
On Linux, in order to speak to local IPv4 applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems than Linux)
So you may need to add line before sending packet:
conf.L3socket = L3RawSocket
In your script. That way everything should supposed to work. At least in my environment worked out fine.

Differences in ARP scanning macOS / Raspbian / Python results

With the help of some tutorials I wrote a Python script that lists network details of the devices in the network.
I however only detect certain devices if I run the Python script. I already saw when searching that certain devices (e.g. iOS devices) don't respond (but are occasionally detected), but the strange thing is:
macOS (Catalina, 10.15.2) does find these devices with "arp -a"
Raspbian (10, buster) also finds a number of devices when doing "arp -a" but does not find the iOS devices
Python (3/2.7) does not find the Arduino devices which Raspbian and macOS do find, I run the Python script from the mac.
Running the Python script on the Pi does give me the Arduino devices as well.
I use Scapy for the ARP messages in Python (based on this tutorial: https://www.thepythoncode.com/article/building-network-scanner-using-scapy):
def find_devices(gateway):
_ip_items = gateway.split(".")
target_ip = "%s.%s.%s.%s" % (_ip_items[0], _ip_items[1], _ip_items[2], "0/24")
# IP Address for the destination
# create ARP packet
arp = ARP(pdst=target_ip)
# create the Ether broadcast packet
# ff:ff:ff:ff:ff:ff MAC address indicates broadcasting
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
# stack them
packet = ether/arp
result = srp(packet, timeout=3, verbose=0)[0]
# a list of clients, we will fill this in the upcoming loop
clients = []
for sent, received in result:
# for each response, append ip and mac address to `clients` list
clients.append({'ip': received.psrc, 'mac': received.hwsrc})
print("{:16} {}".format(received.psrc, received.hwsrc))
Of course I could use ARP -A directly (e.g. execute that from Python and parse the results), but I am much more curious about the reasons that the Raspberry Pi seems to detect more devices than the Python code and macOS detects even more (are they cheating and using bonjour e.g.?) but how come both detect the Arduino's (Nano 33 IoT boards with MQTT pub/sub code on them) while the script on macOS does not detect those.
I actually found out that I can get even the iOS devices and Arduino devices when I chance the timeout to a much larger value (e.g. 15). It is still much more slow than macOS (arp -a gives an instant response) but they probably draw it from some cache or something(?). It does produce all devices that I see in arp -a also from the Python code even though it then becomes really slow.

Python Read ethernet frames using socket on Windows?

I'm trying to read Ethernet (IEEE 802.2 / 3) frames using primarily socket.
The application shuld just sniff ethernet frames and depending on the content, act on it. However, there are almost no information on how to do this on Windows, the default (unix way) being socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0800)). This is nonexistent in winsock apparently. So how do I sniff eth frames?
I suspect I need to bind to a MAC using socket.bind() instead of IP.
My current piece of code:
def _receive(interface): #Receive Eth packets.
#Interface = '192.168.0.10'
sock2 = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
sock2.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1))
sock2.bind((interface, 0))
while True:
data, sender = sock2.recvfrom(1500)
handle_data(sender, data)
Gets me nowhere. I see packets on Local connection in Wireshark, but it's not picked up in python..
On linux, I can do sock_raw = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_802_2)) , then bind and setsockopt(sock_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq))
I would like to not have to depend on too many external libraries becuase this is supposed to be distributed and thus pretty lightweight. pip install-able packages are OK though, they can be bundled with the installer..
Python's socket doesn't come with sniffing capabilites. Simple as that.
The idea of having a network stack in your operating system is that programs "register" for specific types of packets to be delivered to them – typically, this is something like listening on a IP port, ie. one to two levels above raw ethernet packets.
To get all raw ethernet packets, your operating system's network stack needs some kind of driver/interface to support you with that. That's why wireshark needs WinPcap.
My guess is you're going to be pretty happy with pypcap, which probably is PyPi/pip installable.

Parse out UDP information with tshark (Wireshark) or Python

I am broadcasting UDP packets between 2 machines and listening to them on a third machine. I can see the packets in Wireshark and need any easy way to obtain the "Data" portion of the UDP packets. I have been able to dump the packet infromation to a file using tshark
C:>tshark -V -R "udp" > C:/test.txt
However, this prints out everything in the packet, and i only want to print out the "Data" portion. Is there a way to do this?
Also, if there is a way to capture this in Python, that would be great as well. I have set up the following code:
Host = "myip"
Port = 5000
While True:
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((Host,Port))
data = sock.recv(4096)
sock.close()
When i implement this code, using my "listening" pc, no data is received.
When i implement this code, using one of my two communicating pcs, "The requested address is not valid in its context"
Mind you, I see all the data being passed between the 2 pcs in Wireshark on my "listening" pc.
Thanks!
McFly,
If you want to do sniffing and display/parse packets in Python, Scapy is the way to go here. Just drop tshark as Scapy can automatically do 99% of what tshark can do out of the box.

ICMP Ping packet is not generating a reply when using Scapy

I recently began exploring Scapy. A wonderful tool indeed!
I have a problem... When I monitor my network card using Wireshark and I do a regular ping from the systems command prompt with the standard PING installation, wireshark pops up with "Ping request" and then "Ping reply" indication that it sent a reply. But when i do it manually in Scapy, it sends no reply back.. How can this be? I spent alot of time trying to figure this out so i really hope someone can shed some light on this issue of mine...
Here is the code i used:
>>> from scapy.all import IP, ICMP, send
>>> IP = IP(dst="127.0.0.1")
>>> Ping = ICMP()
>>> send(IP/Ping)
The packet is sent successfully and Wireshark shows a Ping request received, but not that it has sent a reply back.
This is an FAQ item:
I can't ping 127.0.0.1. Scapy does not work with 127.0.0.1 or on the loopback interface
The loopback interface is a very special interface. Packets going through it are not really assembled and dissassembled. The kernel routes the packet to its destination while it is still stored an internal structure. What you see with tcpdump -i lo is only a fake to make you think everything is normal. The kernel is not aware of what Scapy is doing behind his back, so what you see on the loopback interface is also a fake. Except this one did not come from a local structure. Thus the kernel will never receive it.
In order to speak to local applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems that Linux) :
>>> conf.L3socket
<class __main__.L3PacketSocket at 0xb7bdf5fc>
>>> conf.L3socket=L3RawSocket
>>> sr1(IP(dst="127.0.0.1")/ICMP())
<IP version=4L ihl=5L tos=0x0 len=28 id=40953 flags= frag=0L ttl=64 proto=ICMP chksum=0xdce5 src=127.0.0.1 dst=127.0.0.1 options='' |<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |>>
Try this
def ping(host, repeat=3):
packet = IP(dst=host)/ICMP()
for x in range(repeat):
response = sr1(packet)
response.show2()
Your not storing the reply properly

Categories