I have an application that sends data over a TCP connection to a production server. I need to sniff the contents of that TCP connection and resend it to a debug server.
I've gotten quite close with this:
from scapy.all import *
packets = 0
def dup_pkt(pkt):
global packets
read = raw(pkt[TCP].payload)
print(str(packets))
s.sendall(read)
print("connecting")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("x.x.x.x", 12345))
print("connected")
print("sniffing")
pkts = sniff(prn=dup_pkt, filter="tcp dst port 12345 and not host x.x.x.x") # don't sniff the packets we're resending
The problem is that the packets appear to be missing data in the first two headers. I have set the debug server to save each received packet to a file, and set the application to connect directly to the debug server to compare the known good packet data with what the sniffer is sending. In the first packet, the first 1546/2079 bytes are good, but after that, each byte is zero instead of full of the correct data. In the second packet, the first 11 bytes are missing, but the rest is good.
Interestingly, after those initial two big setup packets, the remainder of the TCP packets seem to be sniffed properly - perhaps because they are usually far simpler and less than 40 bytes each.
Is there a better way to read packet data? Am I missing something? Unfortunately I don't have access to the source of the application, so I can't tell if it's doing anything special with those two big packets I'm having trouble with.
The issue with the first packet could indicate a problem in your operating system's TCP stack w.r.t. fragment reassembly.
In any case, try using another tool like tcpdump or wireshark to capture the packets. If they have the same problem, the problem lies with your operating system. If not, it could be a bug or configuration issue with scapy.
It could also mean that your IP packets are fragmented. Scapy does not automatically defragment packets, but fragments them.
you need to use the defrag function, or defragment (have a look at help(defrag) ), on the received packet list.
Maybe the packet you are checking is a fragment
Related
So I'm trying to build a packet sniffer in Python to deepen my understanding of networking. Thing is, it has turned out to be a tad bit more confusing than I initially anticipated. The problem is that all resources with thorough explanations cover the scenario of creating sockets for client/server data sending/receiving purposes.
At this point, I've successfully created some classes that handle packet header decoding for IPv4 and ICMP. Now, since my socket code only seemed to capture ICMP packets, I've been trying to configure it so that I can catch all traffic reaching my wifi interface, but I still almost exclusively see ICMP packets (with localhost as both source and destination).
So, I have some questions which I'd like to get answered. But first, my code:
import socket
import sys
from protocols.ipv4 import IPv4
PACKET_SIZE = 65535
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
sock.bind(("0.0.0.0", 0))
try:
while True:
# read in a packet
raw_buffer = sock.recvfrom(PACKET_SIZE)[0]
# create an IP packet object
ip_header = IPv4(raw_buffer)
# print the packet
print(ip_header)
except KeyboardInterrupt:
print("\nExiting...")
sock.close()
sys.exit(0)
This is how I've understood it:
First I'm creating a socket with socket.socket, where I specify address family, socket type and protocol. In my case, I'm selecting the AF_INET family which I don't really understand very well, but it seems to yield packets from the network layer. The socket type is set to SOCK_RAW meaning that I want the raw sockets as opposed to using SOCK_STREAM for TCP connections and SOCK_DGRAM for UDP. The last argument IPPROTO_IP just indicates that I want IP packets only.
Then, I'm binding the socket to 0.0.0.0 which supposedly means "any address" as described here.
What I don't understand:
Initially, I saw some examples of creating a sniffer socket which used the AF_PACKET address family. I soon found out that this address family is not available on macos (which I'm using). Why is that? What is an address family how does it relate to sockets? Is there an alternative way to catch packets from lower levels? In Wireshark I can see ethernet datagrams, so it seems possible.
As I've stated, I want to sniff all the traffic reaching my wifi interface. How does the socket know which interface I want it to operate on? Also I've learned that network interfaces can be put into different modes like monitor or promiscuous, how does that relate to sockets and my goal of catching packets?
Why am I almost only catching ICMP packets? What is the purpose of these packets with localhost both as destination and source?
I know there are lots of gaps in my current understanding of this. I'm not sure if I'll be able to get this to work, but I'm curious and I'd be grateful for any kind of answer or even just some good resources to check out.
Edit: My main question is where can I find out more about sockets in the context of packet sniffing?
I am sending packets using:
send(IP(dst="192.168.1.114")/fuzz(UDP()/NTP(version=4)), loop=1)
But I am not able to capture these packets in any other nearby machine (including the one with IP 192.168.1.114) which is on the same network. I am using wlan as my interface.
I also tried to sniff and then replay using scapy but I am still not able to capture those packets.
i would first try to capture the traffic on the sender machine with tcpdump while executing your program:
tcpdump -i any udp dst 192.168.1.114
if you can see the traffic leaving the source host it may be that it does not arrive on the target host. UDP packets are the first packets to be dropped by any network device and as it is the nature of UDP it wont get retransmitted. if you are sure the packet leaves the source verify if it arrives at the target:
tcpdump -i any upd dst 192.168.1.114
Another point to check is your firewall settings. It could be either on the source or target system that your firewall is blocking those requests.
I finally resolved this. Here is the checklist I made which might help others when dealing with replaying/fuzzing using scapy.
Check if all IP addresses you are dealing with are alive in the
network (use ping)
Understand the difference between send() (layer 3)and sendp() (layer 2)
If mutating existing packet make sure to
remove the checksum (using 'del') and recalculate the checksum
either using show2() or using str to convert packets to string
and then converting them back to packets
You should use Wireshark, or the sniff function in Scapy and make it pretty print the contents on the screen:
sniff(lambda x:x.show())
I'm having trouble receiving all related packets to a request when using scapy's sr function.
ans, unans = sr(IP(dst="172.xxx.xxx.xxx")/TCP(dport=80,flags="S"))
returns:
Received 2 packets, got 1 answers, remaining 0 packets
What happens is that I first get an ICMP redirect. Afterwards I get the answer from my local service with SA. Sometimes it tells me it received two packets, which makes sense, but when I look at it in the summary it prints the following:
<bound method SndRcvList.summary of <Results: TCP:0 UDP:0 ICMP:1 Other:0>>
and in summary() I find this:
IP / TCP 172.xxx.xxx.xxx:ftp_data > 172.zzz.zzz.zzz:http S ==> IP / ICMP 172.yyy.yyy.yyy > 172.xxx.xxx.xxx redirect host-redirect / IPerror / TCPerror
For one, I wonder where my SA flagged TCP packet is. When I look at the network dump, I definitely see it, right after the ICMP packet. I've made sure to run scapy with and without running tcpdump, just in case it would interfere, which it shouldn't.
I've also tried to set and increased timeout, just in case it didn't wait long enough to receive the TCP packet. Didn't work.
I've also tried it out on loopback interface, the local lan and systems that are located in the internet. Same result everywhere.
Any ideas on where the error could be located?
Scapy considers this ICMP packet to be response on initial TCP SYN request (which it actually is). Try using sr(..., multi = True) to get multiple response packets.
I am new to Python and trying to send a byte array as a raw packet using a socket. My IP is 192.168.0.116 and the device I am sending this to is 192.168.0.64. This client device is a microcontroller based unit which is executing my code to simply sniff the Ethernet packets and check for a particular pattern. I am using UDP packets and tried the client side firmware by using 'Ostinato' in my PC to send a raw UDP packet. I am using Wireshark to monitor the network packet flow. The client seems to work fine with packets sent by Ostinato.
However when I try to send the same packet with Python (using raw packets as follows), it doesn't seem to spit out the bytes as I cant see anything on Wireshark nor the client get any data. But the return value from sendto() is correct. So it seems that Python feeds the byte array to a buffer to be sent (by OS?) but stops there.
import socket
CLNT_UDP_IP = '192.168.0.64'
CLNT_UDP_PORT = 5005
svr_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
send_data = [0x00, 0x11...]
send_data_arr = bytearray (send_data)
svr_sock.bind (('192.168.0.116',0))
bytes_send = svr_sock.sendto (send_data_arr, (CLNT_UDP_IP, CLNT_UDP_PORT))
svr_sock.close()
I have taken out the try-except blocks for clarity.
Another thing I noted is that when the socket is closing, it takes a bit of time. If I comment out the sendto statement, it exits immediately. So it seems like the socket close is trying to flush the send buffers, which failed to send the packet.
Any ideas?
Ilya is right, you should be opening a UDP socket with
socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
You're binding to port 0, which is invalid. If this is not an inbound port, you don't need to bind it. This may explain why your sendto call is blocking.
The send_data array should contain only your data, not "the full ethernet packet".
The send_data array must be under the MTU size for your network, otherwise it may be dropped silently. It varies but under 1300 should work, over 1500 almost certainly won't work.
I have a client written using python-twisted (http://pastebin.com/X7UYYLWJ) which sends a UDP packet to a UDP Server written in C using libuv. When the client sends a packet to the server, it is successfully received by the server and it sends a response back to the python client. But the client not receiving any response, what could be the reason ?
Unfortunately for you, there are many possibilities.
Your code uses connect to set up a "connected UDP" socket. Connected UDP sockets filter the packets they receive. If packets are received from any address other than the one to which the socket is connected, they are dropped. It may be that the server sends its responses from a different address than you've connected to (perhaps it uses another port or perhaps it is multi-homed and uses a different IP).
Another possibility is that a NAT device is blocking the return packets. UDP NAT hole punching has come a long way but it's still not perfect. It could be that the server's response arrives at the NAT device and gets discarded or misrouted.
Related to this is the possibility that an intentionally configured firewall is blocking the return packets.
Another possibility is that the packets are simply lost. UDP is not a reliable protocol. A congested router, faulty networking gear, or various other esoteric (often transient) concerns might be resulting in the packet getting dropped at some point, instead of forwarded to the next hop.
Your first step in debugging this should be to make your application as permissive as possible. Get rid of the use of connected UDP so that all packets that make it to your process get delivered to your application code.
If that doesn't help, use tcpdump or wireshark or a similar tool to determine if the packets make it to your computer at all. If they do but your application isn't seeing them, look for a local firewall configuration that might reject them.
If they're not making it to your computer, see if they make it to your router. Use whatever diagnostic tools are available (along the lines of tcpdump) on your router to see whether packets make it that far or not. Or if there are no such tools, remove the router from the equation. If you see packets making it to your router but no further, look for firewall or NAT configuration issues there.
If packets don't make it as far as your router, move to the next hop you have access to. This is where things might get difficult since you may not have access to the next hop or the next hop might be the server (with many intervening hops - which you have to just hope are all working).
Does the server actually generate a reply? What addressing information is on that reply? Does it match the client's expectations? Does it get dropped at the server's outgoing interface because of congestion or a firewall?
Hopefully you'll discover something interesting at one of these steps and be able to fix the problem.
I had a similar problem. The problem was windows firewall. In firewall allowed programs settings, allowing the communication for pythonw/python did solve the problem. My python program was:
from socket import *
import time
address = ( '192.168.1.104', 42) #Defind who you are talking to (must match arduino IP and port)
client_socket = socket(AF_INET, SOCK_DGRAM) #Set Up the Socket
client_socket.bind(('', 45)) # arduino sending to port 45
client_socket.settimeout(1) #only wait 1 second for a response
data = "xyz"
client_socket.sendto(data, address)
try:
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
print rec_data #Print the response from Arduino
except:
pass
while(1):
pass