Unwanted RST TCP packet with Scapy - python

In order to understand how TCP works, I tried to forge my own TCP SYN/SYN-ACK/ACK (based on the tutorial: http://www.thice.nl/creating-ack-get-packets-with-scapy/ ).
The problem is that whenever my computer recieve the SYN-ACK from the server, it generates a RST packet that stops the connection process.
I tried on a OS X Lion and on a Ubuntu 10.10 Maverick Meerkat, both reset the connection. I found this: http://lkml.indiana.edu/hypermail/linux/net/0404.2/0021.html, I don't know if it is the reason.
Does anyone could tell me what could be the reason? And how to avoid this problem?
Thank you.

The article you cited makes this pretty clear...
Since you are not completing the full TCP handshake your operating system might try to take control and can start sending RST (reset) packets, to avoid this we can use iptables:
iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.1.20 -j DROP
Essentially, the problem is that scapy runs in user space, and the linux kernel will receive the SYN-ACK first. The kernel will send a RST because it won't have a socket open on the port number in question, before you have a chance to do anything with scapy.
The solution (as the blog mentions) is to firewall your kernel from sending a RST packet.

I don't have a non-iptables answer, but one can fix the reset issue. Instead of trying to filter the outgoing reset in the filter table, filter all of the incoming packets from the target in the raw table instead. This prevents the return packets from the target from even being processed by the kernel, though scapy still sees them. I used the following syntax:
iptables -t raw -A PREROUTING -p tcp --dport <source port I use for scapy traffic> -j DROP
This solution does force me to use the same source port for my traffic; feel free to use your own iptables-fu to identify your target's return packets.

The blog article cited in other answers is not entirely correct. It's not only that you aren't completing the three way handshake, it's that the kernel's IP stack has no idea that there's a connection happening. When it receives the SYN-ACK, it sends a RST-ACK because it's unexpected. Receiving first or last really doesn't enter into it. The stack receiving the SYN-ACK is the issue.
Using IPTables to drop outbound RST packets is a common and valid approach, but sometimes you need to send a RST from Scapy. A more involved but very workable approach is to go lower, generating and responding to ARP with a MAC that is different from the host's. This allows you to have the ability to send and receive anything without any interference from the host.
Clearly this is more effort. Personally, I only take this approach (as opposed to the RST dropping approach) when I actually need to send a RST myself.

I found a solution without IPTables in https://widu.tumblr.com/post/43624355124/suppressing-tcp-rst-on-raw-sockets .
To bypass this problem, simply create a standard TCP socket as a server socket and bind to the requested port. Don’t do accept().
Just socket(), bind() on the port and listen(). This relaxes the kernel and let you do the 3-way handshake.

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.

Scapy TCP Handshake - Windows

While trying to perform a tcp TWH in scapy I encountered a problem.
When my host receives the syn/ack, the kernel ip/tcp stack aborts the handshake by sending rst.
It happens because the first packet sent (the syn) is transparent to the os due to the raw socket that scapy is using.
In some other questions regarding the same issue the solution was to set up iptables to drop packets with the rst flag.
Does anyone have a solution for windows?
(I prefer not to use the FW unless there is no choice)
Thanks!
That's a common problem, and it is not specific to Windows (or Scapy, for that matters - you can face similar issues with Masscan, for example).
You have totally understood and describe it: the problem lies in the IP address being "shared" between Scapy and your host's IP stack.
You have two options:
Use a firewall to prevent your host from getting the SYN/ACK packet (Scapy will get it anyway) or to prevent your host from sending a RST packet.
Use a different IP address with Scapy. This is a bit more difficult because it requires some kind of ARP proxy (or a Scapy script) to answer ARP request for the IP address you will use with Scapy.
Hope this helps, happy hacking!

How to capture the packets that you send in Scapy?

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())

Subsuming the Linux packet processing stack

We occasionally have to debug glitchy Cisco routers that don't handle the TCP Selective Acknowledgment (SACK) options correctly. This causes our TCP sessions to die when routed through an IPTABLES port redirection rule.
To help with the diagnosis, I've been constructing a python-based utility to construct a sequence of packets that can reproduce this error at will, the implementation uses raw sockets to perform this trick. I've got an ICMP ping working nicely but I've run into a snag on the UDP implementation, I can construct, send and receive the packet without problem, the issue that I'm seeing is that Linux doesn't like the UDP packets being sent back from the remote system and always sends an ICMP Destination unreachable packet, even though my python script is able to receive and process the packet without any apparent problems.
My question: Is it possible to subsume the Linux UDP stack to bypass these ICMP error messages when working with RAW sockets?.
Thanks
Are you receiving and processing the packet and only need to suppress the ICMP port-unreachable? If so, maybe just add an entry to the iptables OUTPUT chain to drop it?

Monitoring a tcp port

For fun, I've been toying around with writing a load balancer in python and have been trying to figure the best (correct?) way to test if a port is available and the remote host is still there.
I'm finding that, once connected, it becomes difficult to tell when the remote host goes down. I've turned keep alive on, but can't get it to recognize a downed connection sooner than a minute (I realize polling more often than a minute might be overkill, but lets say I wanted to), even after setting the various TCP_KEEPALIVE options to their lowest.
When I use nonblocking sockets, I've noticed that a recv() will return an error ("resource temporarily unavailable") when it reads from a live socket, but returns "" when reading from a dead one (send and recv of 0 bytes, which might be the cause?). That seems like an odd way to test for it connected, though, and makes it impossible to tell if the connected died but after sending some data.
Aside from connecting/disconnecting for every check, is there something I can do? Can I manually send a tcp keepalive, or can I establish a lower level connection that will let me test the connectivity without sending real data the remote server would potentially process?
I'd recommend not leaving your (single) test socket connected - make a new connection each time you need to poll. Every load balancer / server availability system I've ever seen uses this method instead of a persistent connection.
If the remote server hasn't responded within a reasonable amount of time (e.g. 10s) mark it as "down". Use timers and signals rather than function response codes to handle that timeout.
"it becomes difficult to tell when the remote host goes down"
Correct. This is a feature of TCP. The whole point of TCP is to have an enduring connection between ports. Theoretically an application can drop and reconnect to the port through TCP (the socket libraries don't provide a lot of support for this, but it's part of the TCP protocol).
ping was invented for that purpose
also you might be able to send malformed TCP packets to your destination. For example, in the TCP headers there is a flag for acknowleging end of transmission, its the FIN message. If you send a message with ACK and FIN the remote host should complain with a return packet and you'll be able to evaluate round trip time.
It is theoretically possible to spam a keepalive packet. But to set it to very low intervals, you may need to dig into raw sockets. Also, your host may ignore it if its coming in too fast.
The best way to check if a host is alive in a TCP connection is to send data, and wait for an ACK packet. If the ACK packet arrives, the SEND function will return non-zero.
You can use Bash pseudo-device files for TCP/UDP connection with a specific I/O port, for example:
printf "" > /dev/tcp/example.com/80 && echo Works
This would open the connection, but won't send anything. You can test it by:
nc -vl 1234 &
printf "" > /dev/tcp/localhost/1234
For simple monitoring use cron with above command or using watch:
watch bash -c 'echo > /dev/tcp/localhost/1234 && echo Works || echo FAIL'
However it's recommended to use specific tools which are designed for that such as Monit, Nagios, etc.
Monit
Here is example rule using Monit (monit):
# Verify host.
check host example with address example.com
if failed
port 80
protocol http
then alert

Categories