Scapy Raw Sockets - python

I try to implement 3-way-hadnshake with a raw socket in Python and using Scapy.
The code is:
s=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.IPPROTO_TCP)
ss=StreamSocket(s)
iph=IPheader()
syn = TCP(sport=TCP_SOURCE_PORT,dport=TCP_DESTINATION_PORT, flags="S")
synack = ss.sr1(iph/syn)
myack = iph/TCP(dport=synack[TCP].sport, sport=synack[TCP].dport, seq=synack[TCP].ack, ack=synack[TCP].seq+1, flags="A")
ss.send(myack)
IPheader() method return a scapy IP header.
When running the script i get this error:
ERROR: --- Error in child 3057
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 89, in sndrcv
pks.send(p)
File "/usr/lib/python2.7/dist-packages/scapy/supersocket.py", line 34, in send
return self.outs.send(sx)
error: [Errno 6] No such device or address

I see a couple of possible problems with your code:
before invoking StreamSocket() you need to establish a connection with a regular socket. So you need to make a connection, something like s.connect(("10.1.1.1",9000)) before the line ss=StreamSocket(s). Further information can be found here
You may need to correct base socket type. I would suggest something like s=socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP). For further information check this

The device is not responding to your SYN packet because a RAW socket does not do that. You have to send the SYN-ACK manually. Also, Wireshark and TCP show sequence numbers as RELATIVE. In order to show the ACTUAL number you must turn this option off. Thirdly, you can set the sequence number manually or randomize it using
TCP(sport = port1, dport = port2, flags="A", seq = random.getrandbits(32), ack = MY_ACK)
or
TCP(sport = port1, dport = port2, flags="A", seq = 01395, ack = MY_ACK)

Related

Why doesn't the Python socket receive packets?

My program doesn't receive any packets (on UDP, Windows 10), but when I sniff the data on Wireshark I can see that the data is indeed sent. I know that it doesn't have anything to do with my local network because when I switch to a hotspot it still doesn't work.
Another thing is that the program receives the data for my friends who work with me on the same project, but for me, even if I'm using the same computer for the client and server it doesn't work.
I even tried to enable Promiscuous in the program via the os module after binding the socket by adding these lines:
if os.name == “nt”:
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
but all I got was
Traceback (most recent call last):
File "C:/Users/roeym/PycharmProjects/client game/tank_trouble_dynamic_map.py", line 5, in <module>
import tank_client
File "C:\Users\roeym\PycharmProjects\client game\tank_client.py", line 13, in <module>
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
OSError: [WinError 10022] An invalid argument was supplied
Can you please help me figure out why my program doesn't receive the data?
This is how I set the socket up:
ip = socket.gethostbyname(socket.gethostname())
port = 8888
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
s.bind((ip, port))
print(f"[!][!] Server is up, running on {ip}, port- {port} [!][!]")
and this is how I receive packets:
while run:
data, ip = s.recvfrom(bufferSize)
data = str(data)
data = data[2:]
data = data[:-1]
if data == "":
continue
print(data)

How to read /dev/log?

I would like to directly access to syslog messages from Python by reading /dev/log.
My (very limited) understanding is that the correct way is to read from there is to bind a datagram socket.
import socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind('/dev/log')
sock.listen(1)
while True:
data, addr = sock.recvfrom(1024)
print(data)
Apparently /dev/log is in use:
Traceback (most recent call last):
File "readlog.py", line 4, in <module>
sock.bind('/dev/log')
OSError: [Errno 98] Address already in use
How should I read /dev/log from Python?
EDIT: per #Barmar's comment - only one process can access /dev/log so that part is clear, the device must be clean before reading from it. sudo lsof /dev/log does not show anything.
A answer in a Java thread around this subject mentioned that syslog should be shut down before. I also tried that, lsof | grep "/dev/log" was empty but I got the error nevertheless.
Isn't it possible to have several processes reading from /dev/log?
There is a socket flag to set, in order to prevent this:
socket.SO_REUSEADDR
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
This flag tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to expire.
Ref: https://docs.python.org/3/library/socket.html

Python 2.7 / Linux: socket library binding type error

I am attempting to write a very simple server in python.
import socket
import sys
# Create a TCP/IP socket to listen on
server = socket.socket(socket.SOL_SOCKET, socket.SOCK_STREAM)
# Prevent from 'address already in use' upon server restart
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind the socket to port 8081 on all interfaces
server_address = ('localhost', 8081)
print 'starting up on %s port %s' % server_address
server.bind(server_address)
I have read what I think to be correct documentation for the socket library, and it suggests that the server.bind() takes an argument of a tuple. However, I get this error:
starting up on localhost port 8081
Traceback (most recent call last):
File "pyserver.py", line 14, in <module>
server.bind(server_address)
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
TypeError: argument must be string or read-only character buffer, not tuple
I have changed the argument to only a string, as the error warning suggests, and I get a
[Errno 98] Address already in use
error. I thought that the 8th line was in place to prevent that. What is going on?
The first argument to the socket.socket should be address family:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
^^^^^^^^^^^^^^
Except that, your code should work.
Reason of the error message: argument must be string ...
In Linux, the value of the socket.SOL_SOCKET is 1 which is equal to the value of socket.AF_UNIX. Unix domain socket (AF_UNIX) use path (string) as a address
>>> import socket
>>> socket.AF_UNIX
1
>>> socket.SOL_SOCKET
1
UPDATE
Regarding Already already in use error, see SO_REUSEADDR and AF_UNIX.

An existing connection was forcibly closed by the remote host (simple UDP client-server)

Absolute newbie here, and I can't quite seem to find the answer to my question. Running python 2.7.
My code for the server is as follows:
#UDPPingerClient.py
from socket import *
#Create a UDP socket
clientSocket = socket(AF_INET, SOCK_DGRAM)
#Assign IP address and port number to socket
clientSocket.bind(("127.0.0.1",9501))
#Set a timeout value of 1 second
clientSocket.settimeout(1)
msg = "test"
#the server info
sIP = "127.0.0.1"
sPort = 12007
addr = (sIP,sPort)
a = 10
# the server will automatically drop some messages
# so we send 10 to make sure it gets there and then
# listen for a response from the server
while a > 0:
clientSocket.sendto(msg,addr)
try:
received, server = clientSocket.recvfrom(1024)
print received
except timeout:
print ('an error occured')
a = a - 1
The server code:
# UDPPingerServer.py
# We will need the following module to generate randomized lost packets
import random
from socket import *
# Create a UDP socket
# Notice the use of SOCK_DGRAM for UDP packets
serverSocket = socket(AF_INET, SOCK_DGRAM)
# Assign IP address and port number to socket
serverSocket.bind(("127.0.0.1", 12007))
while True:
# Generate random number in the range of 0 to 10
rand = random.randint(0, 10)
# Receive the client packet along with the address it is coming from
message, address = serverSocket.recvfrom(1024)
# Capitalize the message from the client
message = message.upper()
12 # If rand is less is than 4, we consider the packet lost and do not respond
if rand < 4:
continue
# Otherwise, the server responds
serverSocket.sendto(message, address)
Thus far I haven't been able to get a reply from the server. The most I've been able to accomplish is sending once and timing out before getting this error:
an error occured <-- output from exception
Traceback (most recent call last):
File "C:/Python27/UDPPingerClient.py", line 23, in <module>
received, server = clientSocket.recvfrom(1024)
error: [Errno 10054] An existing connection was forcibly closed by the remote host
The reproducibility on this one is 100%, this is the outcome every time I run the server file and then the client file. Same thing with the firewall on or off. I have a feeling this has to do with the exception but I can't quite wrap my head around why.
this is the output i got:
foggy#dew ~ $ python UDPPingerClient.py
TEST
TEST
an error occured
TEST
TEST
TEST
an error occured
TEST
an error occured
TEST
exactly ten messages, some have timeouted others were passed back.
besides that extra 12 above rand line in Server (and that doesn't bother the interpreter) i don't see anything wrong with the code.

Python raw IPv6 socket errors

I am having some problems using raw IPv6 sockets in python. I connect via:
if self._socket != None:
# Close out old socket first
self._socket.close()
self._socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW)
self._socket.bind((self._interface,0))
self._socket.sendall(data)
where self._interface is my local address; specifically "fe80::fa1e:dfff:fed6:221d". When trying this, I get the following error:
File "raw.py", line 164, in connect
self._socket.bind((self._interface,0))
File "<string>", line 1, in bind
socket.error: [Errno 49] Can't assign requested address
If I use my ipv6 localhost address for self._interface ("::1") I can actually bind the address, but can not send anything:
self._socket.sendall(data)
File "<string>", line 1, in sendall
socket.error: [Errno 39] Destination address required
Why would a raw socket need a destination address? Has anyone worked with raw IPv6 sockets in python, and can help me understand why this is happening?
Although this is an old question, i thought of adding an answer that works and helps any one who stumbles upon it latter.
The key problems are:
Raw sockets are not bound and connected to other sockets. Also sendto is the correct api to use.
Moreover, 4 tuple structure for destination address is required for ipv6 packets as opposed to two tuple ones for ipv4.
Lastly, the stack (at least on Linux mint 15) is more strict on ipv6 packets. If you try sending an empty icmpv4 echo request, python allows it and sends a meaning less packet on wire. Where as in case of ipv6, it simply gives error of 'invalid argument' when you try sending an empty packet. Hence a valid request is also required in case of ipv6. Following example does that all for ipv6 and sends a valid ping echo request to loop back address.
import socket
def main(dest_name):
addrs = socket.getaddrinfo(dest_name, 0, socket.AF_INET6, 0, socket.SOL_IP)
print addrs
dest = addrs[0]
# A minimal ICMP6-echo message (thanks to abarnert)
data = '\x80\0\0\0\0\0\0\0'
icmp = socket.getprotobyname('ipv6-icmp')
#print icmp
send_socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW, icmp)
print "sent to " + str(dest[4])
send_socket.sendto(data, dest[4])
send_socket.close()
if __name__ == '__main__':
main('::1')
I don't understand your combination of bind and sendall. In my understanding, bind is for server sockets and sendall requires a connection. Did you mean connect instead of bind?
Anyway, the IPv6 equivalent of INADDR_ANY is, according to the man page, IN6ADDR_ANY_INIT. Python does not define a constant for it, but this is the same as '::' (all zero).
This worked for me (as root):
>>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_RAW)
>>> s.bind(('::', 0))
EDIT:
Oops, I first did not saw that you actually managed to bind the socket to an address. However your second problem is obvious: You must first connect to some address before you can send data. Or use sendto with an address. This is not different from IPv4.
This code provides a raw socket with L2 access. Unfortunately OSX does not support the socket.PF_PACKET...
soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) #create the raw-socket
soc.bind(("lo0", 0))
soc.send(packet)

Categories