How do I decode whether a network packet is SSH or not using python and the library Scapy - python-3.x

I am using Python 3.7 and the Scapy library and I am unable to detect if a TCP packet is SSH or not.
I have tried to find an example, but have not found one that shows how to do this.
from scapy.all import *
self.__Pkts = rdpcap("sample.pcap")
pkt = self.__Pkts[i]
if pkt.haslayer('IP'):
self.__NumIpPkts += 1
has_ssh = self.__Pkts[i]['IP'].getlayer('TCP').getlayer('SSH')
if pkt.haslayer('TCP') or has_ssh:
self.__NumTcpPkts += 1
The code presented is able to detect IP and TCP packets, but it cannot detect SSH packets. I want to detect SSH packets.

It seems like Scapy does not come with a SSH layer implementation out of the box. What you can easily do is check whether the TCP packet is using port 22 and then in those cases assume it is an SSH packet and store the raw layer data.
If you want to do a more elaborate check you will have to implement your own scapy layer or find one on the internet: https://github.com/tintinweb/scapy-ssh/blob/master/src/scapy/layers/ssh.py
I have not tested the implementation provided in the link and I would suggest using it merely as a template for your own implementation while also following https://scapy.readthedocs.io/en/latest/build_dissect.html

Related

How to sniff pakages and discard?

I want to sniff some packets, and if the packet meet some conditions(etc. dst ip = 'xxx') , i want to discard it. Something like firewall.
I am trying use scapy.
sniff
I expect I can stop the original packet from src A to scr B if the packet meets the condition
You can't do that using Scapy.
You will need to use:
On Unix: use netfilterqueue along Scapy, similar to Modify with scapy and netfilterqueue
On Windows: your best bet is Windivert (watch out: pydivert doesn't work with the last version. You might want to fix it yourself :/)
In fact, Scapy only receives packets after they went through the OS. It won't be able to discard them. The softwares listed above use tricks to catch them beforehand

Can I intercept network packets with a raw socket (not only sniff)?

This is my first time using raw sockets (yes, I need to use them as I must modify a field inside a network header) and all the documentation or tutorials I read describe a solution to sniff packets but that is not exactly what I need. I need to create a script which intercepts the packet, process it and sends it further to the destination, i.e. the packets should not reach the destination unless my script decides to.
In order to learn, I created a small prototype which detects pings and just prints "PING". I would expect ping not to work as I intercept the packets and I don't include the logic to send them to its destination. However ping is working (again, it seems as it is just sniffing/mirroring packets). My goal is that the ping packets are "trapped" in my script and I don't know how to do that. This is what I do in my current python script (I avoid writing how I do the decode for simplicity)
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
sock.bind((eth0, 0))
packet = sock.recvfrom(65565)
decode_eth(packet)
decode_ip(packet)
if (ipheader.ip_proto == 1):
print("\nPING")
Can somebody explain how can I achieve my goal or point me to the right documentation?
Your description seems to be different from what your title suggest. My understanding is that you want to receive, modify and possibly drop incoming network packets. And this is to be done on Linux. In that case I suggest you use a netfilter prerouting hook, which will make things a lot simpler (and likely more stable). Netfilter is well documented, a nice overview including information related to your requirements can be seen here. The important function to use is nf_register_hook(), read the answer to this question to get an idea of how to set things up.
I suppose that your Linux box is configured as a router (not a bridge). The packet will pass through your Linux because you have enabled IP Forwarding. So there are two solution:
Solution 1:
Disable IP Forwarding and then receive the packet from one interface and do the appropriate task (forwarding to another interface or dropping it).
Solution 2:
Use NetFilterQueue.
Install it on your Linux box (Debian/Ubuntu in my example):
apt-get install build-essential python-dev libnetfilter-queue-dev
Use iptables to send packets coming from input interface (eth0 in my example):
iptables -I INPUT -i eth0 -j NFQUEUE --queue-num 1
Run this script to handle packets forwarded to the Queue No.1 :
from netfilterqueue import NetfilterQueue
def print_and_accept(pkt):
print pkt
pkt.accept()
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
nfqueue.run()
except KeyboardInterrupt:
print
Note that pkt.drop() cause dropping the packet. Also you should accept/drop every packet.

Sending raw data in Scapy does not work correctly

I use Scapy to create an initial OpenVPN packet and send it to OpenVPN server (acting as a client). OpenVPN part of the packet I'm just reusing from old captured connection, but its irrelevant here.
Thing is, I add a payload of 42bytes but for some reason when I capture packet with Wireshark, I can see 84bytes of OpenVPN stuff. Last half of that is correct payload I sent, but I can't figure out what is the first half. All other layers (Ethernet, IP, UDP) have correct size.
#!/usr/bin/env python
import socket
from scapy.all import *
mysocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
mysocket.connect(('192.168.138.129', 1194))
mystream=StreamSocket(mysocket)
ascapypacket=Ether()/IP(dst="192.168.138.129")/UDP(dport=1194, len=50)/Raw(load="\x38\x81\x38\x14\x62\x1d\x67\x46\x2d\xde\x86\x73\x4d\x2c\xbf\xf1\x51\xb2\xb1\x23\x1b\x61\xe4\x23\x08\xa2\x72\x81\x8e\x00\x00\x00\x01\x50\xff\x26\x2c\x00\x00\x00\x00\x00")
etherLoad = len(ascapypacket.getlayer(Ether)) # display size
print etherLoad
ipLoad = len(ascapypacket.getlayer(IP)) # display size
print ipLoad
udpLoad = len(ascapypacket.getlayer(UDP)) # display size
print udpLoad
rawLoad = len(ascapypacket.getlayer(Raw)) # display size
print rawLoad
mystream.send(ascapypacket)
I made an image. Here you can see green stuff is correct - first part is IP and UDP layers, and 2nd green part is my OpenVPN payload, but I don't understand what is the red part.
Edit: If I don't send that Raw payload I still get those 42 bytes for some reason.
You've created an ordinary UDP datagram socket:
mysocket=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
This socket manages the ethernet, IP & UDP layers by itself, with guidance from the user through various auxiliary methods and arguments, such as the connect method you've in fact used in your code snippet:
mysocket.connect(('192.168.138.129', 1194))
Its various send methods, even when encapsulated as part of a scapy's StreamSocket object, are expecting to receive as their "data-to-send" argument just the application payload layered above the UDP layer.
However, you're passing on to it the entire protocol stack payload, i.e. the ethernet, IP & UDP headers, which is misinterpreted to be part of the payload data that you wish to send to the other side:
ascapypacket=Ether()/IP(dst="192.168.138.129")/UDP(dport=1194, len=50)/Raw(load="\x38\x81\x38\x14\x62\x1d\x67\x46\x2d\xde\x86\x73\x4d\x2c\xbf\xf1\x51\xb2\xb1\x23\x1b\x61\xe4\x23\x08\xa2\x72\x81\x8e\x00\x00\x00\x01\x50\xff\x26\x2c\x00\x00\x00\x00\x00")
Thus, the data you've marked in red is actually the payload data you've yourself set, before it is followed by the OpenVPN part:
Ether()/IP(dst="192.168.138.129")/UDP(dport=1194, len=50)
The first part marked in green, which you've mistakenly identified as created by yourself, is actually generated by the socket object (the kernel, the appropriate driver and the underlying hardware, to be more accurate).
Depending on your needs, you should either instantiate your socket as a raw one:
mysocket = socket(socket.AF_PACKET, socket.SOCK_RAW)
or set the payload accordingly as just the OpenVPN data:
ascapypacket=Raw(load="\x38\x81\x38\x14\x62\x1d\x67\x46\x2d\xde\x86\x73\x4d\x2c\xbf\xf1\x51\xb2\xb1\x23\x1b\x61\xe4\x23\x08\xa2\x72\x81\x8e\x00\x00\x00\x01\x50\xff\x26\x2c\x00\x00\x00\x00\x00")

Linux: How to send a whole packet to a specific port on another host?

I have captured a TCP packet using libpcap, and I want to send this whole packet(without modifying it) to a specific port on another host(which has another sniffer listening to that port).
Is there any way I can do this?
Thanks a lot!
You didn't specify which programming language you're using and what you've tried so far.
Change the IP address field to the target IP and the TCP port field to the port you want. Don't forget to update both checksums.
If what you want is TCP forwarding, the Linux kernel already does this for you.
netcat may work in this case although I think you may have to reconstruct the header, have not tried.
How to escape hex values in netcat
The other option is to use iptables to tee the packet to the other sniffer while still catching it in you package analyzer
http://www.bjou.de/blog/2008/05/howto-copyteeclone-network-traffic-using-iptables/
Another option is using a port mirror, this goes by a few differnt names depending on the switch being used but it allows you to set a port on a a switch to be essentially a hub.
I think your best bet if you can't get netcat to work is to use iptables and you can add filters to that even.
I don't know whether you HAVE to use C or not, but even if you do, I would recommend building a prototype with Python/Scapy to begin with.
Using scapy, here are the steps:
Read the pcap file using rdpcap().
Grab the destination IP address and TCP destination port number (pkt.getlayer(IP).dst, pkt.getlayer(TCP).dport) and save it as a string in a format that you want (e.g. payload = "192.168.1.1:80").
Change the packet's destination IP address and the destination port number so that it can be received by the other host that is listening on the particular port.
Add the payload on top of the packet (pkt = pkt / payload)
Send the packet (sendp(pkt, iface='eth0'))
You will have to dissect the packet on the other host to grab the payload. Without knowing exactly what is on top of the TCP layer in the original packet, I can't give you an accurate code for this, but should be relatively straight forward.
This is all quite easy with Python/Scapy but I expect it to be much harder with C, having to manually calculate the correct offsets and checksums and things. Good luck, and I hope this helps.

How to generate socket errors on network bridge

I am trying to create a test environment to test the handling of network errors between a client and a server. I cannot change the software on either. The two devices will be connected across a Linux bridge and I will be using various bandwidth shaping tools to restrict bandwidth or block traffic altogether to simulate various error conditions.
Another thing I need to do, which I have no idea yet how to achieve, is to generate socket errors on existing connections. I'd prefer to use an existing Linux tool/utility, but may be able to write my own with enough guidance. I'm pretty familiar with basic networking, TCP and UDP and all that, but not with bridging.
Can anyone suggest a way I can generate socket errors, e.g. by triggering unexpected FIN packets, to both ends of a socket that connects across a bridge?
Thanks in advance.
You can generate with scapy FIN or RST packets easily sniffing in the bridge (usually br0) and crafting proper RST or FIN packets.
Here goes an example, where a RST is sent in the same direction of a packet with data.
#!/usr/bin/python
from scapy.all import *
import random
def sendRST(p):
flags = p.sprintf("%TCP.flags%")
if flags != "S":
ip = p[IP] # Received IP Packet
tcp = p[TCP] # Received TCP Segment
if ip.len <= 40:
return
i = IP() # Outgoing IP Packet
i.dst = ip.dst
i.src = ip.src
t = TCP() # Outgoing TCP Segment
t.flags = "R"
t.dport = tcp.dport
t.sport = tcp.sport
t.seq = tcp.seq
new_ack = tcp.seq + 1
print "RST sent to ",i.dst,":",t.dport
send(i/t)
while (1):
PKT = sniff (iface = "br0", filter = "tcp and src host x.x.x.x", count=1, prn=sendRST)
exit()
Check the options of sniff, wich is extremely powerfull :)
Hope to help you.

Resources